diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..3fe4dc5
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "eve"]
+ path = source/eve
+ url = git://github.com/adobe-webplatform/eve.git
\ No newline at end of file
diff --git a/README.md b/README.md
index 3ed76f8..42d3a96 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,4 @@
-RedRaphael beta
-==========================
\ No newline at end of file
+redraphael
+==========
+
+Red Raphael
\ No newline at end of file
diff --git a/docs/css/dr.css b/docs/css/dr.css
new file mode 100644
index 0000000..169fa17
--- /dev/null
+++ b/docs/css/dr.css
@@ -0,0 +1,140 @@
+#content section.code {
+ display: block;
+ font-weight: 400;
+ background: #181818;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+}
+#content section.code pre code {
+ font-size: 14px;
+}
+code {
+ font-family: source-code-pro, Menlo, "Arial Unicode MS", sans-serif;
+}
+a.dr-hash,
+a.dr-sourceline {
+ -webkit-transition: opacity 0.2s linear;
+ color: #333;
+ font-family: Menlo, "Arial Unicode MS", sans-serif;
+ margin: 0 0 0 .3em;
+ opacity: 0;
+ text-decoration: none;
+}
+h2:hover a.dr-hash,
+h3:hover a.dr-hash,
+h4:hover a.dr-hash,
+h5:hover a.dr-hash,
+h2:hover a.dr-sourceline,
+h3:hover a.dr-sourceline,
+h4:hover a.dr-sourceline,
+h5:hover a.dr-sourceline {
+ opacity: 1;
+}
+.dr-param {
+ float: left;
+ min-width: 8em;
+}
+.dr-type {
+ float: left;
+}
+.dr-type em,
+.dr-returns em,
+.dr-property em {
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ background: #ccc;
+ border-radius: 5px;
+ float: left;
+ font-size: .75em;
+ font-style: normal;
+ font-weight: 700;
+ margin: 0 8px 0 0;
+ min-width: 80px;
+ padding: 2px 5px;
+ text-align: center;
+}
+.dr-type em.amp,
+.dr-returns em.amp,
+.dr-property em.amp {
+ float: none;
+ background: none;
+ font-size: 1em;
+ font-weight: 400;
+ font-style: italic;
+ margin: 0;
+ padding: 0;
+ min-width: 0;
+}
+.dr-property em.dr-type {
+ margin: 4px 16px 0 0;
+}
+em.dr-type-string {
+ background: #e1edb1;
+ color: #3d4c00;
+}
+em.dr-type-object {
+ background: #edb1b1;
+ color: #4c0000;
+}
+em.dr-type-function {
+ background: #cfb1ed;
+ color: #26004c;
+}
+em.dr-type-number {
+ background: #b1c9ed;
+ color: #001e4c;
+}
+em.dr-type-boolean {
+ background: #b1edc9;
+ color: #004c1e;
+}
+em.dr-type-array {
+ background: #edd5b1;
+ color: #4c2d00;
+}
+.dr-optional {
+ display: none;
+}
+ol.dr-json {
+ background: #ddd;
+ list-style: none;
+ margin: 0 -30px;
+ padding: 16px 30px;
+ line-height: 1.5;
+}
+ol.dr-json .dr-json-key {
+ float: left;
+ min-width: 50px;
+ margin-right: 16px;
+}
+ol.dr-json .dr-json-description {
+ display: table;
+}
+ol.dr-json ol.dr-json {
+ margin: 0;
+ padding: 0 0 0 50px;
+}
+#pageNav li.dr-lvl1 a {
+ padding-left: 1em;
+}
+#pageNav li.dr-lvl2 a {
+ padding-left: 2em;
+}
+#pageNav li.dr-lvl3 a {
+ padding-left: 3em;
+}
+#pageNav li.dr-lvl4 a {
+ padding-left: 4em;
+}
+#pageNav li.dr-lvl5 a {
+ padding-left: 5em;
+}
+#pageNav li.dr-lvl6 a {
+ padding-left: 6em;
+}
+#pageNav ol {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
\ No newline at end of file
diff --git a/docs/css/main.css b/docs/css/main.css
new file mode 100644
index 0000000..2d0bda3
--- /dev/null
+++ b/docs/css/main.css
@@ -0,0 +1,508 @@
+html,body{
+ margin:0;
+ padding:0;
+ height: 100%;
+}
+body {
+ font-family: source-sans-pro, sans-serif;
+ position: relative;
+ -webkit-font-smoothing: antialiased;
+}
+body.light {
+ background: #F4F4F4;
+}
+body.dark {
+ color: #F0F1F1;
+ background: #4A4D4E;
+}
+body.light {
+ color: #181919;
+}
+
+h1 {
+ font-weight: 600;
+}
+#wrapper {
+ width: 100%;
+ overflow-x: hidden;
+ background: inherit;
+ position: relative;
+}
+#site {
+ width: 100%;
+ position: relative;
+ z-index: 10;
+ background: inherit;
+ left: 0;
+ transition: all 0.2s ease-out;
+ -webkit-transition: all 0.2s ease-out;
+ transform: translate3d(0, 0, 0);
+ -webkit-transform: translate3d(0, 0, 0);
+}
+#site:before{
+ position: absolute;
+ content: '';
+ left: -4px;
+ height: 100%;
+ width: 4px;
+ background: #3B3E3E;
+}
+#site.open {
+ transform: translate3d(250px, 0, 0);
+ -webkit-transform: translate3d(250px, 0, 0);
+}
+pre {
+ font-family: source-code-pro, sans-serif;
+ font-size: 12px;
+}
+/* Main Header */
+#main-header {
+ color: #373435;
+ background: #fff;
+ height: 98px;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 10px 20px;
+ position: relative;
+}
+#main-header hgroup {
+ text-align: center;
+}
+#main-header hgroup h1 {
+ font-size: 40px;
+ margin: 5px 0 0;
+ letter-spacing: -.065em;
+ line-height: 1.1em;
+}
+#main-header hgroup a {
+ color: #464646;
+ text-decoration: none;
+}
+#main-header hgroup a:hover {
+ color: #000;
+}
+#main-header hgroup p {
+ font-size: 13px;
+ color: #999;
+ margin: 0;
+}
+#main-header nav {
+ display: none;
+}
+#slide-menu-button {
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ display: inline-block;
+ vertical-align: top;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-background-clip: padding;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -o-text-overflow: ellipsis;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ padding: 0 0.5rem;
+ line-height: 2rem;
+ letter-spacing: 1px;
+ color: #454545;
+ text-shadow: 0 1px #fff;
+ vertical-align: baseline;
+ -webkit-box-shadow: inset 0 1px #fff;
+ box-shadow: inset 0 1px #fff;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ width: 2.6rem;
+ height: 2.6rem;
+ line-height: 2.6rem;
+ border: 1px solid transparent;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+#slide-menu:disabled,
+#slide-menu.is-disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+#slide-menu-button:active,
+#slide-menu-button.is-active {
+ color: #454545;
+ text-shadow: 0 1px #fff;
+ background-color: #d3d7d7;
+ border: 1px solid #a5a8a8;
+ -webkit-box-shadow: inset 0 1px rgba(0,0,0,0.12);
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+#slide-menu-button span {
+ background-repeat: no-repeat;
+ background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCIgWw0KCTwhRU5USVRZIG5zX2V4dGVuZCAiaHR0cDovL25zLmFkb2JlLmNvbS9FeHRlbnNpYmlsaXR5LzEuMC8iPg0KCTwhRU5USVRZIG5zX2FpICJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlSWxsdXN0cmF0b3IvMTAuMC8iPg0KCTwhRU5USVRZIG5zX2dyYXBocyAiaHR0cDovL25zLmFkb2JlLmNvbS9HcmFwaHMvMS4wLyI+DQoJPCFFTlRJVFkgbnNfdmFycyAiaHR0cDovL25zLmFkb2JlLmNvbS9WYXJpYWJsZXMvMS4wLyI+DQoJPCFFTlRJVFkgbnNfaW1yZXAgImh0dHA6Ly9ucy5hZG9iZS5jb20vSW1hZ2VSZXBsYWNlbWVudC8xLjAvIj4NCgk8IUVOVElUWSBuc19zZncgImh0dHA6Ly9ucy5hZG9iZS5jb20vU2F2ZUZvcldlYi8xLjAvIj4NCgk8IUVOVElUWSBuc19jdXN0b20gImh0dHA6Ly9ucy5hZG9iZS5jb20vR2VuZXJpY0N1c3RvbU5hbWVzcGFjZS8xLjAvIj4NCgk8IUVOVElUWSBuc19hZG9iZV94cGF0aCAiaHR0cDovL25zLmFkb2JlLmNvbS9YUGF0aC8xLjAvIj4NCl0+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zOng9IiZuc19leHRlbmQ7IiB4bWxuczppPSImbnNfYWk7IiB4bWxuczpncmFwaD0iJm5zX2dyYXBoczsiDQoJIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDBweCIgaGVpZ2h0PSI0MHB4Ig0KCSB2aWV3Qm94PSIwIDAgNDAgNDAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQwIDQwIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzd2l0Y2g+DQoJPGZvcmVpZ25PYmplY3QgcmVxdWlyZWRFeHRlbnNpb25zPSImbnNfYWk7IiB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIj4NCgkJPGk6cGdmUmVmICB4bGluazpocmVmPSIjYWRvYmVfaWxsdXN0cmF0b3JfcGdmIj4NCgkJPC9pOnBnZlJlZj4NCgk8L2ZvcmVpZ25PYmplY3Q+DQoJPGcgaTpleHRyYW5lb3VzPSJzZWxmIj4NCgkJPGcgb3BhY2l0eT0iMC43Ij4NCgkJCTxnIG9wYWNpdHk9IjAuNzUiPg0KCQkJCTxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsPSIjRkZGRkZGIiBkPSJNMzksMTF2LTFjMC0xLjQ3LTAuNDgtMi0yLTJIM2MtMS41MywwLTIsMC41Mi0yLDJ2MQ0KCQkJCQljMCwxLjU1LDAuNTIsMiwyLDJoMzRDMzguNSwxMywzOSwxMi41MiwzOSwxMXoiLz4NCgkJCTwvZz4NCgkJCTxnPg0KCQkJCTxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMzksMTBWOWMwLTEuNDctMC40OC0yLTItMkgzQzEuNDcsNywxLDcuNTIsMSw5djFjMCwxLjU1LDAuNTIsMiwyLDJoMzQNCgkJCQkJQzM4LjUsMTIsMzksMTEuNTIsMzksMTB6Ii8+DQoJCQk8L2c+DQoJCTwvZz4NCgkJPGcgb3BhY2l0eT0iMC43Ij4NCgkJCTxnIG9wYWNpdHk9IjAuNzUiPg0KCQkJCTxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsPSIjRkZGRkZGIiBkPSJNMzksMjJ2LTFjMC0xLjQ3LTAuNDgtMi0yLTJIM2MtMS41MywwLTIsMC41Mi0yLDJ2MQ0KCQkJCQljMCwxLjU1LDAuNTIsMiwyLDJoMzRDMzguNSwyNCwzOSwyMy41MiwzOSwyMnoiLz4NCgkJCTwvZz4NCgkJCTxnPg0KCQkJCTxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMzksMjF2LTFjMC0xLjQ3LTAuNDgtMi0yLTJIM2MtMS41MywwLTIsMC41Mi0yLDJ2MWMwLDEuNTUsMC41MiwyLDIsMmgzNA0KCQkJCQlDMzguNSwyMywzOSwyMi41MiwzOSwyMXoiLz4NCgkJCTwvZz4NCgkJPC9nPg0KCQk8ZyBvcGFjaXR5PSIwLjciPg0KCQkJPGcgb3BhY2l0eT0iMC43NSI+DQoJCQkJPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNGRkZGRkYiIGQ9Ik0zOSwzM3YtMWMwLTEuNDcxLTAuNDgtMi0yLTJIM2MtMS41MywwLTIsMC41Mi0yLDJ2MQ0KCQkJCQljMCwxLjU1LDAuNTIsMiwyLDJoMzRDMzguNSwzNSwzOSwzNC41MiwzOSwzM3oiLz4NCgkJCTwvZz4NCgkJCTxnPg0KCQkJCTxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMzksMzJ2LTFjMC0xLjQ3MS0wLjQ4LTItMi0ySDNjLTEuNTMsMC0yLDAuNTItMiwydjFjMCwxLjU1LDAuNTIsMiwyLDJoMzQNCgkJCQkJQzM4LjUsMzQsMzksMzMuNTIsMzksMzJ6Ii8+DQoJCQk8L2c+DQoJCTwvZz4NCgk8L2c+DQo8L3N3aXRjaD4NCjxpOnBnZiAgaWQ9ImFkb2JlX2lsbHVzdHJhdG9yX3BnZiI+DQoJPCFbQ0RBVEFbDQoJZUp6c3ZlbVNKTG1SSnZnRTlnNitQMXFFSEprS0dnQ0RBY1lkV1pId09IbzRRM2FYa094anBXV2tKSmtWVGVaMEhpVlpXZVJ5bjM3MQorMVFWZ0xsN1pFVWVSVksySzFDVkVhNE9nNW5oVU9qeHFlTHYvbzh2Zi9QRjlkZHZmdmZ3UmJxYUQ5UGYvZDNOMjRkbjc5NjgvZm1CCjFNTXZYcjc4N3R0M2IwSDZ5YTkvZWdqcjFTeVZybjlSdjdLSy8venc5dHNYYjE3L25GOWRKZm55SGxmLzVCZmZQdnZkdzh1WEQ0ZGYKUG52OTlicy9QSHY1OFBhbmg1LzhWTDcvN1l0M0x4K2t4aCtldmZyZGQyOS8vL0QyNnRzLy92Nm5mbXRwNi9iWk8vbCsrVm44V1VpSAorUE01SHI3OEZiNSs5dnFQejc3OTlzWC8rNENicFlwN0hkOTg5L3JyRjY5L2Yzenovd2p4OEVYS2g3UWR2aWp5MVg5LzhldUhiOS96Ci9lMmI1OSs5ZW5qOTdzdTNiNTQvZlB2dHpadVhiOTUrKy9QRHpaK2Z2VDc4NnRudjVadG5oLzliM3VETm53N0hsOCtlLzhja2I1Mi8KdW4veDhrRmU4Tld6ZDRjUTBSZlh2d2p4cStOM0wxNSsvUS9mdmZyZGc3ejZ1cEdjdm1LVC8vU3R0Q1hONG0rUXkxZS9lQ1dVM3p5OApleWZQSlRkRWYvNzY3NC9qWXdpUjVTZi85dXVIMzc5ZzkwdTMvSytmV3JOdjMzeno2dG5iLzhDMWh5K1crU0QvMlIxLysvRHFtNWZTCmUzemRPRi9sd3hmOHQvOXA5ZVF0V09lTHVGYnBsYkllMGx3UEtWZjl2dmZOd3g5ZlBQenA1NGQvZVBQNlFUdmcrdTI3MytnUUxNczgKNjcvNnphKy9rekgrcDljdjNzbURyU0J0MmdPL2V2UDF3MHVwMzY2L2YvbU1MODRTK3I5YTRiZlBaRTY4azdGNzgvSzdkNXhaMWU4ZwpQZnpMWjM5K3dEQUZ2Y0UvZnZQdytyZHYvcG5QK0VVTTBrN2NyclpEWE9TTlF0eVdRNmhzUCtKUnQ3bmRNL1IvdFdrMGhHYThmY3lRCkwyV2Mvdkh0aTkrL2VQM3pMMUtWdms1eDFpSDgrN2N2dnU0akdBN1YvcGZHcitydy8rYi82OVBLaTc5NzkvRGFubDdtemMydmhua3cKWC8zcU4zTFh1OWRmMzd4NWhkNy9GaE5jSnNCcm1Sc3YzL3hldjJ0Lzh4dTUvTHR2OUEzNCtTc1pxQy9mdm5pTk5xZC80RGYxcXk5ZgpmaWRmL2YzYk45OTk4NHZYLy81bStva3U3WDkrZUM3clY4Ynk2OE0vL3U1L3l3ZFpuNXliaDkrK2ZmWmNHcERQcmM3VnN4ZmYvUFM5Cnpjbkx2WDA0NkpkeUpULzY3KysvK3ZiaDMyVlY5Y3VWZXZmNmp3OHYzM3d6Tk5zb3dsVU8vL0xzN1RmZjMvU1hMNSs5ZnZiMlFIcHIKK1pjdi9pamZQSk9lNm0xMzJoTWFsVm55alhRT0wyR1ZreHU4cDhMdzFSTnU5T3pkSDRRQlBieisrdHZXdG43Y1A3alN2cis5M3p6SApISHg3T0w3OTd0cy9ISDc3NXMzTDF1eitxOWE2a1VsRi9iK05lM3pKQzE3LzQydnRvUE03V1lYVE93bi8rWnU3aTlSKy9BN3k1ZDl5CjZ6ZlBYcjU4OGZ1M3o3NzV3NHZubDI1dzRmdDJKLzN1UXliV24xLzk3czNMRjkrKzZ2TnBvSHo1N08yN0Y4OWZQdnptejkrK2UzajEKNU1FOTNIMzlRcGpjSTh2NHZYVis4NmRuNzU3LzRaY3ZmdmYyMmRzWEQrOWRmUmlBZjMveCttdVorNy81N3NXN2g5NUJiMTU5QXlubAo4SnMvUFB2bWdhL3g3Zy8zclBtYjFtRCtTbGoveU55LytPSTlYRCtzaCtQcjRmdS9mL3ZzNnhleW9ZalE5ZmR2WG43OThQcndhN0QzCmFmZEp0cTl5T0g0OS9kczBXd2tzeStIdnZqcStuZjdiTkovK2hKTVNoNUtzTEZZeS8vZXk0djlKZm8ybHRGTG5iVmV1aDNLVWNtUGwKZGloMzgvMDAzM3ZaUGRqNEU0ZVNockxzU3RZeThWY0pxNVRDMzNVbzI2NWNoMk1yTjYwY3c2MFUvM1E3eVljN2ttN0QvVmpHcnVQRAorVThheWpLVUhGZVVTWC9GTXBRYU55bjY3L1ZRamxxbS8rdlNXRDQybW1rM25zc3dxbjFzcFV4dGVKZGhrSFZVeDlHdFV2QWJvMXAzCjQ3c05JeXovVGpiVVB0akhOc3o2RzZOOE40NjIvS3MvODhXeGp0TnVvSk9NSzM1alpESEdLMHZsS0plVEViNjJzaDliR1V2OHVtTzUKUFJsRnYybmlHUFl4UTlGQjhpSGJiTEJrZ0NZYkk0elZqWlZibGpzcjl5aStzdkF5NDFnR2p0SmlIVi9ab1VjdWtudjJUZVRMcjN5OQpqYTl5eXljTzlvUXJwNHc4d3NUNzRqNHhwYlNrTlJWUnRyWjBsSEtiN21XMHc1S1daY2xMV2VxeUxkZkxjYmxkN3BaNzZjaVlVMTd5Cm1rdmU4blUrNXB0OGwrOG5lYUFnczNSWjg3cXVkZDNXNi9XNDNxeTM2NzNNaFNEZHNKUmMxbExMVm83bHB0eVdlNWtub2NhNjFGelgKV3VwV3IrdXgzdGE3ZWkvekpVNWIycFpOMnRucXRtM0g3V2E3Mis1bDBvVHJkTDFjNSt2MXVsNXYxOWZYUnlrMzE3ZlhkNXhKVVY1ZwpPZVpqT2RiakpsOGRqemZIdStPOXpLNHdzYmZUelhLVGIrUUJicmFiNjV2anpjM043YzI5VExiQVVWaHU4KzE2S3c5M1cyKzMyK1B0CnplM2Q3ZjNkTE9PUzdwYTc5YTdjMWJ2dFR1NTFkM04zTzkzZDNkMWpSdHhMaDkzbmUzblRlM24yKzJzcGNzdDd1ZkwrNUVmR2NwYlIKYkovdmhuSTdsSnVoSEhmbGVpaWJsMG4rcVVNcFExbDNKUTlsR1VvYWlrekE2VDYyTXJLd3puem44ZEh2eHAvYlhiblJNdkhYY1NqWApROWwycFE2bERHVWRTcDd1Y2l2THJxU2h4S0dFb2N4ajBTNmZyTy9IcHg5L2JvWnkxTUtWdVJ2SC9lanR4OHhIYXo5RSsyR1JvWmlHCjBkZ1B3YjdqOTkxdDNYelN0K3pQcVhYcHZpUDN2YmZ2c1pOKzJuZk5kTklqMmh2WFZqYVdhcVZZV1ZteWxZVWxXWWtUMTU1dG1jcjYKMi9UM045TjcrYytSNWRyS3hsS3R5TnFlNUovVlNyYXlzQ1FyeW5xZDBRc0g5Ykc4NC9nZE9WNlY0NU01SUJpRW1kMSt5MjYrWnE4Vwo5dVBDZmd2c3B6dDJ6SkVkVVNlK2VlYTc0Z1ZudnRBdFgrQ2FqMXo0aEF1ZlNKNURac3VkZE9hTjhLMXI0VjlWK05ncTNHd1JyaGFGCm04K1RUS1E3NmVVYllYclh3djdxZFJGR21JVWhKdGxSZ3V5dzl6TGl0OUlkeCsxYTJHYmRpakRRTEl3MHlSWVVaRCsrbDRsd0s5MTAKRkc2NzFUb0o0MTJGQVM4MUNTc09zbkhmeXd5NWxUNDhsbXRoMWJVVVlkcFptSGNTRmg1a283K1h1WE1ySFhzVUJyOEpveS9DN3JPdwovU1RNUDZ6ekpOUDRUc2I0UmphR2E5a2dxbXdUYTg2eVlTVFpPSUxJRHZjeTNXNWxMSTZ5cVd5eXVaUmxsVzFta2UwbXlxWXp5N3kvCmsxbHhJeHZSdFd4SWRaS2RhVTFaOXFna2UxVVFXZVZlWnVpdERCOTJVV3lyMkdpemJHN1lpRU9jQTdoc0UyaXRGdXA1TGRhVEJhV2IKT3VRMzdQd2JKUU9WRkVSMjRIeDQ1SFpzaGczNDVmMWlpQjJ4TTRiN2dkVXJTOWhrVW1XWlVFRW0wNldwRkcyUDRPNkRIOTJCQXRjbApkcUhNMWVzN2tlMUYySXBrdHhFaGdQZkdmdGMydTFWbVdiMnczYVcyM1dHenU4WU5lWEdUR0pMSm9NV2xCZ29OZHhRYmdna091WWtPCjEyTzNveGNncDgzMzJxUjhvREIzeTQ5WUxicFdmRU5zdXlpLzU1dnpyWFVZcmltVjNLWGR5RklrREUzb1VRbFBCUitWNUc0b2lOOUoKMDhHRWJIMGRsNXBOU3FaYXdhYThvZDRNRzJGdjZNVVhlMElmZVJ3b0hhU2RzRUJKSWNuSUY1a0JSODZGRStuQXV5TGJCdUFjWitRNQpmYXAwdmpOeUh2SWU3ZUlMN0dqUGpiNlBGMm5YbjZ6R1QxNk14eWIrZXVtS1ROMnBPTVhVSGkxNXB4bVp0alRaSC82akF2bE9SOTJyCllMN0hOQVd0U2Zvc3gybW4yTjFRZ25hbEFMKzNrMUpQU2xjaTlhOTFjald6bGVXc3BMTVNMeFQ3bVhhYTdwbENoeFUzQ21udDkrM0YKSW54aWFwcjJqU2xqUjlYT0xwYnQwVkpkNzVzR0pWL0wrc1RTVmNvOGxtbi9zUmtiK3QvbkpUMVNPQ21tT1Q2eFhPcmdDMlY2WXNVbgovMXpTM1QvcDU3TTE2UHRpYUQycU1xcUwyYmRXVk1KeW80UWJLYXJwd203RXNKVSttZHJzeTl2TkluMzZuNjVtbDFCOTlZNEw5cWpyCjJGWDY4OVZhbWdsZ3RaS2JnYURiaHRLNFFLZnZYNW55VnpOTGRQUFV5WEwwQlhrN0RVYXQwY2gxdkxnY2p6dlQyUG1DTkdQSzZmcXMKT3l0YnQ4NjRoZWJTRW0yZnA3T1ZlYm9JenhmbGU4dDBaakM4dEZMZnQzNVBsdWMwMkNBL2VRMi9ieDMvOVpmZFoyL3drb2c2YWovbgorby9LSStmNmowc2hNM1RvTzBvYm0ybCtxOGtic1drLzk0UEVVWFlTUnh3MG9CdlJnYWdCVGFJQ1FRbFNGUWhLMEV3TlNIV2dHeHAvClZBK3FUUTlLcGdkQkU3b1JMZWhJUGFqU2xMUk1WSVVDRjhjOXRlSmIzRUd1cjZJSnFTNEViU2lxTmtSOTZOYjBvU1Axb1VwOUNCb1IKT0ZlWVRDbTZwNFlMdFVnVkk2aEdsYW9SbEtPRnlsSGdVcnFuaG5SRERRazZFclNrSW5kRlZWR0VKbEdVRXRsaG9Hbm1qdXJTcmFoTApVSmlnTWtGcGd0cFVsa3pGQ2FwVElxZWFxVDdkbTJKOTFES0ozQWJKRGJKYm9meTJvbjdDVDZEODFMazRaRm9kaXk2bHFXUldxVUNoCkxGUGoxR2RTMXlCanVTVlZmNDhNZUJTUktBOU5neEMwWTZwbmpITW51ZXg0NUk0alRqdVpCT1dFdDExa2ErK1JJTTRsaHFleGlVZloKeCtkY3g2WXRhaG5OVk9QUDNpdzNtQnIzdGpEZlZ5ZjdJKzVLMnBXOTJTMmZsSFZYeXJRejVaV2RrYTlTVWRxWDY1TnlQQzFUczNsNQp1VDByNXovMzU4WG4yRFR1MVBmaFFva1hTN3BZekpKM1h2SWpaWDIwTkZ2dXREUHNGcHFiMzFlMjd5blgwODZjZkxrY24xakkzS2VkCjVmcDk1ZlpwWmJwQXZEU0lUeTdUbzE5OTVNLzVKdnF4RFpuaFptN3FaelNQaFpiRmlwb3ozYnhackxqMWM3Tml0dEhKVEtYKzQ3eWgKTHhzZkQrZXNyaUs3Sk85V1dyWFpMaE9OUmxyV1Z0ek1XMXZackZ5M2NyekFvK1JuT21OUWwxaFROOTFmNWtZREg1b2VZVUtQY1ovSAp1TTdBYVk2MDRUek9hOTdEWTNaTXhSakw5RjZlY29HVGZCOExtZDdQTjU3QU1rNVl3elJ5aVk5bURjTjZmNHd4UEpFTm5LLzh4OWZ4Cis4dGZhQjEva0ExMVowVVZrZTFHaloxMHdrTE9Tc3N5aWFTM0RyN1lvM0FDOWNmTzVwR0ZUemJUSzF0Rm9IVFA3QzE4czdLNXFITTIKVVJTRmc3Wk1sRS9kU3dzLzdSMDl0ZXFyVFpBdTZhL0ZEM3kyMXhTQTRiZkZBbExmTGJ5M0VDenB3WjNveEsyUXRPbklQUW8zdW0zdQozRm5FUDBpUzhPa3U4bmlRa0F2RjhrMUU5R3Y2ZDIrRVg5eVpsM2UrRHBQSThaSHlQTnk5Y1BpdTE0V1Mvalk0ZnVuNmxZTHBDRUV3CjBNQ1k2QWFHSXhnQ2VhRTd1RTdIalQ1aDlRcmZrQmRoYWQvVFB6dzNsdXZNMXRtc3M5Zk9WbzJqVG8yVmRoYnFyTE16emM0ck80L3MKdkhIa2lMZFQ0NE1qLyt0OGI4L3JSaFkzc3JXQm1VMERIOXV6cmhObWRVSHlPZWRIZzB4eldXNTVqTXVjaUIxam1kN0hOYjZYVFR4eApnLy9ZZFd5RzYzK2JSbEJ4T0VUNWF6M1UrV3FSNVhJbzZVb1dTRVRWMzB4Lzk5VlRxaDYvUFcveEtrdkZQQjlxdUJJOWNIMjB1ZE42CmFPc3FyR1ZiZ253Wm9OMUdSeW5uV3VNaWY1UWM3ZXNZOHJvZFVFRWJpVmRwemt1NzJTYzN4S2VaUlRQTnE5U2FaWkd2dUU2VWExRysKMmRhMjVIa2pkbHFZNHBMbGo0amZZV2dyWGMzQ1Z2cERmYWIyOU5uV1dSZ3Eyc3Boem9YWFZXSEUycGFvaUZYYmo4SlIwWmFNVzk1MgpiZVY1M29abit6enRmZndveG5KVlU5clFVczFsKzhTaFBHM3R3a3kxSjkrMksrSG5qMDNUZlNWcDVYamJJSTZPVkx3TVh2ekh0OC8vCjhPTHJuMDcrQjREOURiSjR0YTVCOWttTVk0cWxyQVF3eXVKaTkrSnJqUHh1MmRvVkI3OUM0eERzaW9OZFljdFVIbGlVOWVHVlB1SmkKN2JDblhvaHVXdGFybERDOVArTEcrK3MvcEp0Lzh4OS9sajdHdjNMaG9oMzgzM3ovdWJkZEo5cCtrODJmV1d4M3ViWU41WFowUE50bQpzUmdXU25ZRFNrS3lGd1REZVMwVUVZRDBPbEkwdUtkVlNFV0NsY0xBTmNXQU8rNFNBSHBoMzljOS81cld2dHRUWUtPQ0dOMGpwUFp0Ck5aTmpMNTROQUtvdVhVZHcwaXZjUUhINU1hemtwWi9IMGJDajhUcWJVWVpXUWtWT0VEdlIwQk9uaHNKaUtBckZVUT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJR0pLQ3BzSTdBMVBjWkhYcnZoOGVNcUJEbm9RTkdYMnpUUkFLQmgwWXdRTWRQbkNqMHM0QUlWaWFkTE01ak9CV3h3bGlyQ0VKSWIxVwpSeEZTWmxVTVlhV2NDdmtVMG1tV2ZvQkllaU9UYmFZWW1nMHdlRnZVUDQ1dU5keEZSMTdzZ0J0bU81eWIxL09HMWtFMUJ4WXoreTNtCk1RaG1DSDh5WU9aSmFCa0ZCSFR6dHpyY28yS2JETk4wMjNCTTE0WmVjbk40TnBpU3dwTm1Da1YzT3kvNkFCUnRVRkUxbjZvL1BEV3QKSWxPeldLbGRGR29ZbGRiZ2Erb1pSeG9XYmllS2xmZFVPTHJLb2VoUGpKdnFIYXA1ZE4yRDJvZmhRUlVSQ3YwREdzZzZVUW1wVkVKYwpEYm5kcVNJbnlvanBJaGg2UjQxU0gzR05aRHBSU1RBbk5nT1MzbENxdm10dzBraUZ4RUdsbzBaeVE0M2tEZ0xwWkFwSkdoU1NZc3JJCmtjcklMWlVSQlp4MlBXUVo5QkRvSUUwTG1Xamo2R3JJdVNLU1RSR2hLdEwwa0NOMUVXb2l5b2NNY0dmNDV3R2tTRS9oK2Q5MzdlODkKMWF6bWs4R281WVA1SXUrNlY5TC9Hbjgza1BVSXFsZUR2RUdzUTdQUXA0YXc3Ny9UN3ZkaTdOZmgyTG5oN3RYNEwxeHgyaUh2SFg5Zgo3Ri8xR3VpLzZzenQvMTd2ZkF5M0J0VTIvRDJCUDNBVUQxanRqdFJPNXNKWURhdTltaTlhUFIwZFZFOC95RFRncy91UzYwc3RFUkJ6CnVzdzRZd2lja2RYLy9qMW05QkdjK2dzZTh5Nll0M0owTVlUbWxoZ2RGT2NPMFhPZjZ1SmVqbE5IN1BtbjhmZnAzeU10ZThSQUR3MVoKSHNWdVBJN3NTTHUvMHpSOFdFNWNOcU1qNTdMUHVuL2ZQTmpUbWE5SCs2NjdsSHV2OWg3dWc5QTlNRHRrNnZFQ01yVVlLTFhEVVIySQphaEJVNWZUYzRXV1BuOGdicnJuUjYxWmZhTXpJNUNmSnRuemQ5UGN1MGV2bUVpMWtWdVlXblNnRmROL29MUjlPdHozZCtIenJhNXRmCjIvNThBeVJtbEp1Z2JJT1Q3WVBqVGpqdWhTTjJkSThlM2VOSEc0SjBVc0hIUEtTbkdOTEhVS1R2d1pGT0EzVHRvOEJyUWJueU9WcDgKS044UEdPK1diN09GVHcwbmZZNlVMczJvdmtkTEQzaHBLd05jZWpwRFROL3VFTk9QejhwcS9vTjFQemVuQVMwOVlxWG5ObEh2emE2awpiNmJ0SDl1YzFWbTdjYS9qM0oxcytxN2NDdnNrVGdZSlZGNnVybHlmMEhmV1hUZURyMThudDVUSlpuaXhXYjVTV2FDSW9xeVhIRnczCkN2VUw2N1MvNDlUbjVGY014Q1VuM1dsSXhHbTU3QW1NcDhiOXM2Q0ppOEVUZXp6L1dTREZkQjVOY1FMM3Z4eFVjUjVZWVhFQTA4WG8KaW5MaXNWMVAvTG1QQjFtazZkRTRpL0NlbGZQWXVwR1ZNMTFjUE1mQm1kVFh6N2lHaHBXMHM5NWRiU0prcGt6RkdlSTdyQjdDS0NwMAo2amtJczhxMGpZZ1dYVmVvMTNtTElaZWRHVU5xZHhQZjUycVBWcCs2cmx1Z2RyK0pJRnpOa0NJZm02VkdMVnpkWnJSZWlmeFUrOU44CmRBdThmMW1Tc0Q3WXBsSVIxbS9YaGxCRTdzY2I0aSs4YWwyRVp3NHZrVmU1TkhSRDVTYzNwRGF3T3FmRWZzeHBxelQ2eVQ1YlUwKzcKVUhBOWpHdmF1OWJNZHBYelBCcFJQcjJsRHpLbmZQZnExY05iV0ZUMER4ckJ6R28xU0g0dWtJMVMxUmhHV1Jwa3o3Rit4eFlFZStlaQp1NEtBSWRHNmVKMmJERjJhcE53akdUMFVkUlNGZTlncDFiMXBpRnFzRGFYWkEwb1YwYW40enNkMXpreXRrNEx3TkVqQ3FuSnVnMFI4CnRLM3N6alZQMFQySlhqSUFLTnVoOW9rTm5YcmlSTUJUSWZ4SkZWRlhSbysrUHhwdmNnK0ZDbnZSY05lbURHZHJOZWVKMmlxaFhMUkQKVkZOWnRkZ3U1Y0ZEdVczR3piUHNJS0tHSVowYVdEMjFrbHZwUDZXVjJzcDFLOGRlcHZWbUtOM2J2bmU1akRET3NDdHBLT3k3cVN5dAo1RjA1LzZrblpidFFycWR5ZlZadUhpbTM3eW5OYlRSZDlsbFR1Zi9Rd29rODFmZzV5bmtNYm8vQ0xTME85OWhYYWRqSGsxUXV5bU9QCkpzWlNuRXdkM2NXa2NKbmREL3BsZHcxdkZnZHpPMWhxRmw4ZnNNOU10aVp1NkIyY1c3QnV0bkRkU25QYnRVM25POXBpTUlFVHpZN1oKNWlZc01VZk94RnZNUUhjTFI4Nmo3aEsrcGt2WXhvOVl5VUJ0SU5FKzVyYVhTbU12YkM4UU9HaDNtYzN1a21sMVVSZncxaHpBdDJiOQpCUU9NRk9LNjFRWGkzdGJzTHZUOVR0L2ovdTBPNEcyd3Vkd3dLaGdHenp2REVUYmY3M1RpL0YwcEczZUVqVHVCVmVMdFVKb09vZW5nCkdZN1ZkT0lFWG5kUW1lME1LTE56Q0EvSW1JYUpVVzFrRDRKeHNld1U2M0tPY1RuSDA5MU1GMUF0RjlFc285eDZqbXJwWmJvZ0dWOUUKeUQwQklMZGNSdEk5aHFKN2I2R21Ic2FZWFkvVzlTaGRqOC90c2JuK0RGM3FONUYrRU5vcG91K2piM3NjczB2V1hZcnVnYlpOUUI0RQo0bHNGUmUwRGE3dVlleDVPMjFYREU3VncxQWVuQytyZ1pSUEZtU3A0b2dlYUpqaGRVQVgzeXVCZUhkd3JoTlZNb2FWdGRubHFhbUZYCkRWMDVqQzN0eGp5b2lQZURvbmpYRklNV0ZUejVqYS83ejlaS2JhWHZYWDBienEwc3ZVeW1WM2J0TWc0NlpoaDF6VUhqN0dYVXhEaWUKMDZERDNPeks4YXhjbjVSTFAzVWlPOTJYaXpzM1RUMlBseVlHVGYzUGs3SjhjT0VPTm0zcGM1UVBqOVorZjd3MlF5U25reGpKODVqdApmYVRrUG01N2pOdzI1OXpVREhhanNlN09wbWszMU8zTWRPcXJhOTQ2OTlkZCsvZ1dHeC90MEhnU3kzRFRQRlhiU1VSRDZyWTZzOWJkCmxkdUpLLzdJNmIrWkE2dFFPSFhYcFJydXV2Tnk3Nzdza1E2RnNtMmVMTnhCdlpoeEYvSndSMzYxRDN6WUtKU1VadURMSnA2M0dJZ0oKMWo3YSsrNXRrN3VsM2UvR09NVVlFcUZCRVNvT2VXaUVCa2VvV2tFM3hOU2lKTzVOLzFEdXFVenVTR3ZodFZrTVBYQmlESjFZVFpNdwpKU1dsaWJxUGg2U0dDN0Z4ajBYSGVaekZQaUoybTB6OTJnWUI5TEdnMkY2V1N3R3lIaVo3L25NZXgvWlkrTlFGSVB4MFJycjdtUEkrCmhCWEJLSFVIaXJqOHZRRXU4bHhGdVNQbVJnVGF6UUFUR2JhSDBLMFF6ZVp3Z3ZQNGlLcy94RHJ3VDY5ZlAzdjE4UFhoOTBZNmhKOU8KbDRnZDYzSWg0MDl1dXNhUTlTYzhIcmV1NGUvM0hyMCtHUXoxRklLNkQrTGZnMC9WQjZ6KzMrc2Q1bFRVaXFrQlRyZTllNnViT0pZegpKY2tmM0lQdSsrT2Z2c0J4MGpjd284VlRzeEc4QjBrNzlmZDUrZ01mN1lGN2pvQ3h0M2Y5UFZtSGg5M2pqcHJkWThrVExnTi8wOVM3CnZ5Y08ra0VTbEh5bTlDVFg5MU5QVC9LRFpsVDU4WUgxZ1FjYmQxcEtucEdJTmhhMU9rTVhMelREWHFuaDZjSWZGeG5pWjJoS3VLT20KM3lXbE5iMmpmUm9IbmVlTFBGVEkwblRlY2RGbzREQ3M1eHZDR3hLeEJ4dlhMVGhNSWhaZ282WHpUaGFvbWwwcWw2UkNtRFFWMnZYVQpFRXlSN0svUVZuZzdKRDl6QkpNRDZudnFzMkl3ZW9Mb0hhMHlOYmpLSHFwaVFKVWRjRDZieldRUG5COHRKM2ZiL2RUTUp3cGNpYWF2CkxHWkljU2o5YWtxUHEwRmR0L0FmVTU4bXM3VW8xdjdXZ0M1ajZRRWh1NUQxbml0eFg2YW0xZldTTHBibGtaTDNaVG9ockU4cTVmRXkKUGZwVi9iZ3lmVURsQzhyZmVabWVWdTNwNWNjR0wxUm9Vb0pMWVd2aklpcDdSVW9DWlpkck1SSmRWTGpwcXpHM0MxazFYVStheTZqSgpWOWpleCt5S2lRYmIxZUJ6RnNQVFFITWRNTmRDZDZhR2xmUEluWDNjVG1NNUFNbWRSZTRvVUc1dHhscmhQNVBOeEJ0enFONVpFTWRzCmNUekIxQk9IenVVV3orUEZiUS82Y3owWlovRis3WFlPdDM1MHcwaVBFdW1HbEhCYXBqRi8wTTRxazNiYzdyemtzMEplT0EyMm45TnkKd2NmeFNPazJwVHFOSDU1VXppdzgreko5WDRVUExVOXQ4TWsvMDlPci9xZHA4REVPQXAzaXp1RHBtVnJFdGZxR1dxNngxWlFHVDlJSwovbUVxMmdTaGhCN1QyREswUWplN2I3anF2TXZPcXE0ZWg5eU9icDZMSE1SNWlFTnRMMFQvWGVRaXprY0tzZ29xTTduZWNSSTFpSi95CmtzNVBvcGxjT2xmSlpvOHMwOEJZL0tmUDBUMWYyU0ZEVGdFd3ptR21NeWJ6R0xPSmo1UVRqak05a1FGOUh6dHFaWHJmbHg5UjNzdmoKUHFyODJPQmZvTUVQaVU1NThzLzdHdHpqaHRPWldhVHM3RGhtdzVtYVZXU1hPWEVNczZIZFJzMGdMaFc1ZTNzMTB4TUJJU29ZVFJaNwpVTGxPWUhlNmI5TFJRbHZ4Nk1xK3AzU1VMSUtra0dsQXhpZGFRckVRRTUzWGluUUFLNEhkVzEya3dBb2t1cTJ6Z1IzQVp0UWpCdGVwCnNxclVmTlpaZWRGa2JPakdRcGJnVzUzTmJhM0ZGN21QcGZNcmQwdDFNQnVWcDRrYVZOZVRSa1ZvMUc3MkNzbXAwRHI4S0lMNDlrSTUKejZhaW51RDV2U1ZPTi9ISlpYbEttWjVXN1daOWFwbWVYdlUvVFlOdTFybzlTejU3bERsYjdySXNPbVJqdmJYRVhTc1RkczFNMVhXawpqV3FsZlNwWWFxNmp6REs2dG1DVWdra0s5aWc0cytESVVpZVdnc3h2bVg1TG9lWFo4MjdSVTlYU0Q5ZmkwVlJUQTVFL0pmWHdhZkxoCmxuNjRZOGNuOHpLNWg4bTlTOGtnNUtFNWxXNEhJUG4xa0YycnU1SG9RcHJNZytUdW83M3J5QjFIM1duVVhVYWp3eWgxYjlFME9vdDIKanFKVE45R3BrK2dSLzlCMDRpQjZ6RDIwY3c2OXp6TTBQZVlZdXVRVWVvSWZpTEU1VHkwM1R5blQwNm85WW9tNlVLYW5WLzFQMCtDUApIT1JIRHZJakIvbmJYWjkvK3czK3lFRis1Q0EvY3BDLzNmWDV0OTlnOTNWZlBMbnU2VVM0eWt0Y2F0am91bDYyd29RcVdlWVlLS1ZrCmRYMkhHZEZURi83Z24rc0ZyL2xuYmRVYzZNZ3NFOUloaDZ0WmVOam9Sai81eHV2TFBlV0xOVndoYnYrUWxxczE5UHhPNzZteHY3NUkKcXptdU9GTTR4YTFjdVA2MFJydStsQXMrLzVIOGlXNy9lTm50SCtIMlQrNzJiOW5FN2s2Z3liY25FT1ZIQzNlczY5dXpjdk5oUlpzNQpoU0hqNTMwK2x6UHZrRVloZDZESmJIRHgyNFlUUHo5NnFaN0gyYmd4Y1R4R3JneWdzdkhreGZIVXhaUHlOOWRNVDJKejB6TDdkVHVYCnpRVWRpdjM0N01aV0sxeENRaGdXd3ZPNnRPTnk3SlNhZGk2UHAvRG9TV2Zxa0c3R2s4MThhb1dSa2FXMUtxY3BLZU1ZYk9FOTg4SmMKYVhVSmlYblI1cnhzYzd6d3gyWHN6K2RyVXFOTDh4d0RXeE5aU1p1Rml4eFF5em1zaTZFNkRjK1poSWZXaXV2NzQzemM5WHJ2ei9JcQpuNzF2UHBFRlhtU0E4Y094bzNlR1o3eHc0bEhEalJxTWNYTFk1ZmZoSnNzWmJ2SVMyUE1FcmFwN1AwN2JmRS9ybDkvaU1vaDA5ejZUCnY5TEhRQ2kvRjk0blBOWGpCVDUzVEFMdk1IbEV3dnRhL3dCNDRyNzlGdkd3NXlwMWdPbnRlTVBwRno4NHlpOWRtdXRwTjljTlp4WlAKTXI2T1NaWjBTN2hyYVY1N2t0YzhISSttR2M2T0U3TmtNNlJ2Q09mcnFWelhsc0wxMnVMMGRON1NQYVh4eHBFcVhxYTZWd3pLczlGWgpkYlJnNGp0enlYZFlUeHJpaE9IQXF0T3F3Y0F3NFNQbTk4N2llNVBoQ1RNZFdXTWNwbWRJd3l4djJWMU84N3VNR1Y0aW5lOHpYZktlCjVXWE04eklFa0V5UFJaQzBzekU4Z0tSNkFNbm5ndE5lWG0xUGg5T2V6TzBQelpXd1h3QWZjelgzSXJsdW5wSDlJSVdRbU5CUnJ4UnUKdGRaMXpKazUzTzVETHZxMGRWWXZMclM2U3c3Wk1xQjVEclF4RzdQRFJVMnE0dUNmWlg1MitHb0hjalFJcTE1dzExQ3Y4d0FONlpmNgp4ZkxEQzNaNUJHL01FNXk0Z0k3bSswMjJVdlFPajV4RGVUbDcwRi9pZ2k2Nm9oL0cyTWpUYkRtWDh1V0VDL2x5TEZmTzFBTE1YS1B3CkVFY1BhOVFkYTFmbEF4THFXRURqN1k3VENLK1o3TGdkanpMMFdMWFlZOVgwdnYwZStlS2Q0bnRTOTdTN2RjNDJuY1RGUlp0QWMyTncKT2o2MEpFWmhEWGM4WkdqajZVTHBHS1FQYjVrM2M1V25pSEpQbkI2MDBXeVlwSWs3Sm4vTXdnSm4yZ2MzbVZSWkpsZVllUFRQVVdaYwpFZmFkWkduZU04cnRta2Y2WURMb0FaR1hKYXNubks3NS9jRWhsaFArTkNQODhwL3d2bTA1RGFrY1cxNzVob3QzL05aajdHelAwQWg0Cm4zWnBCanEyZllTdmorRDBFV1BlY04zSzVOSU9kSHNoWC81NytPWXA1MFFXcTQ3OUg0RC9sNkgvYTN2VnNvT2RLZz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJVUhISW5abDNHUno2OHozR29FOVpkTVA5NmhDTVdMd091K3Z3dXZNUWhRN05aU2JaUElLRVRuTEtFaDMweUU2UXovWUNRSC91Sm1KKwpNckUrTjhUNEpPSjZBT2U1STRSbklXQUhJQjFnY2hKeE54dmhOSURKQU4raVR6YWVmZnhwUngvclVhdlRwNXkxNmljUy8vaGtIL1ZrCmc1aTR5dFNQVlBERHZGSEJYK2Q1Z2NSM0pjc2paUVpIYVI2cjh6OTZucThxa3R1UXkvOHpONnVDNVRKSDVnVFBhd2pNUUNiZEoxMUwKcWJHbzhTUWgxWHU4OEVkcmNvMVhtNmpRdzVOKzFtYlZIUE5wOW5Gdk1seGg4LzFzWnZlVFpyVlBaeVFleFRzTFYrR0w1VENuamFNegpyMVZmbnNuOUwveHhVWkQvVEExK2twQy9YSkx4bDUzZG5HbVRrTDJuV3BMMmV5Wm9kK2FJOU96M2xwZ0g3Rm1USU9zZWVXZWJZaklsCkhOdmVOcG4rZmR2MDczRGpCNU12N1hnVnp5L2VEbFlaejFVWkRxV1NoVHp0VDZNNk9ZaHFmd2pWaUFQZkgwQTFIRVUxcGhwOC81bDUKVHl2MzA0Y2RhZlQ5NWEvZm9OcmxOQlh2UHY0Sk5qZFkydlNjZEpYeVhNSTd0a1JXaVZuaENwTWkzOWdHem1oczNjRWh6MW5TcXBaUApmTEhzYkc0NHVlRXVjVzlJMzBpVHlkTFNxUkh2T3pWemlhWkFtaTF0VmFUQkJJNXdUN3hXTGNkWmoxanFnTnJCWFhLU2pPejByRy9tCnU3cGM4c1d5VEhXNVdOYVBMZFBIWC9xWkd0U3AwYk91ZVNvNlQ3V3Y1MjE2WXNOaS8yOEQzVk0xdzhDYlBNdHpwTHRqVE1vOC9vdmYKWTVMcmVVaDNQUUxabjRSMy82aWZIeHQ4d2dWMkNNWXNxL0ZHQkhtY2hvdHpjR2VlZm52a3FiY1E5Q0tGUEloNEVQQWczaTA4em5ibQpRYmFRN0VhNWpvaVZ4OFM2UWJCcm90MnRJUyt1TFl1OG56M3J4MFdrYVRqRTIxUGo5NHo2NHltejQ0bmIyOW1VYnhraDkrZlZ2LzlVCitpY2RXdjE5eDh2LzhHUDUyUnRVVTh5Tm5RT2RhWklad1YzVjBoNW8wb09XOGVEOWg1cE03UUNQZFc5MDJsbTRqME9DSkxkd2U1S2sKMGNnZDZqeVpwZnZlOHVuZG1yMzd4bXpleHhiNzZSdEpUNWpaZjRhTW45TkozczNscktSSFNyeGNwa2UrQ0I5YnBvKy85RE0xcUZpSAo3aE1ZdlFMdUZ3aG5DQWpIUDR3SGovZmNlQ0kzeGwxYXZKNGsvU2taOGZZNThaajV5ME5YVWl0ajlNc2UrWFVTU0hQeHNNeTc2YkdvCm5EUHN5dFBLemZUOUlKY1BLMy85QmtjRDMxOWRLdjRoR255dmJqRTk4c1hsUXdmT3M2ZVBXZFNwRlUwWGp5Qll6N0pMN2pOTWhyT0YKNU12b09Oa2EybXp0ck9hTlczYkhHZGtCRnhkUzNJUVRiczhrLzJEM2lSYjVld1B6cWswK3lXNStMNDk5SkNkZmhYZkhxdnZLWDEwcQovcFFHTDZzSXl5TTZoV2tjMDVrS2NxYXNuR1JVSG1GaFhmdHBHdEhVMGtENzNxVlpwSFYzVVhsSGM4M2VHQmo2U0Myc1dDTEFoYUplCnBLQUZoTUx0UktudnhwTCtGUU5DTThXZlpmYURpVStCenpEd3didzNFOTE4STFxanluOXExVlBoN3pnMXVZOFNuOGw1a084ZzFVR00KZy9CMlRWMERjbGo2aTBmUy90amcyYzllUDdOQTQ2bDk4TE4zNG9uQ3QxY0VIUlNVMmxFK2UwMXptd1pWczU2b21tV25wRm94VmVVVApPK2JzNXkvUzRQdFZnOGVPSzdReVhUd1M2dlJNcDFHZGFWck9XUzlTSzVvTXVUa2VYbkF6NERidkcyQXJ0R1I2eVE0Rlc0ZVVlcFlEClVKUHF1UmR4OUNPK3o1TjRudEN3cHpQa1FRSmI4eHJ0ODNqZE1OTk9wR1VKU2ZsNURxR2VZdm5YbG9vL3BjRkhkSWRIaW1rYzA1a0sKY3E2czdKV1pRYys1ZEpEQTFNOE5zSEswckNMOWVJQzdJYi9JM0hLTXZDZkx5R1BlMDlGMzZtZU5iK1l4N1FmN1JUdGNYQS8wdTU1MgpwdXhvaHV4S3Y5OE43ZGVCbnI4c0R3eDd0VUpLL3VwUzhRL1I0SHQxaSttUkx4NVhZTzR1NlR4ZEk1cUdMUHk5akFwVlY3TThKMERYCnhWWnpJNVNlcG44eUphNGYxMzQwUmU4OFkvOTRZbnNIK2EzbVNqRG53ZVJZdjdQemNmVWs5blYzTnU3TjNlMEo2cXdJUndJK1ROZ1cKVHU1dHVERjM4VUhEejlsY1BhVmU0YURmUTFtdVFpNkRVKzdUbXFGcks4OXhJNDU2RG5IbGNUekNNMFBXM0k1TDJtSWdtaG40NnRHWApGOUpoS1ZmQ2x2dkRmSEpMZXZyUkI3MVNMWWU0WEpYZGMzeDBDNS9rVE11WG5HbDVoMHk5aUhzNTNhK2VuQXgyV1U0Uk1LY1ltRENjCnc0cjhUME9XV3o4bzBrOGc4bi83QVlmNzR5RzdpSlZPUDA4NzBXQTgyZkZVU0lEQUpjSldPN2ZYTVp3ZkR1RTBkZkVrSCtwMDNCOTUKM0pPcFAyWWZKQ0oxUEwvaGZqaG83ZndBaDIwNEpHMS9oTVBTam5DSTA2T25PSFFOL0hvd1QwSFlEUHU4clpFbmlNMnhsdUtuWnEyegpMS0RJdUFJZUdCOGV6ZFQ2NFJmck9WdXlKT2gybGpteHhHSlhWbzlaMkJUSGVobVcraEhYZnRwYXV3Z0R6ei9pd0gvRWdmK0lBLytzCk9QQjF1N1RTaEhvV1hSU2VFRjMwZUc1NjArZytzMG1tN1RSUG5HMVBTT0h0azdjZkYzUnI1Nno2a1VIOTBLRGFEZzFhaDhPTCtvR2gKT0JucGhQZC9NQ2ZkemNLUHVsclBTemc3UzJFMzRSNzcvcFBtVnJrb01wWDh2c2kxUjZPKzNuUHl3UTUzZkRta3JNc3U2NldwT3pUdgpGb3E4QzFoN05FNnROMWhQWXRST1R3NDRlOXJMNFdtUFQ5N0htZVZ1Q2ovT2ZaL0tmOSt6S3A3RzBwK1VKLy8weE5ZZ214SzFDNW16CkVOWkJtZGR0c3lsdWJMYk45ZE16UlUvV3lTZTM5YmtqM2Y3bER5L2VQZnpYdy9IbHMrZi9JY3RpOS9FdmNRckl1ZG5zSTg4Qm1jNFMKem5xNmFrODNPNmFhdlczSENlNXpWWHVPMlJ1Z3J1NHN2V3djOE9oN3JQemo2ZkhINVBqSGpvLy9GUGovelpEeG52ai82ZU1EQUt5MApGSkNlcVBIVTdISmlOZmtoejFjNXM2eCs5QWtyazZxcGo4d1V6OTJaN1NoS25TdzlQN0dMd0QxSHNZaStHME1BWFBpOXN3TlBuNURuCi9DUS9zVmtOMzJjeGZGcTh4ZmxoQ3g4YmNiRlBMZEFQV3poTklYRjdJVW5CazZiQ1I1eGNNMyt1czJ1bUN4TmhGNnBELzk4NEVjWXoKU1gwYURNbXEzemNWdmk5aDlUNWR0Wm1ScC9wcEFTNm5rK0oyK3ZnUWwyR0tEQk5sZXVSWWpuMDZpczhuUFpzTS9aZHI4SkpuNnRMQgoyR1hQM2FZTHpPMkNmbkV4OC9BKzc3QUZGRTJmR0ZGVU5LYW9oeFJOSHg5VFpKNkZveG9mYUhaSXQ4c2thMk9mZHVUdVF1S1JIK3JvCm9vOHgxVjA4dkdqNkVHTmR3L0k1a3M4VHQ5MzIxRzJUbVNXWXZhMGxiN3Q5VXZxMmZmSTJpMGFhUGkwY1NhTjZEYlhLZUtUcDR3T1MKaUZnRm5tRTFwQ3BBcXJLYzdrL1N3NVFMR1dSK25Bby9Ub1VmcDhLUFUrR3h0RkVma0ZUcExEL1VoMS83UTVtY2hQRFZQN3g1L2VYYgpGNi9mdlhqOSt5KytHSFR0OFl2cEg3N0JOMG0vK2ZMWnUzY1BiMStMRW43OThzL2ZmdnRNMUcvNzQ3QnRWOXVhRm5oT2wzVk5oN2dzClY3S055eDlodlpLNXRQSkpyL252di81SmZuM0hQOTNuK0s5LzVzZi9JWC8rYnlIK1NWNys4S3ZEdi8yditmQzFYdkpyK2VYMzhDWVAKcjRSNGRxUERMMGVxUDg4dmgrc3YwWFpYdjViL2YzYjk5dDN0aStmdlhyeDUvZXp0bnc4L3A4bmlaOGMzYjE3SzIvL0NldUtydTY5Zgp2SHZ6OXF2anMrZi9JYjMxMVc5ZnZIejQ2dGNQejkvOTlQQmY1WUwvVS82M1YvMHYzN0dCVzc3TlAzSTZSQndWcURiSUVETW54aUlUCm9sclNQenRBdGZwWmdjdFc1N1FkL3ZVWkc5cDFYQXJoYWs2cmpIdTlTaUxaYThmSXEwVVJ1QTU1dTFwRnBEcklpcitTcHZJaEZ4elcKS3U5Y3BYcU42WkR6VlpDMWRYaU95MnEra3NWYkR6bGVyUWdCRmNuL2FwRlZkVmkyS3hINmNYYnNlaFZrQVI2V2RDVnJMZHBsMjlVcwpYT0dRNU12Q3hvdmVMZGFySEdIUXIvTlYzamFab3VVcXdmakt5OHB5SlNxSTFGb1JtQ3QzVytVdTg3SWVVdFJuQWlIbHVoMlN2SVpJCnQzcVpFRU9vNVNERFhJT00vVnF1SUcvQ1A3NGhTbFMwSUJuT1hFQ0lxZHFycmZNVmxKTERzbDdoN0o5RGxLNEpzaFlQUzdoS290OGMKV28yVXJ4YS9LRnlKb0xxMng0NXJScTQwVFptRzVHVHJlcldFYlRtRUxFTXFnNkJYclZkYlNPc0JOd2gxNHdOSmk5SldYWEFlYms1WAp4Z1NFeWZoRjhqYnNzaS9DbGJBb2RIV3FWM091NGJCSUh3cjdFNEk4QmVaRElEdkplcDMwT1NDZWgxRHNOUlpoS1J1ZVdVWWNuU3VmCkY0VERZcnczRzdDRW1TLzlLYS9LMFVRclhCWnl6N3pLZTZaRngydkpWL0trTmw0cFhNbmZNb2RXNmRjZzd5V1hWMUVuRHVzaTQ1YmwKbGt1VW0waTdxOXhNaGxZdmt5a1hwT01PWlVXMGRtVW5DbmRlY0puc1NFS1FSWmx5a0haV21XV2h0RWtscTJSRlc0ajZQYVJaWG1pVApjYStMakxNTWsweDh6bUNaa3NMdmRjVGtzYTdXV2ZwY1ppQ2NUREtWY0RONXN5cFhaNWxUU1dZYnAzU0pPdXQ0bVF5d0tEYVJrZGRGCk9pQ2g5K1JlOHV4elR2Rnd0c3B3MWI5elFkOXl5Q3RUMmFFKzE4bXJrU2dUQy9rSU9WczJCRjNMdE1JYlJIYkEzRDdyNUpISGtxMjYKMTVHVkkwcmQwSWdSL0ZZK3U1VW9jM2RiVWN1YWtibkdGMnYzY2tLYnFYaWdYc3ZmbzdWejhtTCszaW1nSTJSWVNwSTFML1BxMVk2NAo2THhLTWl0bFA5NUFrTzFWT0lTdzJpeWoyQWc2YURMTGdxeU1YbXZSdS9aMm5HQjMwOHVjR0s5RVk1VkJhKzJFcTBWR2Y3aWJFZlF5CmY2Wld5NSs2dFhQeWJ2N1MvK1dmNUo5L2V2SUc4WXR2di9yVk05bFRiOTU4OCtldjN2dzdONHkvZi92bXUyOTBoN2g4eGE4ZnZubDQKOXU3aDY2L2tGcnVkWkR2ODVLZUhmLzJYQzN1S1RJeTh6c1FVQ1YvWjZQR2NTNUdld1c0aXJLakVQTzRtUmMvbDF0MWtxVmRseTdJeApZc0VzT25NN0Via0o0Q3FWQ1NKNnYweGxtU2hWZUt6MHN0WkFRbHdSOXRoRlFkaEtCRkVtaTE0bXF4RlJCNGVTdGZGRzJLd0dMM05pCm1EZTdMbUtYbHAwNWhOVW93dnZXdUEwVVhybllEdDdyeWNUVmVuUFZCMnVVcmVvbXp3dWRLRXlHODd5OWNRWEQydzVuM2JKZjcyRkIKZndnVHFWRzZWYmpLcXgxUjVBOXdyQ0RzY0JHaDF6bFd3RllqbzJJZjlRMlF2M2p0VmRDRlNYYWwxa1lqMkoxYVI1TVlaREFyN3VUTgp6THBNMjYzbXZtejc0N1JLL3NDdG1aUFgyazM4M1pSTGFhNExrR3F6N0E5MERzMjVoTlV5SGMvTTZWblZ6eTUvYkl2czJEcmhvdXlkCjdORzh3QUdibFZWaTVRSjBsNE9JRmNKdjR5emY1aXdNR1ZNSzIvVXNlNDNzQjNqV09SaXZuSVU3cjdLU3VWV0FXd1ZoMzlqc3RrVzIKMWlxYm42emtUVGFmd3lhN2dFZ1NlaGwyQUhtNVRaaURNUDREOXpYWmZUWVJla1M3a00vQ0I0S0lNYktIYkZ1MDdVaUlKVmZkUjRUcgpIQ0prRzlHWTBKc2l6SUVnMWF1SUc4STE1clRZWlVKYzVJME9zdWZCOXNtYnJWVkVCOWxFNndLSjZMUS9UbllXTEE3c3JYTGZQTXY5ClgrMkllRi9zeFBLZWVVbWNScGcxVVhoY1FKZmI1K2ZleDZYR1hrZjJlT1FvNlkwNHdXNmxWemxSUmxpMHYwTnJwcUJybDdYZnl3bDYKbVQxUXIrV1AzTm81ZWJIZFhBdUg2MjgrbWJVRlNJK3laVUx3a0wxZkYya2paaGtsR1Z4NThxdFFaYTdJc0ZYTVlQQVNVVlJySXlpUApFc2xZNXNCUVMzcHhGY21vdCtNRXU1dGU1c1J5QlFYODBOc1JrVG5MOFBlN0dVRXY4MmRxdGZ5cFd6c243OVo2VDNVcjl0NG5yOVVnClV5VkQzc1dVRWE3SURvU09nRTEzbGJFUmVUTUlLeGZobFk4V1NzUktGVFlqUTRTbHUyRmg2SHlRU1FaR0s0dzNZNWFMNUhzVnNaNWsKK3ErekxJeFE0VUplWXlPd0l5RHJ6MnV2Skt1R2ZEc2w1L2RHRUkxbDRPNUdGT0ZsWFdYMUJ3aVc1T2FMWFNiU1VDM1lGSVR0T25zUAowQnVLek5sQVhzUFdSWW9xM0hXeUNyU2RFbVg2TG41bG80cEVEQ01JZDUwTjR3S1dDbmZJQWExdklsWjJDcStVSFhhck12eTluanhqCnljdkNMWS9xeTBBUmpXRUwyYTUwS2htSWFGL29yTVRueDVyTkFUckJDaTgrbmovb0lQRktXWEdKYzFqMnlCWHlqUT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJak8xVldyRGJ5R3ljWlorUVVmVjlOSlRlUTNHV01STEd5dWxIaFV3K3lBVTFzRjdCcXA2dEorYXRiNXdjZll4am1JRytBcGg0aGxKUQpPQUJsa1hVZFpIdEcyQnk0Y0oyRExSLzVzS3p5Z0tLOUpqQi8yYVNrdTRUamI3UGUvM1NHbm16VDBCMDRTUU51VTB5NjZWU0loL0xXCkt6aFlVVjVBMWgyRVhTTUhTNmY0QkZuQTRZZDZVVjUvRFVOVGpXQjMxQXNiVlRvaUNUOFltaElwZEpWbE05elNLSHBsZTdSV3J6MTkKYSt2MExiMFhSRFBWM3NHTW5uTlVLUjFqV3pPWWlGTkZEeGJCZXdaRnhuL0xPMHBSTFV2SG8xR3hzbW8rREczSmVnZ1lrWDVQbytpVgo2U29LS3gvcnlTNEwrTlhRVnFQczd0bW83ZGxhVyszNVQ5K3o5WUNzRXZhTktMTFVURi90aUVEVVo2eXdwTDI4VkZYQ2crZ0dDYlBRCkNjNk1rSFdtMTFxckRtdHJweEhzYnM5dHVpa3h5UlNCbU52YWlmWkM3VzVHMFBYdHo5UnErVk43TzZmdjlyaTA5aW5tSnVpSXM1QkgKK3hMWUd4UXROeTlCSGNpQVdMcDVLU3dpZ1ltV3RUTXZRU2lWdlc5cjVpVlZHSVFMdUhrSkl1bzhMOHZPdklTMk5naHNibDRDcitUZAozTHdVYUw0UVBqR2FsOGd0d2ZQY3ZDUnZmZ1h6ZFRNdmdSRGozcm9VNHFKU25GbVh3RjFsZXcvTnVrVFdKMHJIenJwRXZpbkNZN011ClljT1FUbHVhZGFuVjZOWWxzTXhscWYycFF4UlJhS3RyTXkrRktITi8yeG1YUUNwVk9MUWJsNW9rNE9ZbHJMQ2E2cll6TDRIeDVpUjgKdXBtWFpCRnRFVlkwc3k1aFVjbnVzVE11eWRMTE0zck9iRXV5L0dYZVJqY3R5Y2UwMENqWVRVdmdCd2tIcEpobFNacElhZDNjc0NSOApXd2FxN094S0ltWXpNNTZibFRaS3lLVlpsV1Jud0p3ZGJVcmtmVnNKemFhRXJvTVE2U1lsdWZjVlhBQTdrMUtRdTNKSnVVa3B5SFROCkFDSzc5aVhjbHJOMk5Da0ZLSytsVzVTd2ZjNTFYWnBGS2RTb3MzaTBLR0dub2xqckZpVzVyMnpLOHNodVVqcGJXQ2Q3RitOdHdySXoKS1RXaVc0TXdIV29XR2RqTVJTRXk5V0FlVFVyWXJTS0VPNjhUWUxTRXVjMGJjY0pvNU9sRU13VzFadHhZMU80MW1wVGFBL1ZhL2g3ZQp6dW1MamJ4YTVLRmxaMUxxUkRNRmdTK21MVGRia2NpY0NKdmFkaFlsY0ZTRSt3eTFacjFwYjhZSmc0Mm5FODBTMU5zeFcxRy8yMkJSCmFvL1VLdmt6dDJaTzN1eHYzYUQwOGRxOUxQQll5WVhNT1BkcXBNcFNwb0d1dVJGazR3YW9WQWhCcHd2WVVNNW1PWVpLc1VScTVtbWIKNFQyUWpoWkpFWmZsWk9aSmJzVlNRN1lOZHhDWS9SL0duU3lNcEpueFJjWGdXaFIySWs4ZFF5T29CUjRDZXVtVllGa3ZJc0xYYW40RgpKMnlidHQvczd5QmlOY3dySGxJMk0rRTRHMVVFQ2lNd3hzWjFJT2pMVmRFMnVJUzlXdXU3WUNicTg5NDhNUTZVV2UyYjJBUkVDRkk3ClZLY0tVeFFaZmxFckxqMEhNWnB6QUh4eHphRlR0T2ZnaEVqcldDK3FwMkJveXlsK1R6ZGJHN1dZUzY2MUJkMkpvOWZ1NlJTOTBwK3QKMWV0djVXMmR2ZWNQSXVvMEl6L2szSFhkbHIwdkRTb0tPWGR6cHFHZWFQT2xlOU1nbSthOHVsL00zR215VTRzSWlDdmRueWJhdmV6RAo5TERaU3NDMkl2SjkzbnZVS09NbDNxRzQwTG5xM0cwK05XZ09JaGI1bWpHbkdsVGN0V0FTdVZjTjNJM1AxdHhxMkpPNmhjdjlhdGk2CkFxWjA4NnlKdkNDRG4zSjNyY0VLSUpQZGg5QThaOURHUkJ3czNia202MEJ1empYb2RXQkJXVXk0Ynl1enZZTjcyS2d5eWExR0YxdFMKMTg3T3gwYkpNeSt4T2RuZzJscmt6czNMRmloNkxIc3ZHNVZycUNITnl3YlJVM2FqT0xqWkZuU0lTUUhkenliN21MNlJPOW9DOWxFWgpyZVpxbzdraEIzZlFtYThOTDY0K0ZYZTJRVDNmSXVhM3U5dlFnZlBpN00vOWJWUnZOcnlqTzl6aW5DQmVidDNqSmt4VUpCL2JrSnJMCkxkSkZVa1AzdWZGS3ZHOXp1c0d5Mm1hUE85M1FYQzF4N1Y0MzJDbXBwRFMvbTJ4dElxaVpnYWM1M21LRVJpZzdaUE84UlhER1FLZWEKODdVdzY5emMrZDVnRXFLWTZjNDNLSmVMOVBmaGZHRSs0bjdEOTF4V3IvYlVLaHR6M0xvRERvWU12a3h6aXpYS3pnazMxRE1IMjlCVwpvOWc5ZDQ0NE1JS2E2ZnkxdHFESTBzRGI3dGtvTzEvY1VLODlmMnZyOUQzUDNIRlJ1aXBMcCszOWNUREFjTzQxNTFjTXN0R1cwRjFrClR0ZzU1SG90MjMrR2hockZicmh6eVdHRU00VGszaFRVa2hDSEd4cGg1NVBydGRxVHQ0Wk8zL0QvdDBKVVNFSE5sU0hCS0dqVEdic2gKOVRwOExkb2hkdFlaUmpxbzM5S24wR1JwYnlaRnVCOHBybWlxZzIxRnZBNGxFV0hvQzJ3dXdpbDBMc3F0MU9EbkZOV1lrbnIwZWoyNAozQ2pHZzZQa0RRelJlRmJJWUwxK3BXZzFkcVZzU0x5blhEa25tRzFnSk1WK2RQYWFKeHBRZ2o0RkcxbWUrM1k4VUlOdU5tZ0hGbWxZClliZEE1ZzRmQTh5VVRsSE5SQlpQbXRlaG5uQ2VDald2TjlVcGMyYzBuU3F2b050M2Eyc1JkaERETXR6VEtjOXRKUGxvdlpvL2ZXdnEKN0MwZmwyMCtoNThYL2h2T2daMmpGM1pjSFYvMzlNS01QOE9EMDF5OVFRUWgyQXIydmw1YWlubWx1M0hCTkhTV05Vckt3NXhxMU1YbgpsTHQ3WTNiTzZPN2VSdG01ZTNzOTkrTkdyb0EwVWxMcGs2cFRNWlI1ZFBCaUY1dXpqZEcraHg3eCtVYUl3c2pwLzJwUGhROGdydDNyCjIzWk1kOFkyd3M3ejI2dTVWN2MzMVNsMnk1MzNseHNyRmZqV0Z1UmpXdGI4bGs3WU9ZQ0hhdTNwVzFPbmIva0QrSURCcjRRdjFMMlcKMktpdUpUWnJvR3VKbUJZMHFveGFJcmlIaVBxeGFZbFFxRUlWSnVoYUlpd090QmVPV21LejQ3bVcyTXh4cmdEQ0RGM1dXSFphSW5TLwplVkFsWVNKYlpESzdrdWlmUngzUmFVMUZoSmw2aFgrdjZYNzArS1Z0M2V1SXNHS1ZCYy9XNnJXZWN4M3h2QzlQN1VpcldpeDJPbUtuCnVsNUhzd3htVmRQOThNZWFjdG5yaUxUNnBDVU85VUpWbTE5dnExRkdmVzJnbWw3WDIzTGRyOTl6MUJIN3MvVjY3YTFhVzZmdmVkbWgKL0NtbThDVWJMQVdHWnpoOVgrMnB4WlNlWlhFbjRhb2FCRmJWREptbFVkd2VUZ3ZuVUE4N09seHp2YTFHc1hzNjh6RHFabGFFMXBacwpSTUxGMXVHZVRuRmp1cmtxVzczMi9LMnQwL2Y4UWJ6TEVldVU3bG5aQ0NqZVUyb1h0V0VyaEJoRkZSeGlvaVc3ME15ZmtDb0pYTHdVCkd2NEIzZGdjMXlHVGc3NG9HTlJqVUxhcElvZDBzR2hKa1dDRkxVWjlXZHJtSE9RUTRYekVacXkyR01JZXNPQ2djbUVxUURMVkxvZkcKMkd4TndLbHNVUkU0OHJLSnV2NmFpbDVadG5XaGQ1V0dYdlNyZEpiTmFhajRDVzhsKzc3cTNmQjBWVkxnaUlZT3Z4VzFHMEtJRXYzUQp0RHRSNFdUVENIUitLNEIycHZ6SHpVOEJ1Q0ttdzl3T0tTeTRnaEhBVm1HdkZxV2JMNENkcDlMbHVHSVJWY1Y5cmh0VTJES3JmcXhhCnN6UnJHbXlBd2hjelR5YUhaNHNXY05qVFJPcE1ORHFrNUpwdnB1MS80V05WSGNsRk1RSVVDbFdIUEowREo1cGRYQlUvZ2l1V3NoaTgKdVZQZGJJQlpRME92OUVrQnNKN2FxYnJpamFKekpDa2VaNmdubTJLb2VXeXJVZXllZW1XakpvTy85cmFpYnBYRFBXUGZQSWRuYS9YYQo4N2UyVHQvekI1RUNZM1pBd0Z5NkZOaW84S3BUR1Y2Q3dlTjhDV0tZU01oWGN6UVhCeVpVWFdGbmhTMWxVUnk5eW9Telh3ZDFrZjVBClVkcWFOQVpoczFEN2dDaW81Z2JYUHFDR3VHNGNYVG5vRWlCOEw1aW92VjdaSENxNDZSMDRLeFc2c0kwU1lEbWhnaE5xWDhpc1ZIbTEKVVdUWk5BbXdVMHR5R1pPK00vaWRrVnNtY3RvckRyR09Jbkl4R0FxTWZmcXdxeitzL0tHM3JMTzlwbE9jTjVRZFZlMkYyQ0ZnTHd5MAp3SGxiMjZBOWdmdndZU0crNjJ0dU5paUFYT2lnekI0RElHd2orVDA1ditlbHFqMUlybEsrcXlKK3RQVUxOcHBpcG9tUUJrMi9VdGxJCkVjMGNGclE1V25lczJhMHIyYlhCMlBWUzJxd1dDQVR3OE5MRUhseHJCRHVsUVFES3JzNkQ4V0VYUXdOU2g2UTFyczNzYUZQMGZLNmYKc0JaTVNRRFo4REkwbmIzYVUyVnJxWXVhUE5hbDZsZ3RzRGxpYzlDdWQ0b3VCK25vQXQ3WjZ4WDFwUTV0TlVvYXpIV2RtbkhVVlRnTQpiY0VxQkl4OHY2ZFI5TXIyYksxZWUvN1cxdWw3Tm9lYlRGdDZ0ekRmdVZXOTJsTTNOV01DckVLM0dPd0htWjZNRldoSTRsMk1va2lICm9OaWRvWjZzMTVoM2JUV0szZE92TkdveEMxZHJDLzVTbURyN1BaMmlWL3F6OVhydCtWdGJwKy9aZWtBR1pzdllja1g1SXl6eDFZNksKcmJuUVhEKzd2UVFqeWIyd0VnSFJDTDdpWjdyL2U3VUZ5ZWJTMEZTaitDMzF5a2FGK0VPZm9iY0ZLRVVKL1k3MldSbUZQNWRYNmkvawo3Wnk5b3I4ODdLMlZxQytndXBNNVhBZnFBdWxYb1hvaVRLcWpnWkkxektLeHB0SXB5bnRnMG9DSjNLa0VkZkd4dksyQll2ZlVLeHMxCm1tRFgyNElmQUs2SGZrK2pQTGVudFdkcjlkcnpXMXZuNzlsNklNRzlHeFhQSklxTCtjOGFGZlkxQ09IZ2hETm1uaXczaW1vQS82WjUKQzUzeTNNUVN1dmlIZW9CQndEdlltbW9VdjZXTENFWTFxMFZ2UzFnbjBKVDlsa1pRRjRFOW1GZnFMK1R0bkwzaUQ2RFBOd3d6ZGdwNgp2SGFnYm14VkszT0pPcW9iVzlDYTRTaHlXRGRNRXFtNi9kMkIzUkQwMWF2Z3lHN2dzRFBzYkEzYUhVVVV5RnNOYlFnQUZZS2tDZG5JCnNkM29LSFZvT3JnYk5WTjJINDJCdTJrR1dkYWxvN3NwNUFCMjB1RGQ0S2RwTzRGMzQ4MElXR3I0YnRqRjdFYW5uWE82RHhrUUduOVEKLzlwQnZLSERKRlZkREZMTm5Sclkwb2E4YnBUbjN1M2c5ME05dzNBUGJUbkY3K2xxa0ZHcjltSnJTdTVFSDJpL3BWTmNFdFJINi9YYQpTM2xUcDI5NVdUMy9ISGh2ZXIyaW96MDdWVkVhRFZ5Tk9TV1RaK3NZN0VaUmM0VkJ0WWQ2aHVidVRUV0MzVkV2YkZUWnhWZkNhbHRUCnhlekEvWlpsTUJmM1IydjEydE8zdGs3ZnNuRXptRzdoN0lQYUxwekNzQmVOS2dKVW5nTWlBa1hJS21ycEMrWkRuR2NQL3dpMnNjSm0KVzVaMUhlcWwyWUNhcmFWRzhUczZVMUlxVEd4QWVmVzJNS0dXYmJ5blUxU3MweWRydGRxenQ1Yk8zdkVITVUwMFdESFdFS0hVSS9TZApzaGhOaG81OXgwTEppVjR1QTc5RHgra2hrSTUrcHljUExLREIzeUhuYkNYR2puOXZGQlZ2RkFEZnF6bTJIY0syMmNDZHNvVlIzekVxCmVTbms0UWFDcDlDbzZvaWg0TUZDbTJ6ZFlQQndscXNLNGZCMjlENGx5RTVaWVdEd0t4dFZwSms1MHFkaE1IamdlK2ltYnpENFJsSHgKeDJEd3ZaN0QyMk14cEVHbnVObkJCU2VqaGl1Q2doMEZIK25tQVVUQVVmQkE1cXp0WVIwRkR6ZUUyc2tjQlEvM1FpcHI3aWg0NkJKZAorWEFVUE56c2hFODBGRHgxamhSVHg4R2o5YVo4TkJ3OFVBZTB0emdNSGlOQXZ0cHc4TmhJa0RqSEJDUUR3a01SWCtzQWhNZEd4V2M0Cm43SW5kbUJIaVdNUUE0SXBYdTJwb29MaDZPS0dPT2M3YndNVzNnaytTWWhmNzdVTTRqNDAxQ2gyUTcyd1VWMnhhMDBCT0JWSDlIMmoKNkpYK1lMMWVlL2pXMXVsTE5rbmZJZUtBZVMzQkF4MGR2dDZvRGVLTzJVOW55VURKUThoSHA4SndCY2RmYnd1Q05tRS83WjVHMFNzTgp2ajdVTTRqNzBGYWo3TzdacU8zWldsdnQrVS9mcy9XQXc4VXhkOHJpMXV0T0ZSWkdJSXdEejBXQXZab0pyM1o4ZXFNNGF5S012ZGR6CnBIdHZxMVBzbnMrbkFSRlAzWVNHbE43V2JHL1c3MmtVWGUzdDJWcTk5dnplMXRsN1BpN3hmZzVjL0E0czVzRDRoaFZyeVBpR0ZXdlEKK0IxV3JHSGpHMWFzZ2VNYlZxejV3M1pZc1FhUGIxaXhobzl2V0xFR2tOOWh4UnBDdm1IRkdrUytZY1VjSTcrRGlqV1FmSU9LTlpoOApnNG8xLzlvT0t0Wmc4QTBxMXBEeURTclc2NHhRc2VhZWE2L1E0UElOSzlidzhnTlNyQUhtRzFLc0krWWRLOVlnOHlOV3JFSG1HMWJNCklmTU5LdFl3OHlOU3JJSG1IU2ptcVBtR0UzUGMvQTRuNXNENUJoTno1SHhEaVRsMmZnY1NjL0I4dzRnNWVyNUJ4QT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJREQ2L0E0ZzEvSHdEaURtQXZ1SERHb0oreEljMUJIM0RoelVJZlhkak80aCtodzl6RkgyRGh6VVlmWU9ITlJ6OURoN1dnUFFOSHRhUQo5QTBmZHI0V1QzMmdCam5mNGNNR3FtRzZHbmk5NGI0YXhuMkhEMnRRK0Y3UDBmSzlyVTRac0ZvRDFUQmRyYTJHKzJyMzNPSEQyck1OCjlkcnplMXRuN3preWYzcVNkdml3Z1dxd0xvZXlPL0NyNGQxSGVGaER4ZmRhaHBzZjJtbVVBYTAxVUEzVjFac3k0RmUvNFFBUGEwL1YKS3JYbmJ1MmN2dDhsOWJKN0VtRnVFeFpoOXA1R2hTV2hxSlNWeVZBS29qZk0rbElEVjZOUlZQMTNMdC9yQ1pkS1N4amJhaFM3WnpNYwpLRlZXRkZqNTBKWnQrY005QnlGZ2VEYXYxNS9mMnpwN3o3WWVQa1hCUGtuWlJLMHVMV3FjS1ZqeHIvYlVvRkUyc01VVUlDWXhXSE5TCllaZTdmYU80RWNhVXFWWXZHTkNsTjlVb2Rzdm5ackF6YXRKZzFhR3RqTDA5ai9jMGlsN3BqOWFxdGFkdlRaMitaZS9MajljdjRRbWMKaStvY0lqT2FOTnFwc0cweGVRV1E1dGloQVRDbjRKOW5VeVdkb3BxWEorcG85UmhTbDllaHJVNnhleXBIZCtvMksvUzN0eVdVc29IUgp0SHM2UmUvcHo5YnIrZlAzdGs3ZnN6R2twWnFrZ1kwSEMrWFZub3JlTmZUWmxyT2xEZ0dDT2VnNVNGdW42SHNBRDFQaldFOTJHaHBNCmUxdU5ZdmYwUGExUjYwb0luN2NGQzFvZDdxaWY5U3AvTHE4enZJKzFjdnFHbjJVUmh0TkZLQktZK3RDU2dvdGU3YWtBUlVIZGh0MlUKbnRNbFdPS0poSEF3V0NxZDB0YlNHdU5ZVHg0Z09pQkQyMm9VdTZlYmZScFZrMlMxcGhiR3Z3eDNWSUl2ZTNzd3J6VzhrYlp6K29xOQpJejlCZ0QvaFpxcStNUXJUUWhkZjdhbUFuQ1dOYjlaWWRCbldBbTgrbFhNSzRFNVJaVzFXQ0VhclZoMy8ycHJxRkx1bE8zK05LbnBWCm9KempUY0hNYWlLQTNkRW96MDNGdFNkcjlkclR0NlpPMy9JSG1aU3drTUJQTEtJL3NqS2FZOG1KaSs1UzhQSFVMWVVEbElpcU9oTTUKclgzV2R4SlpyOGo5V3AxVlhUaTlFU2ZZclZ3NVY2SXM1SVZPY0crbWFMaEV2MWNaSXJYYkF4VVBxdkJIdG5iT1hxeTdVcVBxd0JzQwpXdHlQMklqU1cvT3F6czhVNVRFMlROaWtEbFdxc1U1UXhycXBBdHRxQVk1UVZRUFFkaHJCN3FhWE9SR1RBeXlwdFlQMXMyM0QzWXpnCnJsZDlwbGJMbjlyYk9YMjNIMkw1Y1p1RnlBSjFnMTZqVjNzcTVMdlZRbVVpSEVGUVZPYW8wb1JtUm5PSzg3RTFwVFRXdzl0dmVXeXIKVWV5ZXpzZU1XaFRTUGJSVlRhem85Nnc5c2Nid2JLMWVlLzdXMXVsN2ZnNXg0cVF2WTFZak5PVnRHRWRmN2Fnd3RzQWpEQVZ0aWJPYQp6U2hmUnpldkdFRUZUcmpRbG0yb05hdTNiR2pJS1g1RHZiQlJJOS9rMEp1aUhTZlY0WTVPMFN2OXdYcTk5a3F0cmRPWC9DRmtYRERPCjFSTEdCTWVJZEdJMFVBT2N0VVFMdG5nMm9GRFcxQW1xd3FVclpPa2ZxMkdOTWF0SGE2cFI3STZ1L0JrVnJoRmlIRnRiU0Y0YTZuQkwKSStpRjdjbGFOWC80MXRMSkszNytDVWtiekd6eDFMSkFISVBjcURBMlpaVzNwQTIxQjJyd0hqeVdXMW83UmQrSytYTzNzZDVNODhYUQpsQlBzam43ZDdCTnlKZ3JVR3hLS2FORExjRU9uZVAvcmcvVjY3ZUZiVzZjditYbTJWaUI3a29hK01pengxWTVZUFNuQmF1WkR4dm9zCmFzOUZzdjVPVWVGaThVeDhyWjVJV1VncU5MVFZLSFpMdDhNb1ZmcU11ZFI2VzNIV3dKOStUNmM4dDRmVlordjE3UEY3VXljdjZWMzMKMmNLNkhnL1grbHcrUTBBamsxbDhHNW9ad0s4RnE4N0J6UEtpY3dIT3g3SE1BR1Zsc0xvUnlsd1JlMUZ6UnpJWEdyaFNCeklYakViYQp3NWhsN29zUUVEdUtHZWtiS3h3TURtSmVrWU9CcU9ZQnc0eXdyUlhENHhCbUdFcm5VanVDR1U2SVV0SWV3QXl6OCt6SUp1YmpKVVF4CmRmaHlKZ0I5RDE2V204MGNhY2N1TXp3eXJoMjd2QUl3UU4yM1k1Y0xBVnhMaHk2WFRkWXRzY3lHWEthSVRPUGdBRnlHQ1hjcnk5cVIKeTRHUVF6cFV6WWxJcE15NmJYdnNNdEF5RWJab2h5NURGbHRTQnk2ZmpmYmU0bGhoZEFZYkdtSExuV2dXYk9SZDVDZzZHQmtoM2FtRQpQV2E1d0Erd2JwMVk1TmtxRkZadnB4TUc4SEFuR3NhNHQyTXc1SDYzQWEzY244bHJ0YWUyZHM3ZTdYSC95aWVoT2VJZXBReUNBNVFoCnpqZHdjczA3V0hKaHJFaHFxR1RoejhpQzB6REp6Q01UOTRoaytEK0M1ZGtqSUJtaWN3Y1pZMmFqaVJHS0xPdDNnOTI3RVJOU3hBMzQKWWdRZG5XQ1EwMGlaTy9CNDNpT081dzQxQmc2NFlzY3lwSEdFL25HQ000WUMzVEhHMFI3RGtjTkltclN1ZTN6eHdpeDFuWWFFNmRHdwpwUVFYTDliSUNDMDJkQU0vWiszVEJpa0daSUJaT3djM09lWmZ5VXZIRTFkN0VrY1RZeDdOS2V6QnhLWGF3allzTWZwbFJCSXozK3k2Cnh4RUxDOGtobEE0amhqRjRYVHVJdUJZYnYrSHhBZ1BiNGJweUNERm5uS09IZDlOdnY3YkJjaFp6ZmpYY2NDY2ExSmM1aG9BUmNqUXcKbVBFcFpoaHpjNmtEc1FBSEgwSnZwaE1HOEc0bkdzYTN0Mk13NEhhekFTemNuOGlJL1ptdG1iTTM4eGVIQlMzbnZBY0tkNkpqZTJtWgpIdEMvQU9LWEU0eXdDSnNsYkNORVdIYlJkV3lsRVhZQVlTYzZwdGZiYWJCZnU5a09IR3dQNUxUK3hOYksyWHY1Q3lkRy9BNGczVmNqCjBiRzhXRnRrR3c3M1RjamFXOVk5S2hoV3IxQ0hTdGloNktiMFpwd3dJblE3MFlDODNvd2hmZHV0Qmpod2V4NnYwOTdDMnpoOUxYOWYKNUdJSzg3YUhBbmVpb1hmUmoyR0UvV2JHSGc2SVgyN3h3UHBUWC9SYWNFMVNxL1IyR21FQTVIYWk0WFo3T3didDdYY2JFTUQ5bWJ4VwplMnB2NS9UZC9LVmg1c25NOXptZ2Z4dlJFYnV5T0xiRVBEWUc2b1hwcWRCelBXQi9oWmt0c1F4RXVEZDVpbmhyeHdrakVMY1REYS9iCjJqRkViN3ZaZ1BwdFQrUjEybnQ0STZjdmRza1pCcWQzWk9ENUNCZnNWQWY1SWE0MExCNGFEQ0NnN0w0NHIydVBGNFRmT1pUWWlSWHAKbGJjQmQ5Z0lJM1N2RVIzaDE5cHhFR0M3MjRnVTdBL2wxUDdnM3RMNUMzNTJyZUtqazBVODhnVEw0V2UvZVAzdXdpRWorUFhzZHk4Zgo5RUYrK2ViNVYvL3o0Yy9hZHA0UFAvdjF3N05MUjVQY3ZuajExWmNQYjU4L3ZINDMxSC9zSGwrK2ZmamppNGMvZmZYck4zLzYxbDR2Cndac2t1dTFqTitDWkovLzk0Y1h2Ly9EdTBRN3hxbSsrK1VvNjh2N3RtOWZmVy9lWEQvLys3c21WOFpMU0t5OGV2djJBZDd4NTg5TGYKVWNPNzF2ZS80Nys4K1ByZEh5Nk81WjJla1hQMyttdTc3dUtaT2YvanhSOGZmanJwTCtwWHE4N1BsVEhmVURLMnFxanBXRU9hTHA2WApvd2pwRHpzMngyN2xEVGVNMHU1MlBQZW1VZHRqL2JKZmY0bTJ1L292Y1dvT1RjbXlJOHc0ZGpndU9HVUtta1VOY2RZemlhT2ZTYnpzCmtxbGt6ZFdMVklDTFp3RUhFZUlsc25jamxTVUlBUUVKY0tHck9nNEwvMXlWNEJpa2hmaHMwR0tsSlhXMnRpdHlWS2s5Q2tkYmdkZEIKcGJtWjFNQWVxZHdGUUJJWHVoY1RzamdWWkdHQVVpL2Jjb0g1SElMdzRyWXFwTUFBbEF6RXpZNUFJQ1JMQ01haGhZQWRUd2hFQ3JYTApBSHhFcHJHY0ZiMVVlQUJLTW0wUFFnQ1F5U1NrMk41TTA3d25XSzREUmFRUTRERkJSbFB1blRRZndpa2dleXBmVFBiakxVY2lsVGErClBXQ1kwSjQycGtaTlNtREdOeWhmaXdNZ1IrcXlCcjB3TFp0U01zY2pCOHVSTmRQZzFxL01sWHRTbE02aER1ckNPK3BsQzhqU2pOSm8KZlZsdDVKQWZIRkVIT1BNcGE1Z3dqVjNJTmJGcURpOHEvOGh4c2phaEUvRVFWQVNRMVduVkJLR3NGdVlrMG1wV1ZQVUt4QzhzQ3lVNQprSDlkN2ZRSmhycXV3YXlyVEdFd3cvR21ZZGg2bGdid0RzSFRicTRPZ0E2dW5hL29DcWJXZzN1bExrWlpsQUl2Uzd0eW9TMDA0RkN4CnhZelB6QlNNL0ZrODFCNzNaR1FXS05HTkhaQ1VWdGVKbzQwMkE5QkpLQ3JMemV5S3dQTVhITThUVEVhUVd5NDBCcFZWVlM1MHh4S3AKeUsyVy8ydzJXeGpuRGhDTUplbjRwbG8xbzF4ZE1LUXp6RVVLSzAzSmp2TGdZS3N4RWI2NVJlT25Tb1FVeE1Tc20wbzdoY3V5MnRJaApaZldIQlZUT3JzdXNvMWthMFhyT0NtNWxQQVVvbEVuMEtoaUNZRUxDaUZkRE9Hb3l3aG51T0xpenEybTBHeXpwVXZmR0wxeEVLOTJZCktGNFJlbWxHbnBJTmpuVUZqeEUxaUNqL1pmV0FOc2o5U0hFQ3d4YVJkck9HMUFCd1hLTTZKWm44aExoQ2d4V1F5T1M1Z0JSR2JSdlQKa29BNGpkaWJvZUx4OCtJdWF2aUFnV09Vc1Nyb1NuajRrSWR1WTlwVVRWT29pVHZ4aFkwZHN3MGtwQkNHUGNwRGxMQzRLck56V0xCSwpLcFZLc1Bja2lVaGJCUU5mWkVqUXFtSVpMRExNSXh5Z3BraUhnckNHSHM1RUhBS0lTTElubnd1ODUyaUd3RU1RbHFSWmZaMVRhSEJNCkptZE9jektJUGhLelZXWVZEblFKVjdQa2dRUG9teVZDRUtEK3pveFhxMW9IVm9scUFMUWxiVkN2UXpJWEMybEFrWlpaRnhrSU5HTEQKdkxJQmpENzdVVlpDV0wwN1pvVFV5N2NnSnJ0TWRJRmx1S3hxaGc1ditMbDF2bXpWdEFnSERDUkdkczB5VVdEZUsxa0JDclRzbDAyVgpQWDJ6b0hjcmlGaUpodXFFcmdCblJad1YwWmxnZlFNY2YvYjhqQ0RTbWdHZ0g4NGdtMjN2RW9Md1REWDVzQjBRaHF1WXZYS0ZsMVF0ClFGUkRVQ2RWaS9xck9HNEx1NDIvR0x6TWtYMnJRTmd0Z2FGdVBHbGkwZkJsT3VIaGNGa2RoRlJ3N2dOdUJUZ09RL0ZocXlzOENhdFoKaUFQU0M4SlEyeGdYaUZIbTRySnFYOU9PSFBWNE9OSFJpMEduTnhKd2NHWmo2d1ZyRVVUYVZ0ZFY4MG5pc2hLTXdMdXRnRXZIeGw4MwpwTENVM3l1Vk9SaXB6Wklyb29vNllXS0JwU3JUa0VZR2doRkdzdUNLclhkVHY2MXM5eHpZVEIvQ3V1cThLZ3c2eXJZckY1czE0WXBKCmgyREh0ZVdoVytZaTAzTUxIRUx1MHJyL2J6QVlaUjBpeS9QRzhFV01ZU0U4QjViN2xXTVdRdW9DRWF6dm9JR0Q4Zk9zSXkyclQwRlEKekdzaGhGUWNrdDJhUWk3MHF2anBLdXVObVVyMWtUZlIrZkFLb3RzdCtsN1Nvem8vbUNtNDBMcTNJR0VpWEhMWUVDRENWYVo4WHRlVwpBMTYyTFRoYVlSU2UxYVBCWEZFRjdHSFZKQzA3NlhCdjZxTUVBTVJUZ0tYYmo0OVlORFl2RW1uS25UMXVBQTBIWktQWHdHbHVHWkg1Cm9HT1RKVFFrV0hnbHVEWUpnTVVqYVJLRkpSQVlFeHZBbFQxVUFpbytUWExZREt0NktXWWVMb1VVNWJySmg1bmF1QktlbXpDZnNNQmEKTGFUY1o1TE5ESjViTlVFZ2pLNUpYanpZbHNVMWcyaXRUUmMzd2QwTWg4VldZNEg5QkxkRktFMk82Vjh0a3hBeXFabllNVmZHUHJYUApnY0Y3aTVxblhGclJTRkhJUlVWcmFXd3F6MmhSdVNjdWpHMFJucHNkZExocUFpZ0UvWWFzdWhORlJ6cXY0dkFaWndPRTNDUlZTRm9MCnBNdW81ajZjTTR2TS95SzRhbFRhd25QL3pLeWdqNWhvZ29hbExVZXpWaUVWS2dpMFdVQk13bGpncXRsVDB5UEFEU2RVTWRlTkdibDQKWHVFQ3pxblpGTWo4MHFMN29MNVhWYjh5WmpuTldSbHhYWW5aNFkyelJIV2VZaDNYMGlXM2pkdXNlbVR3RVNPQlBLRTBsNjRRZXlzMwpTM29yL0NJKzlycjVlMFFlZW9iUGVWVmNRMFpPTFJEbUpuc1huVkxJeDB1K2duRVNNUVpwK210U3ZxSkhCVmExVHQrWXhCN1FaNWxLCmtPSlhaMGhQMENMSnhCYUQ3Qyt5V2tTRHM4dG1qZFNqWXBBTVRJbUZpOUN3T0d0V1gxMzlRZTJnejkxZWdhZ0VFQXR0VDFWRGQwSEkKbVBZSlRrcnNscGl6S2JUTFpvQlRzZlhRYmdZQ1lPV0tWOWU0a0FCeHRjejZic3JHZ3ZYMnFqckVzbWlpWlRoVTY2cm52N0dMc1BpMgo1SHpNd1ByY0hDT2RRTVVlVWZSTnkxYVhjZnFnRVhndldjZ2JRazViTGNTWFluOGk5d0dEb0swUHZwbEJMT1FwUE1KSVpXaTRPTUFPCnNKMHYyYlk5NW9TS1BPMGl1V1FDWW9GUEdjU0VaR3VJZ2VlYVFseGtVQUpqN3hHSFZ1YlNMbU5LdkdXeGtRVUIxZz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJSS9aTDBDUjNqRGNGb1hvd1FWQ1pLek4zY3FZQmxUb0ZHUVJkM0ZGUHZnRXZoaExHWGhUWkVaN0ZqRk9HWm0yNkFNbTlVTnRWbTU5TQpQdDNRRzF1TWxmY0NqVXNST1JXd1BFQ29ub2t5ckhtL2ZZT0ljUVlNZUU3WmFnVVNSSWpRM0d3SURNYm42cjJJL0FMZ1o1aTUwQ2d4CnJzd2dMWE9hOGtzbklDallkOVJHcktiK01TNEFtK1ZNK1JkQld5cUI2V2Vkd0NZcXRUcW1vbENKWnk0eUovRG9Fdy8vTWlMc0VWQkkKTkZ1cE5MMUFyV01DZVp1S0N5QldwUjlic2lFMWh4RFZheWdxWVZseFVDM0VIR0JMSVRhRHdhQS9NQmp1VVpkbkJFMGtaOVhxOUlqWgpZajZZdWRxeE9BVWRWOXBWaEFtZ3FaeFVYU051QW9NUnF4RVFOdzM1cmpFcjVHaUFNQXVuN0x3YXdoWkhDU1RxUlNvSmtETXdwV1N5CldSWEJ1bVprdmI2YWJWWWg3MnMwaVJ6TGlWeUlsaGUvRjlZWTVBRllYbGEzUkZma1NDNG1nczZXa0JLWGJRNjhuemROWEFoaXBHSzYKRWIrRjlPTWJkRzljQlFzTXdzLzZhZ25ndGppMDFLM2kwSldnVFNKbjM2cjRMazFzdG5ZNUhrTk5TRklzTHBjRmxRcHhIRTNRcEtYYwpiSG5hVURJdWpEZzNhS3pZYklzbHVTTjZPTklVcFI3eEJkQU9rVm0yWlppTkdrT0VPSExXNFZnQUNMMmdWM0VSeEdHaytVN05ONTRVClRFQXBLbW5lTHoweU9xaWV4MG5PZk9LQnpFeFo4T3laQ01BanpGdkc5TzhJbWl1YTlhYXN1clBQalhzNEVkbGc2NktJLzFVVHB0dVEKTVJ5VG92b1ZqcXR2REorVENLR0lxMlZaMWJ5TnhUZ2xDSHFBbEdwVmZobWxmYzJkWWZsZ0dlcGZiTVBGM3Nma1RnV1NrMGNZVURLRApxVUoySnd0ZzVBR1ZjR3U2U0w0aStBOWhqMUQ5Zk92VWVBK2tmY3FLdEZGZEI5YkNUZkc4ekE3dkJGZHRhTG5zdFRZMWRjR1dvaDViCkl5REdLM3RZWHlQQ0pKbzFsYURzTUh4SW5Xa25JblJ6S1NOeGt5YUJTenJsTkdlN0IzU0ZsVllnaEpQektFL0MweXBQbHkvS0FaajYKczZxeXhEQjdIa3dRZzJLZWtCRlk4NmtqNHBEWitiT2RneEJydC9HQnV1YWdySDlGZjRHU0dZUWR3YkVRaDRSOG1Nd2tBTXJzUnhvdQo4RSt1eS81S1pyelhPMVM5TXVwSlRnZ0x0QVhDTy9CSUw3cXE3Q3dCUm90aDkxdXh4d0J6VEhRcldBNzJBYjVscWhhbmk0U1ZtNTQ0ClFPY2k0S0FsSVdtOGNJdEZVMWxYYllsM0JGT2gyNXh2d0JnT2c4ZVFzZ1E5OTRDSEl1SEN6WlBKQU9hQ0JVNXE1b0VKWEZuUmtvTW0KUFJkbFcycngzYlBmVWZHbXEvSjNWRXVjR1h4V0tGQUlNVTEyZWhQdEszcGxVS2xKeFlYTUNMcUVjRnV5NDhRVEJUSmtSWVY5eHR6eQpmeVl6aTJJOVlESUNSOHk4M1VoM2ptNUdWbFVhYTVGUDE4MmZpTFBUb3luQTloZkdzbTRhNlFJS2hWdUF3dFh5ek9UcmF3OTVVWE1xCnFNdHFvVEUwcGVJdDhxYXdjMEtLUUtHVzdsZFM2Z00xYjhndmlyWjRZQkl6Q0ZXTjR1UE1URHlDd1pQdDRRQ2pXVE9KeHh3dDFRNE4KM3B4anErWUYwc0FCSlBpTTdmelh0cEt3c2RCSUNHc1dQS1VCRTV6V0hNQUtvU0dGVmYwZ3o4MHNwc2Jhc0JydUI1b1JKVU9leWFmUgp4bnhXbVBCcTdOY3RtclNYWmk5V1VuQU5USFl4V3Q1SENxSlpWNExiajNSNEdZU0hidVZwa3BzeUM0TFlFSi9IblFkTFlZVWdvR2F1Cll1dUJ4d3hpR1NDUkdLTVlFTEZjR1NNY2JNV2owZGt0OXJCd01tYUduY0lnTmlna1NUZG0zWkZ4RENWRHUyYUc1dmVVaXlLQmE3MUkKT1hjek9ZcGJlc2xHNFJTR2xMNzU3Z1UvQ1RHNGNGVkE5NGw2Z2JvekNINkFrVlFHZDZWem40NXh2aWZlUGxmMVE2UjUxaXMxSC9ScwpFZzRNYXJTM1NnL1E2dGFzYkJYbmJtNDAxOEV1eUx4WUc3UFJHcUVtaG8xdnZwWm5TejZEb0JreVpiUkNDekJCWjVadGN0Rmc4N1ZOCkd6Z0YwRkpXNlFHcG9MZ1NObU13V01iVU16azJhN1ozUXdwb0pueVpaelVQWVQ0anBuSGpPWWNhU0VwbVR5U1pzemo0UWhpbEg1SHgKSzJzVXVaMGVSZTJMQkdSVVFZUitzY3d6SkJKM2dGMk5TWnV3NUMzK2ZsMDBsY3MybDZLRTBCZFR6WHBvZEt5enZoeWNGWnM1NXhqWQpnRFd6QWF4aEJoWXMxWFhORFBkUksyeWNkUVV5RGFqMUNHWmhTU3FINkpMUHFxUUJGTWk4WG9oSUxmb1p6ampHMU1OMXdwaGpQNWdLCldXZXBNU1owdzhxRVo0VFpBVHFjRnczRnA0a0JhUmFhV1RyaTNFTkNVK2VDOTRMRUNJNVF6VlRDWUppWktkZ0p1dE1oc3h6cU1GOFcKTytXYSt4a01uQ25idG9RRnpIdTUwd0tpTHhRUUVHZWVqRlBVRmtCME16OFdlRHJ3ZlV6OUlnb1loYWNNYUtML1RXWWpDTzFlUE4rQgpXWWg4ejRXcEI2dWVWbVJNdmtVejZXd01EeEk1QS9ZaWZCS0oxMC9ScVhyTVljSkprSmxWbUU4RWVTQUNSRlVRa0xkemcwSElNOUNSCldQVm9NOWdoMlF6Q2pYQW9PUUdSdUJVaXZkVWg1RGZEdDVHckpSWm02ZHJVMUVaemZxSTh3M3hBVzlJS0t2WlVOWDhqeWV2TXpNeVIKbS9oV1RRb2lSSGlqMHltN21RVEVpc1RNSUdZNFI3SmxLTjQyOVJZUkMwQm5hSEY5bGpTNCsrRkI1VjZCcHBtdWVtYWMya2JLdXRveAp2OElJL2MyQ0JaWWhXVUtraFErdVVtRjNZRG96N2dmTk1XN21pRElIR2tTNnlMQmlSSEJ4azBIZVhjbzJ6TGNFRlFQb2NUOStkcXZ0CktKM0lYQlB3U2dwdnJLeEdHQU44cjdCQWtzQXdrVUFvUVd6WDJlbWRzeHBwMlJLVFo0S1hzV3R3UjBaSGc5THVDT3VGWmpPQmZvYVYKdmJqQVFIeDUxTnphVEpXMVZiVkNxa1NYZFlyakphbkI2Q0ZTTVpxbVd6V0ZsQjBTQUVPcU0yVjR0UFVvY0lUSll2WEFaSWpnT3owRgpCZ3VJWnMyc0NTbGxoZmZ6OGJLZSs0aHpXS3VlbmFWcHYxblBLRVhUelVXRWZiUUw5UnlVZ0FRb21GNmdLT2dxS1pEdFhLeHZBais0Cjl1SUtyMldnaUE3ZkFpQVJNUWNnTU1RZ204aUdjNC9odlZnUndPazhPNmg0QnNPYmN2WkF2Q01QbUxPTHVCMkJrTmJVcmlLMEY4UmcKMndnTXMyZ2FXamsvMDAyMWRsV0ZxUWZnUTRlUkppZjFDV3E0dzZLeUZSMXdVanZ4R0dNVFEyaC9wZWtuV01UaEJ1NjN3cDVnc29XNgpyWXhBY1FENVQ4eHJxcldRdlFGOXNVTEsxZUFqQnZjai9mcnN4a3NRMGExNVZyQXJuRUdZaW5sV095M2NJMjVnODlQc1M5U3RFYUgrCk5PaVZxT1l6cTBTM0dseE5hTFRCQkpDSkRkb0hnSm0wK0RMN3JOcW9hWFpDVkN6MkN2dXNNbzZkZU9kMW1PY0dNTTFnRVMxT2dGcm4KUGRGb21QQ1dVSUI3c09nUUZGUGdyS2NPNndUdHdFUTdkcThFWVVmZUlnRmNEeE9URTNCMFc5NWFyeXNOTzNyUndDa0NTUUgyaVlxcwpwLzF4MlpxSEV6U3VidEN5T2NxWjBCUnVNNGJLZ0lBdXhqay84M0RaU2xWOE01c1Aya0ZjTmpZakluZVJ2MkhUeTdxaHVTN3FoUWVSCmJqYmtDZ3c4djdxc2tBMEw3Qmx3Y0ppcmdvWUFnSklnSVM5dUNnR2hiZ3pVS2ZRNEZRckF0TEtYNHNlcEZNcS9CejBpYzJVbDJveHoKTk1CeHNmTVFRU2d0Z2Q5bWJ0ZG8vc095cVdPTkcxTFFaeVFPQkpmTjN2bEZoWWtGY0I0SWdpMkR5YXFpSHQ2VVo5WnVDbjI1c1htNApZRElnQkZMdk5Xc3dRSXFLU0NOaFU0UDE3R0FIbU80aFZnTHZ0M3JVSVNBUnpEdFFOR2ROVXV0MDNQcEY5TXZDOGgxV0RTK2krNTFKCnZQU2pNR28yMm4xMnF5WVRTY21zUy9CSkUrbXp3UE5UdEU4NXl0QlQzZnNHNkF6U1E5RTl0Rm82R2pBcytvOFd2WnM4S1M3YjZPL3gKUjZSZ0E4OW1XdFc1UE5QS0xmMnRjQ0VMa3NRRWIyZHhnd2cyZ2ZTSmpBb0FBYUtvaHNJc1l6dVp5cUhlemR5WWNQSGxUYk4yMGVzego5K1UvR3dCbVZpdEh2dEtWeDM3RDZXK0VhU0VuTURkcEkraTZCNTlrRWtlcnRSWFZ3WkRES2xkTm9FbVZTWGFaa2p5b2tVSTNUS2ZxCkdlTm54TWtqdjFvRkQ5elV4OEF0MXAzUVc5S3NJTEJPWmp1NmsyWitaREtqcTJxemc5WVQ1WDduWnpBMzg2MW1ndmRVOHcwOGtKdUcKNUVhQXM2WDBJenVVdGhsUWtEcFE1Und1SmVpT1VQUkFTZ1dBNno2Q2ljMHNpNHI0aHBiSGhSNGRmb0dVdlp2R1E5RGE1OG9KMVF3egprT0d6bmtRQ1FZS1cyRVY5bExocWJrbEtrUU5uMDZZb3NEQXpHNjhpdStmbnhPUndNbnRyVDIzS1BRQkdGRFVxV040eDV2VW94VUJGCkdXZjZJWjR2dHplclNMR0pFS2pWY3FwU2g0SG1VSG5HQzRGbTdLRE5UNXhnSmhYVVRyb0I4cEFxb0tXaTZVdUVJa0UxNUJIcUxvSEMKOXFnbitITFdzQlk1SWV3akJDeEZneHZDWlQwbnZ4dmkxakxqTThpY296bWRSR2FqL2ZCTW9ybVpIazJ0TFdNYXFpWkt3RkhwczhhVAp0ampTTmNMSndUT2xrRFBCUXRGbE05N25TQ2dha2djWDMyeEhncE5JcitOcUdDWGE4UUpycmVDOHRNL1Y5dEcxUENKMEFJTmNGOHQ4CnpLWVRBNGMwYThKR1R5RVd1cW12UWRWK2VHY1g1cXd5SFJQUldKVFFreDI1dFl5R1Vod3FzNUMyQXFqQnBFdXpFc3lBYU9rSGw5RisKdUtpVkJpbUI0ZDlrMC9EWmd4QldKWkEza0ZDN0RaQmdNTFJOTUZiUTdIVTB6VUs4aHBjSmJoK1lwOXQ3bWN3Sk9TRkZtM3FLalNESQpBRE9CZkFsNnJyUENrWWo5Z3A5aGVPZnhZOFh5SlBESTVFMFhsRisxQXRVVHpTb1RtZTBOWjdwdUNvUWdBYndDUnNoNWRURjBNOXhECjBPVkExQnNNamN4RVVUVGRGblVvV1hmQjhRR3doOUUyU0tzbHN3QXVXZ3ZaekxkcVdTaVlNSFV3aUFLL1JkZExNcUVjK3RhcURodGQKQ0xObWN5SjJaZW5tSG1ZbjRacGNOTHRYMVJNN2RlR3pCdmhRNUVSZisyV0V6OHdHaXd4bVZFWDNMWXZkRFh3WWhPUWFGeTJDUERwRwp6WDlNdU16emUwSFE3QjF4b2ZCOTFYWUtzSjJDUXl2QkpyRHhRdEtrS29xd1NhSk9ZR1RpUTIvcXpPUldodWhpV00wd0pMQlRBUVBLCnpJTVJjRXZJSjBoblNWQlE2c1kyRU1uazBJOUVCZ0Y4dUhLR3lZNjhhZ2o5eWxSdnlPYmJRL1RwZjRocW1XQ1lQVStjVFlvSUpTRXgKcmJaMnRGOUZOekVHRml1YWFUY1pseG9Ndm9JRFkyQW5nU2RzZFZrS2x3VXlhd1VJSTgwbkRJdUlOaU40cDVobEQrdHh6aDExTjhOTQp4VVc2YXBZRldnMnh0TG1kTVN0Q1prUWNoWmwyR2JZemdLNW1WVlVJU2t6R1pFQ2dGNUlFOTB6aEZIakloUERZRWhCUVljZVR3Uk8rCkpsdUdKVU1HeW1IV2RjWVg0em5TOEYxbU5RTEJMMWF4Z3VEdGhyY2RmakVDeW9CVkMzNVVLb2haRVczcTBZUDNEQ1lwd2lJWHZZeG0KQ2RTQWdPeVhFUkVBWXJXazNCVG0xbVIrTVJBZzZSTTQ2VEpwUmhiQVRLNUxwQmloWS9BWE1TYzFVLzh0RGFIQVphN3ZWdFVwQXcyRgorb0NpNnhaRzNCUGdCSWdQdkMvQWUzZWNWcVRXc0FZREpPUHp4cytLZWxrdERuY05LcmZxUlVsZEpraEFIaFlGUFJGK1BGNG1mQ3BxCnV3M3l1REo0WDFURmpNZDJRVDlIUTNtVW9odHVKdGR5alNYb3ZmSmlBYjFBWmNKQUNLOGdnN2JYVE1WNnJicDhuOXRJYzVVQkVNeGcKLzlWMkpRQ0NpWFdEUUw0cVRxbzduUEdFVldHUnE5YWhWN0hCSkVFb0NsZk9jenZTYVRZVmZjWnkzNmpWVUVLam5ZMEtTOVUwRG5sVAoyNFFLamFwVHJXWmQxRlBqWU1OY0ZWeEpOQzRVUXpDSTFOd25XWkdyWUNQMG9PRVVKZHdkekFiVEJRUTZKRUJ3dSs4TVVLVThMMmcwCktNMW1aVWN6MVE1ald2MW1henRVYmxNUElUQmZ0TmE3alI5Mkp0ZURHVFlNRnp2ZVhUa2o1bVdnOXI0UjFLMnVESTQwYlZYY1REQ3IKOHRhZDFKRDJkTTY0M1h2Vy9HUU5JUnd0WG9OQnk5bWxscWl1eDlVUVp0anRaK0JUMXVyaUgxWlg1bHhZSGNjSElrTjVRT1ErRkZOTApCWUJRSVNVczJyRGJJSHBUT0hpQlFnQU1Ld2liNWltaUZqNEZvd21PdG9lblZVM2hhNXNoS2cvVGtWczVJU0xOVGdtcG9BTEJPWTNKClVXaURHd0pFTnA1cys4cW12WjhKZjI1WHV4QjI5Wk12bURGUFJ2Mm5oNS85NXQzYkY2OS9mL2pKOFhqOS9QbDNydz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJZnYzbTNUUFUzY1ZiMlVra2tCWUllb0JWRkZhTVYwYXRqTU1Jczh0UXhiTHVoRmxSZlJRUW1DNGFsbE1INzlCVVJyd0VxSFZSUVlJWQpWNDE1TVZ3K3BWVkd0NFFXenJBcXVnOVd4SVcyZHQ2VFVUQlFDVGN6OHFuUDBTZ3FUbmhpNGw1djArbk8zQitxTkxrakNzZVpGUmNDClZ5Z2U2b3dqMjZEYVJCYzVUbFlGcTFmRDQ2Ymh1bXVLcm00Rm5jdzhNSFpXVVl5cFRFZ0lSaUVPK2VUQ1dYZE5VSW1uSVNXdmFqVzIKSUltZ2dSdWcwQVRodXBxR00xVUZEK1BwS1h6Q0dZbFo1NThCTEFkRGNUbDNnYU8rRW8ra1dYNEpxWUZITE5zNEZzWjdsS3VtOHVyWgowSlZFNHZoQXdHRGpjN0JSWllRU3JscVczSzVLd0RreTlkNmlWeEVSQUoxK0NScmZRQTY3R1hwRzN3eWFYT0JKZzBYZkxLblJvN2pOCkdad0tIQmJiVllOeEVITTFjM0VTNk1wYTVEQlJ6WG9rSUpaanRmUWxUWXJFazRPb1V4dlltc0IyVmtyamlIeUVZUXMxZkhlanNzcTkKSVN2N0FpUU9DdVpxU1VIMHNFaDFaTkVaZStQYTYycEpYbmdjdEdYVDhCaHY5WWNHNXZsTFFLZjdWVXhVd3hRUm1MMVVjVFl5cG9WRwpBUUNqd0dIV2ViQjJKME1acjdPeFJvaDlNSUtnRmtlUi9vaUV6M1gydE1TZ3dWS0YvVzJlRnp1eE0zUDdoeVdOclVBU1hvTyttRjQxClcxOW4wMFdpaFNvV0lBTWhwRU9hWm1ZT1FJeXJPWGlBVjREd3lTMTRVNTZucHVwTndmaVJhRTdZRExlT3pzZXBHNGdQYVpXd3E2NkIKNlN6VWd3dUJCT2R6QU9UdmNremtzQXZEZ1pFOTgraU9XZ3FubWU2dHlCa1BPWmZ4WmY1aUFNbERuYTIrR2lHb2NWa1ZjMFh6UEpxTgpNZml4SFYrRlREbFlSVEJTY3c4RUFSQUJuSlNRWjIxSDB3aXRxZ2k0NTVBcDlwSDlpV1lLcE1TQTFGUm1sV3pnRXl4b0J5bldaN01SCndla21NaGJXaDd5NWVzbVdxbExDRE9nYXozRkJoRUJkMUJYTm15MUpaVWpLRWxpTndDWHprUllGbkpNQWl3ekVoSWF4V2VpcUpWSGgKUUt5MU1WRUJUZHBzZU5FMENUUXQ2R1ZaK1JyVGVLSzdnV1dEL1I2eVBGMDRUaERCa0NZWnZjeUp5WFQreFVJcmNEb0U0SStSR0d6RgpSYmY0RXNDa0tKUzFXbjcrZkNHNHRnNEVoSHU2U3VuRW10VmtIK2ttbUl1NjZ6SDdmVDdDSGJINXdiQUF3aU9lRmhZOFFyRFdXZk9pClFSUmtaQmQwQnh5NFNjM09XUSs4Y0VrSFFKY3huSENyaW1VMHI5R1ZWakxIcmNXUmNMYmpmSGEweFNxeUNEaldhOVMxUU13Z3hxeHgKSzZ6d2pUN2l4VmVWMm5CbjErY2hrbURoYmJScTM5aEFpd1FWV0FuR2pJelpGUFVpWFRGTVdhamU3NmJSZ01pejl1QVM1enNnTVhwbQpSS0ZLdW93bmluUnJ0N2pxU0tXb3Npa0Nxa2xBQWhxNHlNbTlHV0hFQ2t0Ykwram5va2V0WStMQlEwZlFsdXp6Q3Y4Q0VqMVZUWlRSCjlBVU1zd0lEWjZRaldUVVRNcVZQSE15UXNwNTB4VTBYUm1wSURNcXVOc1hjYk5WV05RQmQ2bzVHREF0Nk5qSGVWTStUYUZJUXJFb0kKQnlSVnA2TzZCK21maHA1REF1RjVjRkM3dnNiVzZxcjFvb0w3cW1xK3BQQVZrMFd5a05JQmREUnlNSW5acHNjTnAyQnlEUFlWUFpJdQpyN3FqTzRZak9kRElJQnJFblFDS3p1Zms0Q1ZHRFN2ODBJSGRQS2lJMHltbzQ0UUU5YjliaEF1dkk5QW5MRDNtbkZRT0QrelZ5NnlaCjdEY2U2QUNLOXVpc0hJK1Via1FyYW9RUGxCWTJUV1ZLVHNIOEs2b0tSUFhJV1F4RWJydXBScHJEeXNaM0FxYU51RHVBQXkwcFBUTWoKTzZHWnhHZ2M5MXF6UVJZQ0FYbkxTSUZlc05VZTFtalUxZUpWTWUwQVR3bDZXSUxLdG51NSszUEs5Z1RhODBDWnFwTlprNmtGRGZXQwpqTXM0ZHFDTUNUSkk1ZzNER1M4RXppMmFhWW5xbnNaaVlZMXB2QWlQaDZGMkE5Mnk2a25yM1BxVjBmdlpGYXNleUtLeGhKckdrSjZ1Cm1ldUdXUTJoZjJuK2c5UXUybGE2ZXZ5aW9zbi92R2tsekhUaE5FbVE5Nkx6STNxbXhhQ3dMOEFlNlE5ajRDQW5qZHJQK0dhQW0xY2UKT3FOdWMvZ2hwTW1LQ1UrRXB3Rytrcmw1ZUM4R3oyMTh4Sll4a2VkSEppN3NhSGtsNExnbTB0c0RMN0s1bzhMTUdEYW1qcU1yS3FxNwpHNFNBN2tnOWFCTDNTbkR6SlpvS1VZY29wLzZFMVZLWHpXb0U0bFhZd25oRU5mUnBUWkdta2YwZVA0ZlFGM2o2Z2JOb0VTOHczK01rCmxzMWlDb0RPd01sQ1FLZlJUb1Z6WUdnMnBybkNyMW9zRlJkcy83TW12YXpBSzh5UWl2RmVPRmNjeG0rbVUyaEJiSXRCTElEbFYzOGQKOFBBdzdzSWgyK0lWT0lteFFIcHdQcWpvU2JoQWFmZml3ZVdhRjJUbFpnZEtRUmcrOG5ndUxRUU9salBJNEYvTVYzcHVBUzN1UG84UQpSQ2kzRmNHTEFwT241ZllWZ2xES3RaaVJqY2NzV1pDYWhxVERSdGloMTNva0djOEVObE1Zb3ZXWXNpSXIrb2FFaGNjTnEvSFVMeXRRCmFLRHB1Uk9abHVxd2VpNkhhcGtuTEtWb000WnhPSXZucDRqcU1RUjhudmxBc3UxUmhlZ0d0U2N1bk9zeFdrNUxxRnF3aFFFTHFPYnUKMlk1aGpZUGRyUUp3eVVOVHpUY09WSUllbGFyUVp4S2dMc2N4WWdBZS9aWEhBeUcyU0kvOFlob1JNT3hpWjN0eGprYW1wZWdISkcvMAowRzBlSG1vcFBia3QyM0ZMeUNyaS9Qakd4b3dSTEF6aENob2hTV1JKTXNNb3Zkd3crS2JZTlY3NjFBSGVCSkZCUnZTOEp6cFg2RlpVCllNQkt3emxOQ00wNldJVUpwcWpCaFMzT083bGR0bGpLQnh4cDBHZElVR050V2kzWFY0dk5UYW90YVl3a3BEQ3pwdlBkbGszUmRqeG0KZ2FHd0NMeExCTWtraTZnbHM4WmhnL1BjczRRd3BDdDU2RGxNeE5pK2s2bG1yQUhzSmhDVHBaMzNaeG1yMDZaNFl6Yk9sSEtiNWU5QQovSzRzdUxScERvaG0zNGFFbExBRlIzMHp5a0xKWEg4TUJhL3FBaUNhU2tjdHFzZVlpejdZSWR0WWFkbGkyZ0VneE5URGtxeXpNNE5WCk5UamtqV1hBeXJJcUxDUWpoUWVHWXpHdkRXcmtHdHRsQkd1RHFORTVGbFdmMVVYR3p6QkE1S0lHQ0wwS1JneGhUSm53WVEzK1ZKQ0YKNTZGWkxDOERRbEFoaXV1WVlXWEJDYUV4S2F5RXZZbEdWdXhOYWRIbG1zdGdnNGViaFdrM2k2cThJTkJRQUFMRG5rQ0F1d1VFTjRXQgpTRUVEYlRFYUdDSElzSHVDNEhkVDdGaFJDT0Z6MndtcExpNUluVkUxU2JuT3E4cmNJZ1FjZ2w4bHk3bkFxd0x6a1NzeEdWSWYxamxtCkc5cXFmUTZNblN2TmF3VWlJaFU4b0k0RVFyYUtoNFBDMVErSFZORVZySmNWVFJDQVkrMnE1ZDZtWVk1WldSbkl1ZXFaS3d3VG5vM1AKUWNUVm1MZk1OSmR4dHMwNWVWenJxdkJyQUluY2trTEJEUlp0T0ZZM2srU1NmbGF2RlQ1elVnZDF2ZmxWUEVNQ2dYcmNITkJNcGY5MgowVTlFSXlVTGlsUFJKU2lhQ0lwRlpBeFBOZ1JRdEN4QzBjS3QzQmZtUWhuVHBqQkVwMnFjVE1vODlWcGRuMFRIenJRbURqc01zQ1E0Cnd5SzZQMmkyQS9nWWx4Y3RpTUk4dW5rZXdoMXBGV1dnbGFzMW1OUHcrMVlMV1NLU0tKb2R3OStOOHBOSVlSdDBEb3BsZElRdjVxVmgKYUhaUzNnZ0Frb3BscTA3czZObU0wV0hnc1J4TGlubFp3MW9vMExmREFqYzlhaHRTTGIxL09MR1pSNlFWZW9jMVZ4Q3owUTdDRWd5ZApWVkU2QkJ4VGRNYk90aWx1aHArWjc2anF1dk9yRnJxQUZVWFB6endCemxNL25RcmduMVc2QngvR0lvZnFuS0tmUWltekN4T0pKMkN1CjZzWGtIbHV5SjdLYURZQ2FOVXVCTXZsWjVUWFk4UmloRERNZ0pPVjEwWEJvcG5MQS9zVjBVS1duckdJWUY0aVc3NEdHWHJTZG5VRGYKV3U3cURkcW1teDhlNTNtMkF3L2dMV0F1ZUNJR2c2WnhBa1RmTVNqME5xNmFGbzN2eStNR3dURmhUNG5aY3VtcXM0MmYxUUUzTjErdgpWdHFLZFlnR2srclJMN2g1VUF1ZHUrMVV4QTYybzZBV0pqRXNkRkFHQVpCSEZCZk9FbTVTQUVEMGxnRlVzNi9EKzBlRG5OVWlBUndGCnpUaWdBWjQwS2lERjlFU2U4d2VyUkxIVUtjemJpeTJtakxsVVNsV0JwdFhDOVhDU0VaaUhTZXlFdW95WEdaRjUwNkVQVk4yK2dZZGcKNHZOcTV3TTVRV1czcXRieFZtdWIxVHlNb0J0R1NEZkMzR0ZialZnOWl5OE1vd0Q4MUdUeVZiVk1HalVPSHRxYWxFTlVwcU93dE1SYQphU21ySGxUQWNPMjZFMHVUeHRIVmFNSDUxU0JCZ0NDU3JlRm1SUzlyTm13OEVyTVhnQWhJSE1PL0VFbk1rNVpYd3djQ3hGM05EY0xwCmlDUkZLMDEwbWs5bVM1cVNOVjJwYXNjUXBVcERZNE84a0lqRmh5R2lvQXdDWE5nNEFwVU1HeW4xNEJsaW5udGZubHN5ci9GR1l4OVIKamZBSTRqTnpGbTVKc1N0b3BxVlZNakVFUGg4bVRFVzJzVVJ2VmJaZGI3UDFTdHVKSS9Rd0gydFdJNUpIaWpIcUNKTzNNR0ZVVUdOVQpOU2VYM2k2bzFhWGFoczdMQU9tQUNSMTZLd2dVQWFzRlVmdGw5QzJEQ0E4c0E4cG05blZtWEdMVUdCSm1kc3ZkU1JoaDUwSW1MNDB2ClhEU1BCM1pYWmxSZ3gvSTR2RmhVbGRWWHN4UmlvS3FDczdseUJRb01qUm9ZaDBRc01GVTRPRm9mcTI1bXdLanFKbWNlQVZJcW55SXEKREpaV2phMjV3Nkx1eVNGcUh2VkV6VkVEVXV2WVRGRTNzWTY0TzFBQlFiVGM2ZlFyY1JzMElKSzZZbzJnN3hmY0JMSnE0QUFXSVBnNQp3SEFVWWJET21DSFBLY29VaWlWbWJQWGdRb0ZLUjlHSitLQ3FhaGllc3dYY0VPeTlXREN4YXRCMDlDd2FKY3lNRTd6U0k0azd2cnIyCllHSlZJOERQNkV5RnlrWWhDTW5YR0dRYjY0QzRRYlJYc0hlazEwdlY2RTJQMEtINjNTbGhpQzNveEtnNTBvdW0rWUdEbFc5RTRITDIKQ0J4WU45aXA4R1VsbW8xTlZZRXUyUklQcWdpVExYNk5kczVTTzhySHdyMFh5eEFCdlVnVE9FS3kzelRUa3NvbnRJWDYwYzY1YUZCKwpDRXUvZzZXUnROUXJyTVB6NVlDcHlFMm5ORUFGckxtYUxtdmROTW9aa1ovY2xRbWpZdUtOZVFUWEI0WDdZL2xEaitPekJxdW1xZmVECkpqWmtoN1hEeDRMQ3BCaWFSZUVhYVU0V0U3V29wREV6Z1JvUHErTGg5RXBtZFYySC9rZDRTMUdQdDY3aWJFQksrdE5kd09ZWkJId3UKYzBVeWZSVlkzYlphMU1pcGJIVHpHUVd2Ly9KSUN1Y1BidWl2bjR6NkpOdnV4K1haUFQzUGJkWFR2OGVzdTFpcG9kU1dkRGZ5U0tyVQpjdTdDNEl0RHJzYVV1MmxUOTZLbjNNV2hvNWovbm5GMzVUa2k2NWh3RjdvMFpyRG4yNFZHS3ZkdDZYYWhRMVU5VXJCbDI0Mk1hVmxhCnNsMTh4cU42cmwxOFhqUkRiMHUxeTJ0Q2JwbDIwVzRwVzB1MEd4bXp2a3V6QzRTaXBmU2pReEYyVmxqUE5jbHVOdVRXa0dNWG1HbUsKd0paaUY0R1NNS2g0aHQzRkVGRzdCTHNqa2ZsMWwyVEpXejI5N3BMVWZMdkxycnNrUmZLMzVMckk1UDcvc2ZkdXU3NGt5WG5mRS9RNwo3QnNEdG9HaEtzK1psMUpiaG1XM1pFR3daQW1HUWRETmxrU0RQU05RbEFtL3ZkZDNpTXlzdFhvb0Nkd0NmS0VMY25yRnJxcC9IVE1qCkk3NzRCUmRSd2RhdHpuNi8wTHBNc3VVUlpOMXFoWS9CdXMzVDZNM1ZoYVJTN0ZkamRZTjF0cW02aU5qb2c3K2d1b2hhNURJT1U1ZTkKZWVZNlNGMG00MHQ1RTNXYmkwTTJVTGNWYWUwMlQ1ZUczdDQ0M1ZiTVdRaWFMbzZUNTJIcE5vdklYaWhkdE1RUnVVQWtYZWdmQzFONApCdWxpWlNhVXdzWFJaZnF6OUlQUlpjSFFPQkRkUGtQQ2RERjA0ZkVYQzVZNGQ0NGh6V2tRZERFSGkrQi9BWFE1VmZkNitMbXMzQXBVCk1UNnhxTzk2MFhPallzbjRYQlNKemNQTzVaOHV6TjNSZVhpM3ludWFuSXVPTUpwQkRjNGRsU0dpRzVzN0hLa0lhaTU2SFdDbURHZ3UKa3V3b3lMcVp1Y3VOTlFLWnV4SXpKUUhNeForY0JTNHdHblpaTldpNUsybCtNU3dYN2hOV0p6Y3JkM2JsSVFPVml5OFlxODRnNWVLOApxL2Jkb0Z5SXN4QlBDVTR1UzJMeHFRUW5sek1jSVc0M2NaalRYaDJiazh0Wno4UmJjbkl0SWlzdlRpNDFaUGpJemNtbGdpeEpDcW4xCkpBelVMODRiWHRXMU5nMU9MdTc3WTIzb293dzQ4OHNYSlhlNXkwNVFjdlVacXcwVksxQTRJeU80ZFdOeVpaeHIwdz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJYkdHZ0dyeHZ1dGFqd2UzRzVQSmRvZHphbUZ4Nkt4UmtYYnN4OG5oamNwZnB6a0hKQmJzaDZaT2dDQlg2L2FZRjEyYmtycXhmQ2tTdQpGMEFCeUYzVCtxbUxqd3NiUHFiQTR5S3FnTnJ0b09QaU5GcTUyYmpJdUROV0lqUXVYdjFIQjZYdUZXSTVDbG9QR0hlaHFxMmx6Y1hsCnkxT0Rpb3U1RWl1K2k0a0xQcW5iK3pBODI1WWNyQ0RpdGtObjJ5TlFzKzR2ZUxoZ0Z1QkhBNGZicFBpN1liaE5ZYTlBNGFLK0Y3OFMKSkZ6OHpWKzVTSHBJVUVBc0hCemNIazJPbkl1QXMxREdEY0h0YnRRVEROenV4R0FnY0JIdnhpdHpFM0JaUzl0SEFIQ2hSL0pycjFrdApLWTEzNDIrclMzbUNmZ3ZPR2ZWOWh0K0tmMWRlN050cXZFaXdiNnVyVkFKOWk3K0Jjcm5KdC9zNEJ0OHl3UUhaczhDM3Rhb1kvdWJlCkZnK09nYjFGRkxxV0h0UmIrRkR0NlMvcUxWZEVxd1QwTm5jOTkyRGVmbmJOSWh3cEVUQW01MW5leUZzVVJTQTBaZUl0YUJGTmZGc0MKYjV1N0M5NjhXOElobnJseHQ4M2xTa0c3eFQ2Wkl0dFRPSXVWaHRwRGluV0wzK25zNUM2SWJjdGFGMXlnVzZJUkxocHVOUjAzTUxmSQpVeVB5ZEZGdVVXZGVSdDJRVzFSc00zNXN4bTEwRnJzUnR3QjQ0cFV5MGJhNVdldjVrMEs1bTI4TGhIRTVkTnVXbmIwMDNCWi9zNFQ1Cll0dFc1NWNEYmN2dkUwWGRJdHZ1UHkrd2JaMUt3Z1hZOW1PaHBNSlh3MXFhS3dodXJDMXkyNkI3QnRhMnVZWWdxTGJ3UW5IWGI2Z3QKM0poZU45SVdJd21URjBiYTRwK2JPTGliYUl0VElVL09RRnNreWxBQUhEemJWaG5MdTJtMk1QR0xNczRXZitPdUI4MFd3d2ZrSGpmTQpGZzRYNGFCbTJVS01oekJMc0d5QlZXbUNxdS9KQVRsSERySWkyVUtiaU1CRWdHeEp2eXoxeGJHbGt1SGpKZ1hHdGpvWUVCUmJnR2N4Ck9OOFFXeUFWTDRSdGRVNDVDTFlnVWZKRHZnQzJoZjFFOHViWEVqejU4WG9FdmhaL3AxVmU5TnE4eEc4TGVHMVc4Qy9RdFpuUThCZTQKdHJoMXNMbTFoZW1ydkxHMWhjclEvS0xXSW1XV1ZmVEVpbUpRbUhWZVV2MTB3TUxYQzFtTEZFUStGRnNvTXJpcUMyQXRKQVZFZXI2QQp0Ui92S3g2MWdiV1k0L1NFUE5XakdyKythYlVvTFdqandHcmgrai9qc0dvZnljOWZxRnFnMXNZNHBGcmNuSXRUKzNDWXV5bTFtSmhRCml4bVVXa2dlaTlvUnFpYU43ZWhmaUZxZ1pqRXZiRVF0MGhLaXlJcFF1NFFWZWdGcWtUbDd4Z2JVb2l6bTBHbXpaWGozbElvVVpoTDkKbElJQ2JsUHlRZE11ZFVCOW9XbVJOVVloVDVCcFVkSFcxZ0hUeHQ4M2x6WnNnYVZkV3N1Yk9BditKOWJZRjVRV0ZaVm9wQnhiMFBtdgpHMG03Lzc2SXRHRUxJQzNxZlhEVXphUDFhM2JqYUJmTHhldW0wYUo4SGk1S3dHZ2ZMb0VGeTlpYXhhMHJDaG90NUIyRVdRU045cUZXCnJMeHB0UGc2S1JJSkd1M3ZtRmJDV2pSd3RBOHJac1VDM2dNT3lqOTd1V2kwOEtyd2Q2RGF1ajd6bTBVTHNpRkFRa2JSZnJ3c0hBTTMKaXBZcXgvSW0wV0tXZnRJRzBRSm5NeEcvREJBdFJnaUdRRzRRTGJ1bnozbEF0QS9vejRqTUI0a1dxMklNakRlSVZoU3RkRGkwai9seApnYUZGa0tYTUY0VVdJV05FbFFKQ0M1bk0wMG93YURIdVBDTy9FTFNZVVRycVNrMmdCVlNBWlVOUk1JTlFVU2t2L214dUd2ck5uMlZsCnM0cVhtV25IMzFQYy9aMXF3bUZLR3hzK2k1eXlRRUxXYkRhRmRpNzBMUHl3cmlKY2NwdllkMm5XRFo2RnlCQkJtSnM3RzdiQXprSWEKTW1mYTFGbmVFS0kzams0Y0FpTzhLOEdjaFJRQVkyQWdaL0h2N0E1eEVXZGhtK3k5STBsTGNSMTM4R2FSWWMvdFJadEZucDFNV2NObQp5ekxjMUt4Wk1HeGR1YnlyK0twMUlVR2F4Y2pHUllRUnNxMG9WWDl6WnVHd0kxNFhOc1R2eUtBelpUYit2aUd6MjJiR0xKcnpQa3ppCjZqMzY3TEtHUTR1QXNLbGNGMkpXRFRGRzM0alpWRjFNdFJHemtDSUloM1VJczZrNGk3c0pzOWhLdUZHTGVmQzlNT0J4QTJacFRSY2wKRmdiaFJvTXZtMWdSMk1hYkx3dnBBMHV4cnoyN2FQNmJMMHZMek9YTmw4WHhLRi9jZkZuQlFsYzVmRmxwWWNvbndDemg0c1VKREdhNApTM1plSWdDelJLZU9OTitBV1ZxRkhEVmdGdi9Cbk9ZR3pQSS9tRjY2Q2JNQ3k1WjVDTE84T2tSbk5tR1cvNVNNNU4wUXF6eGRQUmVFCldXYWYrR0lFWVphUGhwQzBtekNMQkpGU1VTYk00ajQ5ZFpaRG1OV1RaK0xySXN3eUw4WklZUkJteVRaRlZYa2daZ21pWitqeVJzemkKQjFEMnNnbXpPQi9seDRJd3kwTXkvSG9UWmlsc1lwUXhDTFBFNFdmM0xaYk1NcHY0OVNMTVNoTFZEMkNXQm5ZT0NjQXNMT0lTM1lSWgp3bG1adnd6Q0xHS1ZpdnNHWVphQlAyVVlMOElzTTJQNmtFeVlaWXhuK1Q2eGVtMDFRWFplZ0Zrd0Y2UkJGbDhXREVRQ3N3TXZpMFpWCmFwVjI0V1ZYaStwUzgyVzUxVGgwV1J4bU9lMjU0YklJMmZEQkJsdVdnU2tWVlpndGkrdWdFdW5GbGwzTFgwS2daVmNTejIrVFpaRWMKU1BYTmxVV2NVTzNEakpXZFJiaXhUWldGQWV2TkYxUjI1bWlhWnFZc0RLSUNHaW1yN0VWNUUyVlJvcTN5VVFObEdUNUQxbjREWlpuUApiMk84Z2JLODVQejBBNVRsbytOWEdFQlpjREFSbDd4NXNzdTFpTWJKSWxiRjRMOXBzdmk3OXBzbEN3dGxKVWJKNGdDUG9tc2t5UksyCitmRTkzU0RaeEt4N1Nwc2txemk1a3d3c0lNRHNKNHppUlpMbElFWVljNUJrZWRPclhoVnhHbkNqTUtyZktGa0cxSWNhR3hJbFN3T2kKYllHU3BjRUUybzJTVlE2bTVZMlNWWnBram8yU1ZmNWx6UmRLRnFkTWVWaWdaRmx1dy9yYWFQU0ljbE44SHpkTGxpME9vQ0VJbGl5RwpkbjVyWnNueW5yQlc3bUxKMG9qNHVWbXl6SXdqQWgwc1dSaVlSTGhac2pBR2daWXNXUm9RVndtV0xBMXNTM2F4WkNsNXBLYkdNRmwyCkJNSFhIekJaREI5VUhOdzBXY2tnODl3MFdXNkYyU3Rvc2lrN1ozSFRaR0ZrZWlGb3Nsc3NLWnBzSXJ4bnRCZE5Ga2I2RWtHVHBRRmgKdktESjBzRG1NQmRORnFNMktibUd5WXJvdjFMUVpObmFHd1BXelpPRmtXV3lBWlJOcElhV3VZR3lOTENLK3dMS3lvaGtoWUd5UEE0TApEZzJVaFlFczl4c295MDRJeUxZSFVGYkZFbmtGVUpaOVFQa09YMEJaMWNZQXpXcWdMTnJWY05JT29peVV6eFMyM2tSWnlxR05rU1pSCk5sV2pmVTJVNWQ5OHB5K2tMSTJRQ0FSU1ZxcnFyQXdST1Z6OE5XcVRicVNzWk5UNnJpblFZT09mcFZwQUVtVzNRdm9teXRLdGExbUQKbkFTZUlQSFRtUW1pTEVUMFQvb0VsSVV4c1JneWlMS3dlSXA2b2dkOFBYbkdqWlJOcDMyQmtiSThGbnRHQkZJV29uaXFMRjlJV1Z5agovS3hBeW5JK1ZvTFdoRGE0TitNVFVaWktKNWFYQlZFVys2bWdMWWl5dUJFaUc5eEVXVWpZVFhVM1VSWXZGaitLQU1xbTVvNlJMNkFzCnkyV29DQW1nTEx0d0tUVnJvQ3g5Y1FDU2JxQnNpb3ozQnNyS2NuQ3lYMTM0N2R4akxIMmtGTjg0V1VFUzhxYkpZbXlsTk5vMFdUMzQKbFY0NFdScmhpd1ZPRm9lbWdEbDRzakJ3VnJwNXNreVR6N0Z4c3Z3YnMxVHdaR1hvNjhXVHhZOGhqUnc0V1g0UEFralNqOExNWUJUWgpscXNodjRZU2xjREpNaStaK3ViRVloU2FiYjVnc2hqUG5GbWtyVWRyVGFGa093YVlaNzVJc3JBOVpyNU9iVUpNaVRpeVVPZk9GMFdXCm5lZytibHRBWkx0ckE3MEovc1NRY0NOa3UxdTZCa0VXMktoSFFXSEVpTkFxRnRQRHhZOGxqSFhWTUxIWGErdWJIaHQvWC9EWWJUSTcKZG5yT0RTb3NXS2tzMHJuSXNhTXBhcnkzS1FLRUJEZzIvcjY0c2R0a2JPekh1VlBuYUdyc2ZBU3R1cUN4UWNzTlp1eDhOTFFGTW5ZKwpiaGgxRVdPeGo4bXZqTTFNQzBpQ0Z6c2Z2Ym8zTG5hNEJVN1FZcGtiVTRpS3RGalFCTWpOdTJDeGhJaVd1Vm14QVJVTlZDd0MwQjhECndRMktoUW1mVW9CaThUZHlvY0dKSFNLMzNwVFlZYWxYUUdLSHU1Y0VJNVpCNnR4ZmlOaHVEeUVRc2ZqY0prdkU1Y0dONkJad0VXSUQKR3hXQVdEUzhRVFl6K0xBOUszbC80V0ZwS25uVFliRUxrWVNHd3dMNnd3em9nY09DaUZYR1JzTWltWW1Vczhpd2dHR3hIMWw5NWJkWQo3Qk5jV0NSbUtWY3hGblo0VFhoVFlkbk9sQldtZ3NKMnJYRUNDZHNOL2J1SnNEeVJ1bm13YkROOWFMQ2RZYS82Z3NHeXVBdHZvbG13CjNjVE9RTUh1UXh3UWJIZCtMeml3dzBtVFozL0Vvc0NDU29GUUJDQ3dHSlBTaFh5ZDBTYmpRc0JDeDhYVlNXeXp0RndLQUN4SlYwUzcKSHY0cmlSV29JVk1xQ1g5MjNpUFJYNmYxQ2pmOWRSbzBHL0JYcU4xWnZXVDJLMUMyS05PN3lLK0xvZDJ5d2E5WWJiTEJnd3VDNCs4TAorN3BOcHI2QzY5SkY5aHRXam5HZGNUTmZsNkV3Z1h6Rk9veWZheUJmaVRkb2FoYTFrYTh3U2xHc2lCVjFIUXdlalNoZDZacktMK0lyCmdVaEQ4VWI1RTVCYlVVdHE1Q3Uzb056MFFyNWlDdU9vSGNoWE9KUmw4MTVuMFJPL2NhOVlKcUhTUDJpdlBKdEhHNm5pRjM3Q05LSjEKMXczQVZjQ1ZCdTVWYm9JZ3VXclRsZHdwOXNhOTJsVW9HL2NLQTBlendMM1N3UExsQy9kS1A0c25idHdyOFFrWWVvTDMrc1hsK1BHSAovNks4VjRiUXdQQzVlYTgwSXNvWXZGZUYxVXJlZ0ZkR3kwaDN2NGl2RElwQWVCTEVWMkllZUhBUlgxZlZ1M0FEWDNIQlhKMEg4SFV2CkJBUDRpckFYKzN2ZXdGZTFQcFREUXVJckRUam51Z042WFk1QXZlTjVvbFFFOEZVUnRkNDI4SlUxZlNTMVg4QlhCcFllSjdNa0srb1MKa0FmeGxmRUxacXN2NU90MkRJMTg1ZnRub1lEcTR1bktJa04vSVY5dkkyUHV5Ukh3UUw0UzZkQ1VwdG5JVndyTklXSUo1R3NpYkRmbgpqWHcxdEtLOGtLOVVDRklQWU9Tcm1HQ3RiT1FySGlFWE9UZnlGZVVaV0VJRzhSVmxSVVFtcTVwMXVhbkd6WHVGSnNsUWFYck44RWt4CkNnVHVsYkdqcWk1L0cvZkthRWRYUTJQeEJ4NzM2UXpjS3cxTmxYbW45b1hHMmpmdWxjZEJoRE53ci95MVBGKzBWOGJvMkJ2WnRGY3UKQnl2ckwxalB4d2dUYVlNSDlvb3dqUHMwc3pvSXpDYXNFUVAxeXRLSlhGK2tWeFFORVJwcjBPdVk0cllGNTNXNFNPdkd2TUpXVkpGSQpWZnR3dldoQVhvZS9oaHZ5Q2wzYU10TVZRa2pSTW9Qd09yb2lPVGZnZFRSWDI1dnZPb2FLVUUxM1JZaUZyUElMN29wK0RSaFRBKzdhCmw3dGJtdTNhSFd1NzBhNWdEaUZvRkdUWHJnaGVjRjNKS0JydGhYVmw4eEJrcGtSMXhSSHdoZ1hVbGYyUXgzZ3hYYnVyTDZPTUZUMHMKc2lyWFdiT0dNOGQ2K3lhNnN2OXdMUnZveWtMcm5EZlBGYXdvT0hrM3poVXViOVk1TVZtR0xvRkZsMEdZYTNVVjRNMXl4ZHJSemV2cApZTmE1QWJBTStlTnZ1T0EzeUpVTnpVZmVIRmYyeXNsbFkxd0JJSVZ5NWFhNG92NlJMcmNocnExcG0yQzRRdG1DdGZHTmNJVU5ybndnClhLR0lhVUt2Y2pVSnhZeHBiYnQ2dkZVbEpBTGcycXJrc05jK3JDQzY4YTJvQjJmSnU1a1Y0WVFIdmhXMUpKZy9iM29yUUJQNG5ZQzMKdHJsNzBuTE1SeFVNeWJvWHV4VTJmRHFCYm0yZVhvTGNpdk1vSnNSRnJoWXljSVRhREc1RlFuRWNkUitJQUVYaTJZMXB3WlV1MXdvQQpYSXJGRGN2cHpXeWRiaVIvSTF1WFZ6ZUJiRjN1MHhQRVZtaDZpWGk3Z0swUWpMS0kwYnhXbHRDc3RYR3QwQ2NqQUhmUldpVmozcXpXCjVUQjJvRnJ4ZC94S2tGb1ptSWVySGFUV0NLRUhxQlYxUGVBZzNKeFcxT2h4N1dsTTZ6TEdMeWl0eS9IY0c5S0tuSURlakFnb3UySTcKeEtxaU9lWHhnclRTU0t5dzVWT0pHTTFjTjZTVjRXejRxamVrbFEydUVmb0xTQ3NtZHNNQnlXaE4wWjdnWXJTZUk1blJDZ01STk1GbwpwWG9mUVltYjBRb3ZKbDRJcGFuZ2dMTjN0aG10VHMydUY2T1ZuaGRiUDVqUnlnd2tacDFndEg1eDJDSlk5ZjBZcmNzdFcxNklWa1JkCktmUVBRaXVpcmxHOHdQVU1wdlJrWXV1V3N5eFN5Z3h0eFhBQmd3cEJUV2ZGYmt5ZzNIQldGaVhLcXlhYWRRVmZOUT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJaUtzS2wxMm9WcjIyOFAxWWNoaWJvV3ZUOU5xRWhmRW5yM09CV2VtR00xOGZZRll1ZHBoYURqQXJRM2l1NGR0NFZZYnhXQnRwTGl2UApDN1hTbTh0S0I1ZmtyYzg3OWlxZHZkb2NzeUptam04Ynkwb0xPN0hlV0ZidXdGb1lZMWw1MFpoTWpHWGRmOTlZVm9aeldhMXZMS3NxCmMyZmRXRmJtcjFoZGNHRlpHZnhtZzdnUnNyVkh5czdnc3RMenpRS3NucHBDZUU0NWJTd3JZdThzT2pLVmxmOWVoSURkVkZhZUVlNWMKVUZsVDlCRUlLaXZGK3hoRWJ5b3JqZnlvVFdXbGdVT0txYXdjekZBN2NGTlo2ZTNodklQS0NnT3JZNFBLQ2dQVjVqZVZsWXRLanYyaQpzbExac0JReTBxOWpkSmhLQ0cwcUt4ZVp1R3VCWmNWN0RkRitVRm1WV3l6MVJXVWxUd0pJZzZDeUtzR2QrcWF5SWpiUE1lV21zaExvCjBRUmQxVmdJeHQ0OFVGWkY5RFZlYlNvclZRd0lGQVdWbFlZaUNpc0NXTnlyS25Cekt0cWhpZUs5TnBXVlhMcWtZTjRRNGkzcEJ0MVUKVmdnZUVPb0xLQ3R6YmZNd1dhR0RZZERpWnJLQ3A4WDA5TjRLbmdPQkM0YXlJdTNCOStPR3NzTEk1cXlDc2dJR1JIY2dvS3hJenpCQwpkRU5aeVI3RGtqT2dyRERRWXdzb0t3MlFTdDlRVmdKNldNOXZLS3VJUFI5M002Q3MzSTIxTGhlVU5UVzdhUUZsUlYwcmx4VUJaVlh6CmJqQ0VENVNWYVN2V214akt5cE91OGdVSVpRVytqYUNBaThrS20zN0xUTlpFVWsydG04bEtBK0ltTjVNVlJtTEhnc25LclhqOVpyTHkKd0VtYytNMWtSZjVQbkFveldmRmtpYThLSnVzMjNFeldZelNURlFkblFDSm9xNG42NGp4ZlRGWmtUT2wwN2EyeUZqQ0JaTjEvWDBUVwpzQVdRTlJIU0JTbUNnYXo3WmJ5QnJNeDhvaTQ3Z0t3c0ZVWnlPb0NzVEdPWmdIKzZ1OE80NUo3cEMwWVNDNnVTQUxJeUdhVy9kNTBEClgvU3FtOTlVZ3Z5SUIwRkVBLzRWNjhlYngwcThWWk1QcWV4eENkWmJBRmtad3BrM2o1Vkl3Q2RMVWpQMGFhZ3FQbmlzL0ppY1BMNDYKVEZTNUJ1YXg0dStPQkY3d1dHR2dwM1B6V0dGa29ENTRyRFM0R1NsNXJEUThPazQ5MzBwV210UkVWbVpYS1hJS0lpdjBhaXlKZXhGWgo4Wmk3T2VzRVlyS0NmNmdmS0lHc2xHOFJHSElCV2FrVHlJS2c2NHZHK2xuWlhBTlo4ZGF4ODlPTHlBb3IrY0NieUVvTEhzbEdzdEpDClFkdU5aT1h4Mk9vOGtLeFV6TEVxTlpDc3NEQnVkU0ZaNldBeSsya2tLd2xXZytxaklJY2treUl2SnV1MmJTWXJKeVBxTW9QSnluczEKeXljb0s2eDZwUXhsaFlHTC9RMWw1U2JVek54UVZscjVoQUxLS3Z6WE1LWlZ1TTZzRWU4RlphV0k3akZycVd2bTdCb3FOcFNWakFLbAo4eThvS3dPMnJFOE9LQ3RySUtsVk0yNlZiejJ2KzRLeWN0R1NqbTFGTDdSQUFHN0RUV1E5Um9OMjBNSkMxQkR6V0wvNDJOL1ZqZis0CkUxV1lpWU5qVlZWNTJqUldlT3RjWVFXTUZaSGNYdDhzVmdTSldGNXJGR3VYdW5xVFdLZEsyRjhnMWcvYklERFZTRlhJSmhBc0RCQXIKVnMxbzBITnpXTEdPNi9jdUErckVEV0cxM3ZQRllFVXRJSW9FakdCRmV3MXhTRVJnUmJ5eXBmb0NzRUp5alFwNzgxY1Ira0xOYk5CTgpnWldGL09QR3I4STJpV1FWZlJWQnVtZHU5aXBVOVNpV3VkR3JVR2Vqd0NMUXEvaDdJY1J2OGlyK1JubnZUVjRsdlBialF3anlLclRuClVERHNVNFBJbHF1Umd4SmpNZ1J1c2JDclVGY1hmTzB1N1FLVmJ1RUdYZEJWS0crSWw5YUFXcGJHOTBDdWxzNlcyQmR2RlI1RXhuTEIKdUZYMlhudktwcTJDYWxlZitZYXRsaUk5d0dhdFFndmVpR1IxU1FRTUtDQjZrVlpoaEdRMFFLdUZoUHQ4T0tzRkViVlMzcGpWc3FRawpKV1VWbVZBeU5mMmlJTlhNRmdrWFk3V2FMUmVJVmNiQTF0aUVWU3pZdWE2OUFLdUlUcERuRXJHcXg5UUM0MVc3UlZZM1hSVTI2b3dNClY4VStTNWxKUlVvZjh3Y3V0R3F6eENuSXFzM3Q1d0tzMm1LcU9XQlZxRTRZU0RkWUZaSUl2S2ZHcXNJNUhPa0ZWVVVnbEFrdU0xV0gKRVRPQlZCMHM5SHNCVlpFQXo2S2xrcWM2alBZSm5DcDJBWUxncHFsQzZjTDhsMkdxbU0zQlh6WkxGVElzMWlsY0tGVmNIaWJwSUtuaQo4cGxCZFhnUzRVT0VXbStPS2dKdjBDMEdScFhaYXBFVG1hM3JLdFMvR2FyZFBQOUFxRWFKY0JCVXUrdi9iNEFxR3g2VXRmbXB1K2pUCitOVEMwdVQwb3FkV002OENuZ3JJSjlKalpxZTJzdkdSRzUxS2tFU3VtNXphM0ZZb3dLbk5Lc1dibXdwYkVRQ1ZxbHBTSlhyZTFOUlcKQkpxL3FhblZBdnVBcHNLTFl0YzBKODlRL2NTZWZoY3lsYUtEVVRZeEZhUU9mRGdHcHVJT1FFbDU4MUpoZTFiZnVGVGdGNmZFTjZTbApGcVkrMGd1V0dpaVZZS1VXbGwvblFLWGl6NHlydWtpcHVCdVBoRU1FcFJhOGVpS1pNTUZmV0psZlhwaFVWUDJ3N2t1RkZTVnIrZ2hJCkttcUt5SFc5R0ttc0FjaHRJMUpGdmxxYmtJbzhaUjh2UG1ydUtySU1QQ3IrQmpRazZLajQrNm5yQlVmTnlJTTg3YkJSUVJaU2grbkIKcHJDVkgvcE5SaVVnM1RhQVVTSGdRSTR2d0toNFdiTUFwNXVMMm9BMmVnNFdGWE1qbk1LZ29pSSs5SWlsdXFHb2l6WGo2VEJSS3lzdQpEeElWNDVaZW8wTkViY0xkYkNKcThwUnBJQ3BlaFpwZU9GUzhRWEEzZ29ZSzNTVFNGMEZEeGF6SXk3MWdxS0FrUVA4UUxGUUVFSldpCnhFU0RMSHNlbjBpb1VNKzBBMExGbWwwL1F2SUxXMitXL01hZ2ZyeFlnRTFzQ3FvRm94dUNDbDF2TFc4R0tzSVBwUjRFS3FhT2NnQ28KeUhDbS91YWZJdnE4NXNHZjRsVmwyd0RUVHo4bS9xcUt5QU0vTFhKZWduMmFQVE1IK3BSbHZYaUxMdklweEJWOWJPNHBGaEFrNFFYMgpGS1ZBVC9wRVBRVUF2bTdvS1JKbGoxd3FESjFjdWxBdGV6RlBKVlZnWTNaSlloRkRkS3RsS1VjZWxycktvZHpRVTBUVFJZczI5UlFHCm9lRU41L25pNTM1UEp4ckQ1dkQ2TktDblVBVkFjUlhNMDBBbkJmSVV1YXNwU3VrbW5tSWxEaGxrQUU5UjhneWhTUEJPU1J5bzY0VTcKeFNnRVg4RzAwMlpTWThCTzhmZVlMOVJwYzRZN1NLZklEaUx1SHFCVDBrTWc0NzA0cDYySk5oS0JZaUNTNEcwRXdCVEFEK2VuTnVWMApwcDBCcFEyTFpkNEJWUzBDVFlQVitJMDRoUTAzTWdpbnk1aDlBMDVCaHRTL2Jyd3BJdG1ZOVlKdWlpb1lCcmE4RFJKbnlDemRiTk01CjFkWXowS1lCOWd4bTZaaEtWOXhnVTRUWDRGK0VyVThKUVFOckduL2ZWTk93QmRSMGVIWU5YT25vV2tUZVRGTW9MSXZrVzdUTnBOQnEKRUUzMzN4ZlFOR3pCTXlXRGRkV05NeDFHS053MFUwaE1TVEl4ekJSQU13UjZBMlpLd0ZrZUw1YnBjQy9hUUprT2ExMENYSXBYdStUeApBcGtDQm1yOEtZVmUwelR2d0poQzZSYlV6cUNZSXI1V0ZDOWtMSUovbDBNeFpSd3h2UmltMDVDWlFKaE90OW9KZ3FrYjI5NzhVc1lzCld3MThLWE9jSWlkeHJsTU90Tjd3MHFEMkJMdDBUamVEQ1hUcDlNZjNJcGRPWmlPbDMzSlJFa3RjQWx5S3Y3UEN4WnRiU2x1YUcxc0sKMWl0RUMwRXRSWDBLZkxBYldycE94ekJXZGhFRk8xSXdTMW5sa1YvRVV1Q0JFQVVLWUNuZU9lbm16U3VOMXI4dlhPa01BR1BRU2xlcwpWZ0pXeXJLck50K3NVcE5vTjZrVTU3UDY0WlNpNklTVmVEZW1GR0ZCb3Fvejc1UEtFZ0pTdW85d0lVcG41QkJOS0oxT3NRU1BORDd0Cm0wOEsyYVBvcDhLVHpxUWJ0N0dqbzVwQWR0TkplNkJDdzRoTUMvR2JacE5TUFR6ckcwMDYzSlI2azBuSnhlamxnRW5IYytwUFE5bzcKbmxPQktyVGE0ODRlUVNYOU1LZ3U4NGFTZGtkN041TzBQMUU0NmJMYmJiaUlwTWNtSUdrM29HVURNVWRXZWMrTFIwckpTdjIyYWFRbwpLd21NRzUySzZ1cW5GNHUwcnFnTU5vcVUrdlFlSFpla0xJOFdUenRuaU94T0tvb0E2dGd6eUh1bWFsUW52bDhRMG1hOXdHYVFJcW5WCjJpYVFqcURnM2dCUzVBOGhJdy8rS0ZkRDNnaTFvU1FnbW9vV0tncVVBeFdEN2xoZVc3TlVUSnM5V3JONldyelFveFdMNndDWjRrYkQKb0pwb2swZXI1WHczZUJRTjczVFdUclpGcmlld281K2RreCsvbytQelg2bWpmeXQxbFAyWEtETEFTUG94eGtveVc1cTcwNUpxMTVQYgpNaTF0eDFjVUt3bkd5MmtJU1RDMFdYTzZ1enNodWs4Y2YycDFCYXl1RUwycmEwbW90VWh5ZVJqY2hxYldJOUs2Y3c3RDRJMzFYc1kvCnNhajBPYlFBZ1psQm84TnlDQlpxdk1TeWZvUUxVS3VxUlYrem5UMGZKR3lKQ2NmS2hDdEtrOHZUbUxJSTU3d2M1SXVyYkducVRDWlkKT3FRTVkvV1IrRTVqVklFT2lyd3UxT0xDSjlUeTBXMEZNZ3RiY1JjSUJ4NXErNnppelpiazZLQ1Q3V2x5ZjZ4WmdaelVYRUlKQyt2ZgptV2tsTkF1V2tzNmVoTWpSMnJwSXcrNWJnVFVwTGhnV3lqZ1JnWjRCNW0vdUtjMG1yMWoyc20zNzR0bGlQYzlBKzZOUmt3MWxJLy9lCnEvS3BiQTNIeW5rV01pVjEwUDJZaXh2YmhaUEppSDV5VWJ6RUh1T2RDMGpNSXl4cnFPSTNveXN4V2FQc3YwUGxPMUErc1ZCU201NXEKNjNCL0hTWmRZRUhva245WC9WMERza2pqVkVQdHhsWTUzYzIxWU9rdEd2NGdza3hMTDZjNXZBQnRrTkJTUzRWSHJqWk1qemlncVR1dgpyajBqSjhibFJkSjJEenRoUUJHYjJTRWJqZGZaamFvcjE0NlhvRTVEcGRCemdEQlVQaWFFcnRGMVFDZzFURC9FRjB5WGpPRVc4bkVyCndXQXhLRytzV2xRTlIwb1JqK1czT3YwcDBaTGliT0gxZVQ5a1B2QTNpMUo0ZkZiL3c0SUJIcFlVMkFCOHQ2eW14aFAzOGJzS3kvQlcKRkR3QlVOV25wTXpqa29wdzlRUDFORHNRNC9OU25XNm1wUzUyVkhaZktIdzJZM3F5aHBXQ0RWcEI5S05sOEJjNmtWVTB3S25PcktqWQpUUWNmbFVMRFNnaFRWaEcvRHNXd1gzN2M0MUtXcVBSZUx2Q0VWZG80RWsxTjExZUpPQzRJdXEwc1dZN2pGVS9Jb0hFODlZOUVySVF0CkJ6QXFaM1dsWm5OME1OMzNyYVVWekZGWSticnd2V0dPRGt2bXhaYmRybC9rTm8rakVHeUR6VzZPUTJFb2JpZTBQMzRoOFkxcmtqNm0KTWM4b3dnN09LSDVtM3djR0RPazdJRjZCcDFNNStBM0RWVUFMd09pZzZ5ekV1ckg3QW1vM3NLTTJtNGJBOGJIeU8xZ3FRTkV6V2RKdwpKUzU0a2p0U2t4Y0R6WVArbHRBTmY2ZTRPNCsxdG9tUVhlOG56RW5zNTZyNmZlU2YvVHdvZXVBM2hlZTdXMEhnUk9uM0xFdUQwMXpDCkxPa0NrMzhReTFzeW5BQ0hXQVF6c25URmJ4RllFSURuODV1UG4rUlhpUVp5S3o5Ky96anRRU2YySkwzZ090YkFnT09xV0xiWEpFb0kKVnVUOThKdHFQem1ZeVM2MHlNZWs1bXpGbnRuNERDaXgyR05zRllQNndheGxiNjVaQWl5WmxLelV1T1V1SEhqSmxLeGpzZDNRUUZjUQprTU00cithZ3JWOGpIcXhVUERaeXUvRzN6Z0h6Q2ZrbzNkSmZXa3BNMGFoZDVMcUdWaVRadXh1NzhVZ01FWEllaVY4c2dXM29XY215ClJKK1pYNFpieTdFbkMxWW1pQlFoVm9XM2xZaGlEajZqUzYzTzdpWHNGMENRYnRORC96alM0ay9xdlVQTUFQSVR6ZTNEYnhVNTZ1d0UKRVBYbncwTXhCRnNmbzZnZkwyWjcrUk5ZZWFCYWFEaU1DOHZIeUsvVEp6dUZmZDlXMThNa1FTSThrVFdUbnpuK0E0YkhiOEhIRGEyeQpKTDdzaGVITi9aTStISlE5dVBIVnhCMkFxNXZQbnFWaWliRXRYeVFFK1hwN2t1RWIxV0p3M2d6a1ErZ3Jza2RORlNMNTUzQXB1U3lCCmxYVXNzS1FzSi9OaitIQXowSmN6R2lGUVNYbnBWbVMxdENMRDcxY2JwUlNCZGVJbEl6QXhhMG1kcUdQdDdvS2QyRmYzOGxMVWh4ZFcKUWdwZ1lXMHNjQlYweG1DaDMxc0VkZk9lVFJoNnJaeVRlakdKRmZTeHRsNjl5STl3NXhOYjVGS0Jvekx6dFIxQ3FIeC9TelhkS3JvWgpraS9RUnJpT3pRMW9VWUgxdUxWRkk1bWNQYit5bTFSQmRRUkYyZWhSM2djVkpGOU02TXo0aEhxZ2FtNExrV0RhTStadzBocTdGR29mCkE1dXVxaWg4Z2ZOZmNyTVlxOFQ1TS8vMXN4M2RRc3dUeVBsdG1IREFxYWVaNDNsWnB0Qnc0U0lUVllHUGgxck5GZz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJSFp1eFpxNXNwVmhVMVVIV3hneVZXSGRiRWpUaVh1eWloZi9BODRXRlZLL3Vya25jTWI0aDF0dXcvV0ZSTW9lV0lzUGlDOWRkK3FlTwpyZEVqcXdWMmkzMDBLT0lNTGo4Ri9sa3RUeGRIMHVHYzZoNmROS25YakdFQmYydENRc3FTelRxenlXV0RKSys2OTlQNWt4eis2UGg5Ckx2ZDhtZXJYU1lrcUxXMnZBWVpmT3haT1BSS29VUkNNampVMVY0MU42cW5kbldENjBhc0hpa2YxYmxVMUYyR3hPQnVwY0R4a3Q4MGwKcWVmVGg1MVZKREFmdDA1YkpEaHgzWlRWSldlaHowSmliaTFwTXVvdEpJTE12dUpMUnNkVVlpaVE3R1MzbnlPMURDb1RaTWhyQzlXbQpwVW1UMGZDa0pyL1R6VllaYU9HZUxESkdKSHQvSkRYRkkraGUyWkJ1eW04RDhWZXNRR3YyUGVzSVBBVUFwamkwdzVtNDlQaVFOVVl5CkJ3VjlGVlhNMjZMc1UxWHEvbXlIVlJWblFjQjA2cU1JbHQ2ZmZybXJGb045M08vbFR3bFJKRG9TVkZlU0cwVGRwK2dzOFRrajFjUkEKR1FBcUkzaHUxVEFXSnY5SUhFcTVCM2FsN0QybHZpTzBoUUhrYWRZMFhxUktQQXZZY0VzV092emEwOTRmbENqNWNRa29heS9BTzhpcwpIWEVkSkY0THJoWjVYeW5oS21yRFU1S09UMEtBVy84bzJNZ3laYm9IZTRoRldESjhobWF3SHFzRDZEUGszSUtLMXo3NURGUnFWSGtwCm81cTdwMGdqa2J2VGJaZndqVFRyb3JSajk2QklLY0RrODFZamVNclVlUTdiZ2dhZU1mUWM2L1NpRlZGWGptS0E4M1BhaGw1U0hxRXQKZXRIRFp6dmJlWFZGcHdsNTY4dENXWWwzREdOcm9oWVRpOGNmd0tmT0JlOStYVUVxZ1JPaEo0bGdQRTZXZlhTYk9EdWRrdGhzaU5GagpVajd2Vjl2bDd5eHMwejJMZU92eTN4UjFQY1JJVGxucXhzWGdzVlU5Sk5KZWhlTnBlclJVRmRCU3U1Mi9QZHFCOUVWbm14TDJxU29CCjl3VmJwb0VpZmxVTVRFbzFlcmdoRjA2cUc5UmsrckttdXBnVUxoMVlJc0VoREVUYkhXTEI5MGdmaEtGTkJsWWgrb1lRbUJiditlRVYKNlFkempjYXNXSnB3dUs2VVpJcWpCRkFMREE4bGNOaVJzU1d5UnZaM0JjZ1JoZkpKcEdrMk1lMTJyTkxqdVA2Z3l3dE1TeXc2S0NrZQpmai9zSWliN3FSRDBONDU5MlpNNkFrTWw2dHNRTnFha0dwMXZOUElqUU0zN0NrYm5sRitnR0RGSkJWdk1qcWlQUExLVzdJcm9FZUh0Cm0wa3V5KzdVbGtmb2dHRWQxVDRmVy9JV3Z6MTBBaC81TUlyYXdZSm5wdkg4OFRCRDRWT1ZBSnoxRFA0RUN1ZWowZTFIOUQzd2JDdXAKQlJTUkluYlFteitWNWp0V0l0VXpJc2dDZ2c3Zk1sZ2Z0MWNYdTRvNnlhVEhwU1VUOGZreHZ0WUlmN0p1R29NY0FXbGRGczNzTEpzZwpNZlRxOGNOWG5EY0dEenMxa2NONm9lb1lpd2l2SGZwangza0ZOQTdOeFpScUFacHRhSGgwbjU4cUxTbm11WjNzb0NWV1pidkptcmZiCnFaUEJzUE5sZ1pSdjlmQW50eFh4WVhvK3cwZ1hWQUx5WmZ6czVNY2FJS05PdXFJNkhzSTh2Sk5xa1lYTUUzdXhkd1hBY2hERU1xWUgKek50WjMrRGlOcHlpdVd5dnhybmxZaGxJeGdjMmliMW9lazAvdmdINUFMbk1IZDJFc1l1T2dmRUluUkdnT0N2a2xLaldFb2FLQkJBTgoxWmNQSzdYb3J4M0pRT1B4ay83T1ZLM0FiUWs5TFE3UDhuYktEeEZPd051OUdETEtVZ0hqSXVCOEkwekttWVNYQ0NqVzRHYndhSGxCCkpnaGxLcGJ3azhVdHgza0sxUnBKV0lWZzRBVWdwZ0ZHTHRzWUY0UHRZRUVyRlJwMmp5K29wL0NPOFhEb1ZseTYwcENaZmhmQ3FMQ2cKSm9BWDJhd1M0Uzh5WUY2YXBnVnN4KzVVT2xmOGI1WG1FQmZMd0pGMmRHa2JubmRMRkc3QzI2WHFjMEJOakFmZkFqR3dSSXptbmtSUgo4NUtTWHNlY3ExQUtrQXFpYzFCV0tsY1h1V08vZkxORUkxaEtSZkRKTEQ3QlIrNTBSajBFdys0WUk2dFQrckFxbGd3ckF0eXdLSTZNClBpc1FLTUhBakFBSGo1WDJqblFxYzNWREVCNEtDMGRZV0hqSW4wekxCc3V2TWpXcE9NV2FsTFptSkozQmZyNWtET1VPVlVqalRyTUIKV29UODlvYzBFTDVRbkE3Z2FDTERHWjBxVWl6RE1sWWc5b3ZEMUNpN2U1Z3VLQ0xsY1RNK3kwZmR6bUhvdWU3OUdHWnZpdVp4RzRiRgpRYUJRWUsxWWgwc21SV0RTbncyUUtPcFRvRGp4MGxpeEVFNWlGSnJ2SlI3eHNKd1BjZWNlMlFVQ1J0bHFHR0UwaEZSYlJwd0kzYTE0CnFvUWVSOStCSkJJampSQkZzdjB0c1VPd2NPS0dHSWowSXZqS0pWakswQU5CazVIcGU3UGRzUjB3V056cElQa0ZoaCsvRzBJUlJjSkcKNGxuTHJDeTI3VkNxcUxEeGVKY0tLTWRJek12RXhSTXNBdnhQemRwVGl1WEhEaEVicWo1WnFSM0dEM2UwY0E3RlRCbDlWSjlYcDRBNgovSEgxb3NXckNjOXVmOCt3RHNic3B3cGxlU3dGdkRGZ1JKUGFvUjF6dkR4cys3QVl2YVNQd2J0U0krZUVjWVl2Q0hsRmVFYVBWUjg1CkcyekdwQk5DV3JnSEJLNDgwSWJ4WVQwZThnRlZXVEhXb1lzZEk5K1BPYlE1dVZVUis4NFc3VWdTR2U5U01rT0tWbkxVY1dXTG1aUEgKc0xYSFJMYk1ibmhqMkpMUHA4VysyTHhMT1MzblYzUU9VMW1yWXNUTkE1R0UyenZoNVJKSEdpVmovQ1NReldJT2ZpNlA4Ymc5YkNSSwp2bkowNHNXSGx0ek5PV01TOUxjb0MyV1UvRjRyazBOUTBVVjdBSkMxdEU1MUVVT204cmRvTzdZZjRUYU1mS0I3NHc3RlEwQU90M2hGCmJ4VW9ZUmlhVzQ3bFlPanRqOFlETmliUW80U3NudTJ5bThCUm1WRHU0ZWd0SjdyaS9CVi9jU2R5aWpHcUNtRmpkQ3pSWWhZV3FBZGgKVVIzWExLZTZFMVo1SWxQcW1FeXR0cnRvNzU4a0NZUXRzM3ZNemhCc2N4VktPU0xlVC9oYlU0K2NpNGlNU0ZIbU5VSStxOTNRTFlkOQprNk1iSnZnZk5YdllhM2hMWVdtUHR1bWhrSmQxNnBheDB3RVBOYm9zSE9Qd2U2M29GOWY1eFNyQkp4SlRLK0c5UmNpSEl4UUtDZVVmCmRIVld4TGx6RzdsS1U1Ri9waFRnem1RU0NKMEVvdTlFTnNqU2dKSWlrZ1ByTEYzakRRdW1ZRm5QZEhLUGVUVnNzNW9ubDNoekNJU0IKLzRFRkYyY2FOc2h5VnJCandRWkw3MDVQVTZtc1BhMnZoSlZkVzNCTkpIbHh4S3FrbUdVVjR5dHA1N3dqSEVLaG5xQ201aVNGT0FsOQpJNHdreUdaa1JIN2EwR1RROCs0ZkJrMmlqV3JNeXZTK3BscjJ4WUNoTVUrN2JnMCtlcElOcGFRWmdlYVJHcWVwUjRzNC9tS21LMEk0CmdYK3hHZnlBbkNHckUra1NLczN2WmltWkRhbTZoMWVFVXVVVEdzeUNTWUVMSTdvc0hLblo1NGJ1TWpsYStNVU5mczRoNDhYQVZCQUwKd1Z1MkhuaEx1U2pmblJtWXhidU04aHZYdE1EWUpoNFRmRlZVUFdRR1psSFh3ODFzR1J3R0VBc3FWb2RsYWlpeXRtdDh5MGhnbXJKOApMQi8xays5VndWNHZZTEN2ZTJuOThTcHp2WUFxcCtxVzB1d1pCd3R4VTRqcXkrbER6cDFwbTY2S1FBM1p5UTA5Ui9lY2tGaU5oTDlaCmJBMERwek51TWNiYSt6MXdZbWh0bm9XV3MvNE1CTkNnMUYwL2F4N3NTQ0VDdzkycktYR3FoQVdiZURGZC9RaThVVjJiSXFkbVNuYkkKc0hwU0lwcjEzVWpjVVVjSkIyT244ZzUrSExKWlpadGp1MUhqM3FDTkR1SWh3eFF6Q2o5cXhGMWg1YjFHSVZqMmR1SVFFeVR6eU5JaQpGTGpkZmxnNTFhb0JkeDZSQkx1Mll5NkxHYmorNkVscXoyYWlDTVRuakdBSE1CYmhOQVhGZ0tYa2ZCTVdPVkpGenMvWmJqV0RUcUQrCjREUGNGc0JyVXNEWWp2VnhGNW5sK1ozMTVUeHQ4Qks0YUE2TDdtMVJvUDVzbHQzWG9FWnQ0N1l3Y2g3NGdHT3RiSStjU1BqMW1RMDIKdVovVEFkUTJUNHBZZVU1S2pOdzZBQloyRzJDZVFpazZrdzhSU1Q0Um9obmRjeEZmN3Q2T2ZSZGhZYU1mNXU1WERrdEUwV2Mxb2FZdApkZXBoQmh3dUFLb0IwYXdJZVFuQzh4Q0VacDZHMFFpa1FoZzJhaEdjZ1dYNlpGbUx4WHcrRXpWcVUrNjNZT2xieFlOREp6am1MeGtLCmgyd0hFMUhhL1hsUkN4Zk9XMkliWHpjOVY5SVZWQSttSDBuMktqcFhkWlhBc1dwQWxJWmNGbWFveVBKbkRoVWhwdExsYU9LcStZbVQKZStncmJGSklJeUNWOVh1UGtCL01QZkEvWUZGb0ZHOUxqay9rTWJFWERHd0lFN2dkRmR1YW9CUXVwcm9WaG5MdHFBdzNyQWdOa1ZMYwpSRkNmVlBQQXdrWXg2RDEwOHB2ZGpaQnJjUWlNRFphVFV4bFVIdTBHeCtnTGtnTzlQY3dwaGRYYmVSRkh5MHdLWkdmSmx3RjlDR0pPCkVKUnBaVFlOb1cwT0dMQ3dtcnN2QTRvU0tRMDdxTFJFUEsvUzd0QlNvc0tmYit0OXFIUnViQ1NBNGJhanlEZU55SUhSeVVqM0NCSVcKWGlhVFRtN1RrclNka1JrQ2ZDSWNpV29TRGlWaDBRaGlrTzdaYmczWHhaS3loYk9BVW1adFlsVGJnNVp4K1VXWlJGckVUY0IvUE5Jcwo2Q285dGNlT1JCR0pFYy9sWlltZU10bEphTWoxT2Rkd214aXowTUtBeXdFK2twRzlhbWRmbWNubC9qR0FEQnNkeEMvcnN1cVRqVWZtCmNKaTNhQW9hRWI5OXVtdlNNS0dKTklFUTNHaGVvSEs4S0tHSVNSdGIwQlc1akNXVk8rdzR5QWVMRVFodTRBcUxVcjNZcGg1TkZEbHAKUEJ3ZEoxaThIeWNXR2pneVpKRE12TnR1UHpRaU9sTEVVbVAwSE9velNjRndBMW1DNnA1UnVFWTFla0orSHplYnkwSGVhTWFCNGRiawpwSzRLdUYzRmJidHA1SVd6VXIzSys2UGdqUllzOWFnaG8wNUxFZmF5OTFTdGRkRWJSUU5IVjhUVEtUWExGbzlTRTFCYi9PVGpma1QxCmlRNXZ6c3NoVlBsSXpQZDJzMzc4NGI4bzVKZUJTREtYMlk3VVFBaGFsYTN0RnBVeFBKbVM1VHJGb2NoNS9vNGxxb1JVa0o0K1hkRVYKSHg5cTRhYm9sZDRRc0YreXV5YlRzU3RURXRnUEIxM0JMUzJVZTlieU9STXgwT1dMblRod1VhMFAwNFdMN0laSU5iY2RJNjEyYnRvcgpSbG9WaXFMV2lKMEI4UU1VUjZBSUZ4bTNYS0xNSHBiK25GQ25SSDJzVGs1eWUxa2pnVkwyeG9XbytsTlRackgyUllaenpNNjVqQm9rCnIvM0JKK0Nna04wTU9yR3dPODM5NXRnNk5TWFJ3b3dERkN5c0w4K1A5WFRVdEpTeDkxUVpSSEVraXVKY050b2dmWGhLbktzUmhzWGwKTTF6bUZhcVRwTStHWWtZQytWRGhrSmZjZHE3OXNNME1SVVptdlFKY1pFWnJzY0lOWUJ0MTRrd3NQTTMxTW5nTU94WU1KWjRTVXRrTApDcXlKdXhOWittUWVGUTFLVnRSUDFJbWpONHlOTDk3ajdHbnhhTUZ0T0lJUnNUMVBoTXo5eGg2cllaT2p5a3dXeithZjVJQU95NGhWCkk4T2lReWZDSUNoamFvZzAwdEladVJyR1EzRFBHTkNoeWw4Nk5SWVN3eFBtb2hvM1EwS2cxYUpkbW52YWNLWkVhU0hiaDVYb05JTlcKOGl6UEttNktxMm9CU3JqeUNUMG1Ncnk2MnFwMXlyaEk5U3lhQ3RnN01ybHFqb2FZMVhkTldISDRoUUt6NnNZdWxBVW5JYXYwMEhqegpZMDhsMzFrYVFORklFNm8zTVc5U05hdUxqZ0VKa1NWTDB5MXdhckppSENwY3d1U1JuS1dxZkRqVWlhK0dLdGhZL0R5TTFMRkxBcGVPCmpxWENvbmx5Wkl0WE1Wdms4TkJnNVR6SkZ1aGVjRW1GV21zNE01SEVoV1VuRE1ld3M0ck1ZYlpJbGUxUmtPZXM1RkNoOW5GWUV2VEUKazRUb2pUbEsvQ1JYQlZnRThYTnJydnpuZjhpVHpScFYrSk93TnNzVWxRVkZxcEZCT2NwaG5kSlg3emxZU25RSWc0YURRd2JGaTltNgpUenFZbE14YU5LQzFDU1d6b2N2R2VnTWNVNnllS2ZtakNEQS8xZ3F3S0dIVUVJYVlES1Bybkc1MmlQVVYxekRxU0Y4NXJnOXEwaURFCklwWnBwR3YxMDQzeEJMS051blVZbGd4U0krRmtPSGlpQmlESGUwYytMQVRSc0xZbW9acmFzOTE3c2hlV0RyNWxydUpnSjViQWNZWHYKdFFrenQxU05ERS9yNmxrUnk2M2tYNlMra1F0M3R3Q2hINDRwaU9FUUNzU0dQdm1mL1JMb282UmNIT2ZUWTlLalhCejVhYXdldXZWdApKNVBmdTVvTkRvY3FPRkZUemJIVnNiQU02OXBUdUNCY0xpZ3FnVEd0NkxmbEpFSjIzTGplbXBEdVJkNDVIRjh2RFlmRHJoalNKYmFZClRhcGFDclc1MG9XR1BUekp4MDNnWWVUS25Ma0luZ0paV0k4VTNzenR5TEw5M21qUGhPWUFqSzA5VGxWd08rWWdPQT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJaS9nblNRQ0trWm41Vmk2UG1mYUliRWxpU0xDcUVtck5KdWtPYjRRRzJPNENVc2hCV1F6d1JNUExuaFMvNHh6RjE2N1BMUUNBMDZrMwpxdS9FQVVJd0krVEVEc2VwUWVXWW11eC9kcVpGbGFYRFNrRzRGK3dRejZjclB4UzA3NmFIbFVPakNhdXF4c1owTVFDaWlhd0x4Uyt3CnBUQmhEejc2anJ4Y3gydnFlc3hRNGRQMERaSW5oZWsvSzNLMEpPQlNNaUZxS0dDbG84NWMrWlIrZlRJa3g0YXl5ZUtwWGZNQUQ1S2kKV0dqTStRc2xKc2Z1TU1WWGJ6VGlqOThQWVV6bnBEQU12UlMzK2RYV3FVS2ZGUjdjMFBLWWxsNGRuaWYvQ0h1R3NvcHhSS2EzOHVOVwp6K3h4dVJ4MmJxN3VvUGZNNnFtMjYyUzY5SnA2NE15a0RSY3FaZDVDaDBHYmt6MjB5R2xCZVZ2dTkzYkdJTE1BVEF1N25lbERBN0FWCkxpaW9aYzJPZVNGOHBJcDZ4WlVnNWdvRlo1M3lZOGY3SGJKOXVnTGIxTFR6M0FhOTN4SEIyT1NHQmU4OUg2YzBrM1ZOdExCUkJYTGwKcXJsSnJnZEs3RHU4RjVNdW1SdFNrUE5mMVduaFVRaDFXMWcrYUxVc2RoUW9FWmt4cmwrU2RVMU1reTQvemFFNm9xSElVenhOTHExWgpSRld6OGh4ODZEQTBQMTZWd21ISDJkUGVrVDNuYUUxT2tFaUQ4UURqclY5VXc1M0graVZkWkRGSEVDNmZMckk0cERNalVvOEJqU015CnhwSlF6bEFWOThqWWxYSmRNYTBSM0NVRGk0Tmd5UDNzS0lBaUFzMTYxNWNiRWNMQ0pRRUNOTjErejU0aHViVFduRkk5eXFXaDlrYUkKVmVra01KSlFlamJkSy96SFdHMTNWYVFtcHMyeU93MGhXakpSVTZKRXRGVURDeVVNc2FNSzVORUJpYm1yN0s2dmlUUjhOcW9vSG9JUQp1TnU1Z2hJNmMxZzVqRUpVejVET2VQeHdtZFZSZEt6V1VFN0F5UEFjNWtoOEVEQU1COUVZU2VTUjZJaWpvSCsvNk9XSisxKzlQc3BSClBndFZNbUtMMU16d2hxRVU5ekZNRktJUVJXTTU1Q2NOamc3d0w1VnZJSk9rR0U5WWxFbWlTUExhREZtZG5wUjNVQjRkM2s1MmRmSDIKa3pLWjE1alJrYjVBK0JLSG1tUG9UZFJVM1F5WlNHd2VFSmVKa2dxdXcxZDh2V0NnNlNNY0ZnZWdydysxMEtzckhCdDdLcUtOK25wTwpwckFRcW9HMmdpdnJXSHBuWVhsbS9DYjhTTlpYWWQyTEgxaEtjc0hocHUrRS9LdjRIS01yOWNRN3kzS0NLVjM0aDB1c1BLUmFxUU5jCkFibGh4dUtiMVNYd0swWUVNMUN3RUlWcVRCRkRuSzR6cXlwSW9JV2hKcm9mTWRQVklqb3RyRXlNY2pQZWpLb1VBSSt0QWFvcVVLSWQKbXhzb1l5d2puQS95UTZZL1FOMUFubXdiNWxDb1NUdHVhM2Jnb2thUkRuZzdVTFRtbW81QWZwY3VRYlVrNzI5dlYyS1ZOc25CcUxjRgpWY214L04zVzFaVHR5T3hQU0tIQlVpWDNmbVdaV2lzdDB0RlZIV1NoMTVCc3JyT3V2bk84VnBWaHAzYXE2Z2FGSnBUWnorSkhvaytmCkxXSHNBRDdhYjR5bVI3bUxrL2hOektFbndnZ3pMS3MydVp5WlVoeFlxUDJFOTdwSFBCUnEwTGZ0SVVjWUNuTXpZOG1BQk55ZHpNeXcKOHdBLytpVmdFeG5OcGtsU3lnZThIR1pFK1huaEV3eEp3bDVzd1RxclZSeXFSbFRzTE1sQ1Z4dExuNUZETXJhSnBIRHJwby9IckRJcwphMGtHd1NrZEJvNzRWUm54dUVncGg1YVZtc3hvNE1HZzhEWDdFMUY5TGFLK3NZQ2h1cEFlRERJQjFJcEIvcG5zNVM5MGc4ZWd5SmtkCmJ3VTlFdzE0SzdvekRZOEVKVGtKRHdJK2xVbUlXSFVKQWVwMnQ0b2JrTUhhOU1JcVF5dTlRSkc2a0hrSENRYnkyRHRLVFFSL1RtTE4KcWFVNi9UbGVaWEYxRkxlSnB1SDBjQkd2MFdSSHQwdk53bkRaTExhaitKRktNYm9OTWZac2E3S3FocnFoVW4xcWZKTFV5OHAxM3lMLwpUTG51SEphYWNzSnhPcHdoVm82NXJMNmpMckFlbWdLdGZFNVE1bUdsZ1B1L0VDR0NSWW92Uk1Rb21zdFhUU0Yxbml4K0p5ODM2Wjg1CnFtQU9ubHFIWk9VOEtZekZpamltYUxFVEVQYmlSWDA0WlZ6MElVZzhxVXVCakl3WEhwWWQ3bnZXWmFWU1JrclhJa0xCc2VTcE1LMzIKM05idVNtdW9idEtRZGtIdjRoZFAvM3V1SmxoNUlWalIxSHZOQWtwMnFXbWlRQXZOQUI1ZW94bzlPNzBJdlRZVkN0Z214ZEl6dTRFdApXeUJBOUlVNkM5VVdwQmFsTnQzdVJQSUV3YVU1RWNGdWQ2ejZWb3JhMVVVT21nVW1ZN2dLVERmdEF4a1prcy9QZmtNOUNQYnhaWG5VClcyNkhodm1MU2c4bExiQVJucVdtajcxcmxndFpsMG9TR0JQa05TSS93bXc3TmYyUGFralY0M2tvQ293SUtNVjg2dFFjTld6VkJjZzgKLzZ5S0U0SjYxQlN2RkVOVmtCS09wcy9hc3ptSmw1MkZMaTBTZUJ0bzB0aTFtVmM0UWxpS1gyUmxGbjZIMjBpc2RzNXpXb21DTC9uWgo4UC9IM2gxRU5ta3FYRWlPQldwVVZidFp1d1VZSU1qdmVxbEtNa3ZsOFZSd2dsWmdoV3ozSnY0azJ6Z3dLZ2xXMHpnMUMwcVVwV1J5CkFDcEx1ak94OU1rWlMyVVNJQkFpMmpNME1iRFdvUWlyUXRycFVkeVEyL0F0aHdBc25mSSsrYVpJSnpMU2loOWdIQVlXNGxOcU1sME0KSzRtZHNBWFNwamdsckZRdnlwMVMzUDdxWHQybVJJM2pqU2wxNDg4SVNGT0hEY203YWk2SlJMY21jYkxhVWQremZKUytlbzY0WHArbQp6TU5DTVFjc1BOdmNGQ21PUFlXeHg5SWtNdmNLMU9jV1BKTXA4Z3E3b0tRUWZTQ3lwMmM4Z3RDU25YbEZVUm9CT1UzVEd6OVdKQXNVCkw2MzZIdkE5alNnOVoyQVB5U21GL0I5LzdoRGE3MWdpcWp1VnZFeVNKMEFyUXRvT0cvQlpQTUo2eUhKWGtVQmNRYmtMa2FwWnRaM3EKVXg5d1hPN0pkN2d3U2hSUmMrUXF1bXFvWGIxYzFPazRFYnY3cUNxWkRXVlNET2MvK2xtcTlBa2ZrZGdIMFJ1cE9nUk1rUUhEM0RXZgo1Ym5pcWN5UFp1VmNwSDl3VG9vcFdnazF1akxIZFgvUXNMSWJBR0ZjVmIrZ01xRWFnZWhoRGdvdDUvMUpEazhEQ0V6Nndha3B6MXJECnFXZ1hqN2s0cjhEclpHMGZia045RkdaalF3d21TRkg2bjF3cnJtRWY5YnoxNXU4OEtxb2lYZ0dTR1FaOHExZU4zSVFhWHNwSm84ME0KNDlKREdqWnEwM2w4MW53QlVrQU5DYXJPVzdGaGR3Vng0UXFzS1ZWZEpCMHRmclBETmMwZlRremxqYUJpVGc4ek95M1Bpc2NpL3BFKwp6QjdzQm9oRytYSjJGTkh0WWFSN2RZbTZwY1NuM3kzaVlTVlQxWDFTZmd0N3JxRGdicDRWcktyd0NvcEVkNEtSRmtaUitsQVVSWHVpCjBSVGpsNCs3QWxSM0lHVC9FR3BJYXBCS1VOU0VsWUFlWnJTd2FLNW40bmFjOHhCVWRxa3lQL0Urcm53RThwdGNKOEU2dTc5a0JqcHcKcnF5bTQ3ZHRsa2VMS0IrczlHaG9aU0Y3cVk3dm9yR1JmdEZLd1NFWjZjK2VaYldjSlVUajhXeWsxMjVhMVlONEdBZThhdndJOTBRcwpTdFdSdy9LaXBNb1MzamQxVlFzMVNuVThMSFpVdjVLbzVKUkFxY25pV21WMENtUWViK2lyMTU3RFlBeUlwZkhDUXNiS1lRcXZ4Mk92CjU0bFhuYUpkK1V2bFQ2TE1NaTIycFhyc0FOUVM1ZGZkMm4xa3B5TXV4TTRiak9qRFNnUUNZcVkyS05tWDNER1k4OXF6TDdJTGo4OXAKa3RlR1EwMlZGeks3UXpsSFNyWkVxVWxPbG9XaEtHbWs0dm1rdWdpZVpLNGN4WHlSU0F5ZlVOd2gxbjh0MVcwWHVrY3M0OUtFSzJFOQoxazk3NXNJMERKNnJLa0xiOE1UOERGZUUxaHBUdGNrZTdhcStWUk1FTGt5bXBtcTkrRmhKa0QzMWhDUk1hNHQ5bFhMYzBKRWk1ZUk1CmJBbkdvV1FXT1FORkEreDBmWUtBRzdpYlpKVDdGQWZIYXFpWmhCRnRxcDVpWm4zUHNxd3p5aUtIS0lrS09WZHpmeWRtNEZrdnpkcGgKT0tiYlQwT1lkM28ycGpxZDdueFhHVHpkRlJvbzI0Tmw2NzlDMThIeXVFZFYya3FINTRDc2ZWa1lmTmRsaCtTYVh1TVAxVzB5Q2NzMwpEUEkwbmtTdzhaQ2RNelR1Q1pWeUZabERFOFpqWHhFaHk4ZlNZWUZYMlJ1cnFPSmQweUlzbXlzQlZBbGRJVmdEZTZMMk9qaldNdjdOCldjbDZWbUQ0QlFrc0VNT3EwaHlyMUJmdG9vY3p1cUtub1VWaWlJU1l0dTNHRTlLalE5TXpqcmpvcWRmRnI0Z3NaUW9QQjRGanBkRzkKMFJweGIxemp6SUFWNVpmcjBmb2lVcDV5K3RmaitRbmI4UjFIRkxKVTdTazhCU3piMlVCVFNrN1hLNkRvU0o4cTZPanRhT0V3aEtPSApxSVIzZ0N1azZYVXRybFY1eEdua1VHS0hPRU9YRG9TSUdPalNydTNZQ3BwbFBzdFNoRzFCZE96czJhTjg3VEg3Y01wRlVHSTJLOGVyCjVYdFk1RHRPcFEzT2RnenZONlZaV3IzL2ZvNzBibHQ1dFp6WUlQT21RZ3VpUy9wMU0rZ3lLMTk1NzJCMzAxcGNkdFM5V1lLb2h3WlMKQjliTFBTNEdBeUhhM2IyZFJGd3JtV0tBbnh6ZWN3ZjFpV2dicmtBVTRTb1pwWWI0TVZFbWtJQ3lKR0E1YWNTM2xVUm1SU0pGWkFvbQo4c29TZ1BJMTVtaEZWbnBNM3l2SVlKT05WZjIyTTdxN05PYXZBRS9QSlEvOVovK2VFL0pMSVUzZVRLWlRZVEdHUzZvaTdIZ2dadUh2CnJDa0NFSzVESEQ2MndjMjZTVXBtc1ZsQmFIVVF4bThLak8xNlJsYkJzVVFwa2RXV3JJZFpUaExxSjVQRjg4ditBdmVrdm1aUjhVK0QKL00vbCt2L1lVV2w3WkJyR1Vya2dWUnRzWnV4aUs5WXM4ZGl0bjJRcis2TWdLdVNDMkNxOERVSklwSWlJY1RxSDFZNUdBbE9jMVZqUApPN3dDVzE0RnNteU9wVW1zNDJTWlVOOXFlcDBab3YxczY3SWtReUFuZzV1VlIrTWJGZEU1bWpURm5wemxZYVZPbWhaaUlkR0phWmVZCnhyRm0zTmkwSWh0ZEg1TjNsdk54TEdTbTd4Zmp4N2JvTXBOaU9pelg1bmI0VEI4RkR1VW56ZDNjeHhZTkg4TXcxYjBkWmhnRytPR0oKMGhtbjlyOHJ3NzhydlZnandIQXJWTCtQNElTUE1tNkRrQlh1cHdMNGNVdng1Nm1DMTVvR2d4K1QwMlFXV2ZxaDJuQnVFd3Nyb0lBWQpEQzJ1S3RMS24vWGJMdjQvbG53WHF4eHJrcENWV256bnczbEoxTEczWGZyVjVsWUhFUzdEcERRNVRUMGZXS2o4b3VheVNrWnQwenFxCks1TUtxa0VvV0tXSnVsclZ3OFA0bnVWNGIwOTdUMElsYUkxZkVQazFtMFRFYmRRZXFxZ0xXY3pOaXQrbllpUWRrRUVzejRjbnhWbWQKRXJlbTJxdGRrSkdNUkNXSUUyTklNemcrcy9uaEVQNUVLRklFZGtMbXcyVWpyeDMza1k0OHdGY3FCL2Rxa1hpTlFuWEFrSHBSZXo3cQpFM21lUUh2TWJSaitvcHMxc1pRb3hJREhsVjVjZ0laK1pnbUhhekpaRC9EWnovcnhPenB4LzVXai9iZHl0S1BDNElYUlJwUXNEU1d4CkdXRkVUSnZSR0VPMEVjMW14T05tYUpmbHpHc3d0RUdGWDEzbFd5eW1nTHRMdXZ4TjBFWjVKc3VlRE5DT3psT2JuNDNsR3Z2djNQanMKdkpRdzNmUnNNbU00ODBjZCt2SVljN096dVZ0U3BRcmpjamo0c0Y5Qi9FaGVLbGE3dWRuMUNiU21zZG1JRERGYkVOVHNadjNjQzVvZApmV2syTTV0RWUyYzRxYkdwMXFPOWlObkhhR0IyZGRQTXpjc0dtcEF3aVJ1WERiUlJMV0pqY3lxdVJTdTJEY3V1Vmc2OFdObE1ObVpWCkozT2dxS0dvQ2xKMmkvbjJBbVZEQml1ZXM0UGNBUkRjbUd5V0NGUVJmcU1ndncxWFl3Y2tHOFhTSEZHRGtVMHBReWx2UkhaekFkRW0KWktPM1dyWXdINTIvaXVvV2J6NDIyNitab1UwaE13NlM1NEZqTjh2M1hteHNBdUJhT1doc3hKL1VVczlrYkt6K2hrOXdZMktaQ3k3OQpjTEZaZEtiY0hCT0lmWVppN0lKaW85OU5zVHlNTXl2b3RNOVF0US9qYXBpaXlkdStpZGljeUxzdzJRUmlzeDdRNkhIaTY2SnM4SVhECmpxcTN6Y01tWlBqYmhtSHp6NlZuczRITnFDcFRBdGdvYkpHVlJZY2dDWHRVMFZCdUR2WndtR1Jqc0Q5V05FeCtiUXIyY20rL0Z3UWIKcXdWMlJBd0c5bExUd0NCZ3I2UWw0Z3VBVFVHTjlxRjdoU1B6dFF2NjlYSS80UmY4ZW5ablpZTjlEVUJFSjU3YjZPdXh4Tng2a2EvWApWRS9qRGI1bTFWbkpxaUZnZ0pjTkpVUkN2Sm5pYkROUkpTSVdKeDBKVStHckRiNkdSZG1ORzN5ZDZFS25FSld5MDBWMGlRbndOUzBTCmxNNmI3ZGE5REE3d05kYlBUMmlHa2IzQ29vY3B5QnQ3dmFyVGFvRzlSajhPYlJiWWF6YkVZT3p0NWw3TE9sWHZxZz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJaE0yVExQWWZodEE5cm5pOHVkZXdEaW5vemIxbW01RHVza2J2cDFqcHpiMWU1cmx2N0hVMEVRcnFOZW8xbXRkeUczcU4rV0o1WmMrQQpzOWRWbTNpOVpnalhMdUExakV5QkJ1OGFjWTJSODdlTnU4YlpOS24vZGlVekdqd3JiR1BXOVJvbWk0Wk9lUTBuSDI3U05kYTZUTzBFCjZIbzIxY2dHNWhwbHU0Wnlic2gxZDV1bXpiaHVTeDdiUmx5M2kzRzRoNjVtWmFZQjF3Qnk4S2VEYjkya3lIelJyWnZqY3NHMmJ0TjAKMFVCYnc3Qi9LYkt1U01kUTdoMWc2Mmo0R1Z4cjZoejFLVzJxTlhNVDFDa2FhdDBqYXhwTTZ6YjhTdDFJYXlTREZLTnlWZ1Fhc1AyRgpjSEpNVG5IZVBPc2FsVitCczY1UGFEQ2R0VWM1WkhNUng0WlpWME4zTnN5NlJnMVRzS3hoR0cxOGU2R3N6N0ZNc21iK2QraXJvdXFYCkpUS3NuRDhnYXl6cXBzVm1YRFFnbDZoaUlXT3M0YXlSZzMxanJITS9CVVNrV0dkT1pQTHhwS3Y1N0FsR0tGVmFic3o0NGl4ZkRHdlUKeDNEdEdBaHJRRkthZWRVa1dHT0daMlRoQmxpVGlQSW9qazU2U0l0aXQ4Qlh0K1k4NEUydnhpcUhTTm1BVitQWG1FOE5Kalc3K0tVMwp1WnBRa0J0d1hZTjRIZHpxNkNMN3dsWWo1YUtVcnFuVmRVVlkzTkJxSk9NWTY3eVoxWUJpODgwTFFEVk9xUm5uR0FicEdHOWdOWkRsClJZZGltU0QranBwVzVudGhVQkgrQmF1dWthY1BWald1bFpORm9LcVA0U0pWc3lLeXBrT3FidEhIUGtEVkxRcEpiazUxaTI1VndhbHUKVVVvU21Pcm1ibmczcFpvbEh6SXhFbzdWbjlJMlpsUmpBK1ZmTDBRMXpvaDNMUWpWSUV1d1NqMEExYTBxRm5uanFXSFRoMmcrTlF5YQpONHlueGlCRWljMU5weWFVaEJoZnc2a2htbVRvT2VEVUFCQ3BxdWxpVXlORnE3SGJhT3JhTEdJTk1qVSthR2JxYmpBMUZTT1BzcUtzCmRhZ09XbXdzZFlscDlxWlNJd2wvTTZsclpPY0RTVjJDVG40VHFVdG9Td0pJalFha0tsMDBqNW9kU1MwODJEanFqREtVcE4xRWNGR3IKdnMyaXprc3hvNXRFWFpqUWxEeWQza1JoWms5MU9nemVsbUp5NzRXaFJybThJdWltVU9kZFhCbHdhY0JzMHZyMllsQjM1NzNDOW5DRgptWVZ0OEpvWUdVMTNQVGdFYWk3UDJpRlE5eWpqRTMvNmNjTHVoWjkyYmVxaFR6OU9TRzM0Tk1iM21qK3hweDh4L1E1Nit2bVROM2dhCmZsVjZZNmN4QjZKbjhNWk9WelpsbFk1ZVZZOVZ1ZHViT1QwWmhHN2ZEblA2RVJicklLZVgweW92NHZSeUVqQ0kwMXkvSE53MC9od3oKdmVmeGJBMzRoazF6cTVJdjFqUzZSeHBIZlZqVGp0TnQxSFJYQ2ZraFRXL0REWnJleHVCTUw0Y21BaC9ORUdFYXg4QnpiQTYvN3EzcwpHRy9HOURFY3hQUzJCV0U2NzZyUEFFekhxM2p6cFZFTTBFZ2pGbDRhU3lXMkZ3cTY5TU5ZWktwdnVqU09rTnVZZ1pjV3BxRG1nNWZHCkI4MHV5aSs4OUVOSVl5a0hMLzA3SnQxcVQ0Y3ZEVkxCbU9aOTd4RUx6a2RuSGovdzBnWkhiTHAwRG1MMURaZkdLcHVwaW1CTEwvcXEKN1Z1d3BURVN6Zkx0alphR1o4Q0tkcE9sSC81a3Rab0JEaW5LeHovT3p6c0dXUnBlVVowenVBd2ZreUdHTHZiaTNHaHBPUVhTQW0yeQpOSW9sQVVFOFlHbmNxbVM1NHFPUGdHcnpGMVk2bTBpd3FkSm9TUDgwZ1NKSU1NQ3dKVVhSeFpTR1lLUzcxNEpHYllqcmpOVlE1Vld6ClJ1Y0dTcE0vMmkzR2xQNWJsV3liSncwRDVTQTNUaHJIS2sxdUZJVHp5TkYzcCs4bHlXMk9ZOTBzYWJpRzNiMHhpRlZoZWZqVXRiSUsKa05EWGtiKzlRTkxiR0J4cEtDSllUeHdZYWQ2aVZOOFVhV0pPeWpnUTZlS2lwTTJReGhZTStONElhUmo1VUlJZ0RTSENNK1lCU09QcwpyVTNaSlk2NEFBNU5RWTh1UzRqaURZK211bzArNVdGSDE5RG1CRG9hUlJOYy9nUVJHalFoeWlGdWNEVFdHTkVWazhiK0dCb1pzTkp0CnVLblJ4MmhvZEZ0V1h3UXorb3RUSFQ0M2hpQmo4aTVtdFByeWpINlkwZFRKc1d3dm1ORlVDRkltZnlHajhhRXlGckNSMGRoTUJPRlEKV0FGanpGalBSWXltTVYzY1o3M2NlVzFnZEdJQmFodHZZRFRlTDNJRXJoMjcrb0lZR00yL3AvbkV6OEd0RCtsUk56QWFNa2psRWdNWQpMVEZTK1VTTUp2U0JSYVZCaktha2tzSEZJRVlUNnNNYytrMk1wbFVNWVJPaitYaEdiNGNZVGVrSzgyNDNNcHBxbFZibVJrWlRxY0p3ClZDQ2p1VWt5WVB1dzR5Q3ZaN2c0a05GVXFqNnRibVEwVkRpaUZ0N0lhT3JhQlFNMk1qcVI3Y3NDQXlPajhVNktmSHNqb3lsc1pwQTAKa05Hd0VJS3dtZEZpSTVtVWZmb0ZKdlZYMnNob3FJK1VPUXhrTkhYQ2pEM2Z5R2lxeXhoaURXUTBHMll3dm1wa05BMTh6VzlrdEdScAovUkNqYWNDU2JST2pZV0hkNEFzWmpVc1MxRG1RMFJCcUsrWWR5R2pLa1pSN3ZaRFJiSzRiM3hGcnJSbTdVa2JReUdqRUpab3h0YUdXClIrQ01NZHdBUnE4bW9ldm1SYVBObnBvK0hsNzBhbEhHYkdBME54b0hGNDJqRU9oNTA2TFhqT2RxV0RRRGJvejhCaXdhbDBIUjF3c1cKaldLZ2lMS1RGWTFPN3VSckJpcWF2RjJWNGdRb0doRlJkVUUwSjNvVzRmdzJKcHJhbDZ3dzg2WkVvMCszMmo4YUVnMkRHSjFtUkdPMwphb3owUmtRallxY2laUk9pR1JTa3VpRUkwV3p5emJ6aFRZam1GZWRIU1EzbHBCNzNpTnFFYUZTOTlqcSt2UURSeTVXdG13L04xdHJPCmV4QjB5Szdmb2pkdk9EUnN4UlhOWkVQak1Bb0pDdzNOWHVDUGtKZEJoazRVSnlUakdOU0VKaWlvZ1liV1RPS09pQnNOTFE1Y2NUOVMKZGpzamIySHBXQUtMZ0pyQXNmMW1ROFBxQW1pem9XbEJzNWRnUTlNUVVPbk5ocWFWdFVuQmh1WVAxQmtrYUhqalRHaXQrZTNGaGtiQQptV0s4ellabWFZTUt1cU1BQkZYTi9HQnVPRFRMS2FoaURqZzBLaFNFN3dvNE5HK1FxaXd2T0hSUzhmdjZ0dUhRN0xmTkFIekFvVm5iCjhKZ09zK0hRckM3WldHbkFvV2xoSENqZzBMU29zK0lGaDZZU1ZTb2wwNkhaVTZpNXBsS3lEUEFpdXNzSU54NWE2bFNTMDQySDVuYmsKRXdVZUd0T1IybnZmZUdoNk5XcDFhRHowVWJFR0hocVdHcFRualllR1ZVNkg4ZEEwTURvWmVHaGExSHpxd2tNekZzZXFVTk9oMWRuRApNaUNoZXhCbTR1QjJBNks1T0tKQUpBalJpZEJmWS9ERmlXbHVoZjRpUk12S1Q5ZUVhQjVMOWFzaVJNT2diZzQzSVpvdFVpaGFDRUswCkZnRm1SbXNwWE1aaHFHOUN0SXFubW5SMVV5VTl4WE45SUtLNVlKa3UrdCtJYU1xMHhaTTNJcHBLYm4wV1JrVFRvZy9nWWtUVFN0RkYKTUtJbGxjOW1BVlF2d0V3MHVCalJFc2JyY0ZwTnd4OVpKdEVURWIwVjd5OUVOTDFDOW04T1JEUnVtUVNGZ1loV05PTVRJWm9SRGRYVwpHaEhOY0FhbnVHQkVLOERSamU4SVJuUTY3VXpNaUhaMFpCNUdOQ01xTS9BZCt6Yy9ybEorV2pDaTZRVXF1UjByVnN5dm54SFJXQXhJClNCSWNTVmJhcUFpVWlHaVMyWko3S1c5RU5BTy82dkpnUkRSZU13SW9naENkV3JUTHZRalJMSitpeWlZSTBXd05LSTJRQ2RIMDVIT3EKYjBKMDJvS0JJRVRMY3ZqUVgxY0FlMjJBMGZjSnVYL3dvWkVFWk5vdThOQ0o1SXRIb0NQNWQ4QUJrdmgyODZGcHBUVFlmR2djWDVMegpBRVRESWxuNkRZaUdWWEptODZGcFVGclFnR2habVBDNkFOSDRSYmFtQ2o0MEVwUE1Cd1FlR3BtOGdQZHRQRFR6a0N4VENqNzA2dFk3CkJ2WVpRMXdrd1RZZGVwVEl5TnJZbzhOd3NLRTdxc1Vka3Qxb2FCZ2ZzNXM1czhBZzFJN0IwSkJTVDBXd3RtdlBkcHJVV1pzSzNhUFUKTkxicTFSbXNtd25kM2Z0Nkk2Rkhjc0lxU00vb3E4MHA1Z1pDazZpODZqR3lOM2FUUHB3NDZHMjRhZERIYUJqMDlIeStJYytBT2FtQwo2MEpCaithdytONnFDSHV6U2REYmNJT2dqMUVjNk5HdFBnME1OS2dTQkx2ZEZPaU54QTRJTkVMUFRBa0ZBeG9HTmErN0VORFlMVGpPCkRCN04wTzRFQUhvK2Z0MXYvdk9JRmx1QmZ3YkVSWDBEalg4R3RVUjB5b3YrVFBTdkEzU01wMndXY0xDZlJ4SlM4U0kvdzdRc2V5TUUKQ0lZYURlSXh2UXhEbUcvczgzZ2luV3ZxODNCRHBBMTlob0Yxb1RmenVkc1AyY3huQkVCWm94SEk1eEVmN1VFK2I2UmFFSjhCWldOYQpPSURQNElSdUZuWmdpV2tzTWpJaGo5M0VBalh0K2NNZ1R1Rk5lKzVKZVYrem5oR1FaVm8vVU0rNllCbnVYS0Rxd1FMMGpIUzMrbkdaCjh6eThTbjFobnRuM2VkVkRlZTVhZVczR2N3L0k1bzE0NWluVkEzakdEV1lGalBITytMdll1MjFuSDJGK0F1N2NBNmtiYk9mcktKdnMKM0NNekdtRG5FU21rb0RqdmNlREdPZ09ZcURKZVU1MHg1cVViNFR5alYrTE5kSjdkWXZTOTFUS3lQWWpPa1BJMWs1b0Q2RXk4NWF5SAo1d3hEOTAwa3pubUdoT1RHT2MvZ1J3Zk5HWFVPVE00RnpCbkVhdmJqdkZET2k1SHNja2pPV0NvejcyV1E4Lzc3NWpnZm96SE9RTHBFCmYyRldiczFpWXQ4TmNWN0JTUXFHTTlhUyt1cUQ0WnlvYlhjenU4MXdobFVMbUlpNlVYMURrdWJPcTJONVpEanpidUVMYVJPQlZJRncKaG1Xd2ppQVl6dHlHSC9waE9HTUcxZlFRREdjMGVIZXBMdEw4V05Qd2hiajV6UitYUjY3SXhqZnpsSGgzQTkvTWd2NFp2T1ZkUkFLbgprUmNkL0daVzlFOURzTlZaTUVYWDdadmZ6R2ZKUWduem0vbEtOQU9pSlY1T1ZqTysrTTFzRXhsWG9GQTNQRDBPWlFZNGYvV0RmdnpoCnZ5akFtWEZCVXE1dWdET3RsRGdFd0ZuUndwSVBzSmxoUURXTHVCRE9ERmRSSHhRSVp6eFgvNElSenVBeDhnVzVDYzY0Y2hVWUJzSDUKckdhRDRLeHZlbW9DUFlGWmRueTFENlhNV283Nnk3WmpsdDNPU0h2RkxNVmgyUVJuR0tRYUNJSXppMGZWOGVFaU9PTXFwVTRMZ2pOZQpPMEdiQXVFTTEwNkNzcHZoZkR6WVlEano5UXlwaGdnUFpGSU1wYkEydy9teW11SE03cjBNL1FmREdSYkp3MjZHTTNFUFZCd0Z3emtSCnErMEtldlVTaDZDV3c4dk5jTVliYXpXR0djN1U1YW42MVF4blBGK1ZJOThNWjFTbmtlZ1ZDR2VVYWdtWDdnTHI1UVkvTDRBejFHWEIKbDZmSER6ZWFRMGZ3bS9HZWNIMXk4NXNaNE9Gd0hmeG1CbmpFSmZCb1FVdHpEZWlwbHFMVnJYMnA0K1N4V0NRZC9HYitaSlp3WitPYgpHYWlNWnZRcU9Yc2VSUUUzdm5uTllHd2ZlalBLYVlSWE5yeDVEcTEyTjd1WjVUVTg4d3Zkakc0d0FrR2IzQXpwSkN2MUE5dzhvdkx2CjVqYVA3dUV4c00wamlwZUQyanppNDdtb3pWallMQ09hR1JRWkp0c0dzaG5rUE03N043RjV0Q0JJR05nOGhzdWlqV3NHSW94Qm1rTnIKUnRzWURzMUJhNmFzZ2lYL2hqVjNCeDlmckdaUXVoZzNDMVJ6TDI2OVkxQXpzVjVENWRDYjA4eE9SNDl3enJ3c0hJYXZZRkNhMlgxKwpLSm04MDNJOUtvQ2p0SnBpUDBNWVdCZUpxNmlQR0FrYjBjd3U3MVdmTlFOUVNOVHhXd3BBTTZocjlFQnZQak95ZHdRakI1NFpFQUhHCnhJTE9YS1A4OUlZelF6WTFTcWp4SVBNTHJ6RFF6TVF3ckZCM1dqUU12UTlMNHdQTXpGWmZ1Und1TS9qQlZCZmRXR1pVNEdxTllDcHoKYTk0cW9NeFlGN0hFOEdZeXc4Z0ZTRENaSVYxcTVpaHoxUXh4azBpSkY1SVowd1RCOUVGa2J0V0Z0ZGR1cW1pOWVjeGNpaEhnWUc3TApYamNFanhuS0VzN1NONDRaVjhCZkN4cHptNmU3TnljVDFGV0pvSDNCbU52d2x4WXM1aGF6VjZDWWNUN0ZqTWFkQk1lc3dnS1RJREZqCktocVhxTE5OZDd1NE1jeHczclg4TjRVWnB5WkloQ0hNRURuTnRGNE01aFdMdEdBd3J4YTk5NHhnWHQycDQ0dkFEQzJ4Q21rTllGN2QKUHg3OFpVRWJ3ekMzVGxqTm5BeGZYczRGYlBZeURQRmJHNzNNUkFmWEJvRmVqbVRFSmk5RDVFWHF4dzFlbmlNNktwaTd2QUt3R2RqbApGWUh3aTdxTVJJdmVtNzRqOHNFY0NEVXoxeitVdzkvVVpWcEZFN2NNTHBHRGE4V2R2Y2RxanNsTlhZWjFzZUEvcU10a1JQbTlrQ0JpCk4wRzVvY3ZYNFF4ZGhrWG9wb0F1cCtSQ3R4ZDBXU3VmdFE1MG1mbG15azREdWl5UWdaVmxoMDhQUDVEQ3pvQXVNdz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJemNzNUxhRExYejNJQ09wOVAranljck9wRjNONUxRRVdObklaVmZPc2p3bmlNcHlIWkFUejFob2hIY09VVWZDV1lWQnBzbkhMMkkwSgpxcHUyek1MWWVsakxLNERKZ1ZCV1FQRmlMK3Q5aGtpVEphK3hHYmlQNUFZSGFmbEtuRjJrWlM0TnFJc0kwaklYWkV6aEIybVpZVTZYCmtHNWNNa09kQWs4YnRNd3pVNWU4Y2FLYVJ0dDkyck1ieXF2KzhUQ282R2RFaVVkMjZjbkZXV1k5aCtxdHpGbm1aUS9XVjVtenZDMDMKWnhrN2ltd1NuR1Y4a2FUN2I4NHl2S3FxcXBXTHN3eXIydmtHWnhrV1NuazNhSmtPT0IvUkRWcW1sNWExR1JPRW9EU296RTJZWlc3QQpSM1pqbG5saWpDUUhaam50bmlTQldXWXBDQWZkQzdOTVkzVVhCdEhVWU5Gc0pjd3lCejBXbzl5WVpUcVkyVUw5b2hWRlVzbjJ4aXpECm9qS0ZHN1BNSmJEbURHT1dFd3ZoaW5TOU9nbU1IU3hkdURITFhCUlREeDJjWmF4a1dRTVNtR1VsZFV0OVk1WVpOeUdwSXpETFhDS3AKVzRReHkyU2pWY3MrVDhROWgxWTZNTXRrbzAxdnhrZWJnd0oyWTVhcEptRjB6SmhsR29xaHlnemdjVWVobmkvTU1qS1d2di9HTEVNTwpvczVOZ1ZuR05ycGhOMmFaYU1VZVF6eFRuY3ZoOGhWc3B1VVl6QTFaSmsyTGxUVjd1OVlzdEEvS010YU5lbmx1eWpMankyUTlCbVVaClBxWWNqYUFzSTNhZ09OaE5XUmJYYUk1RFdhYjJUNStnS2N1MFVFcC9VNWFscE96elVKYkZ1Q0pNeEpSbDdxa3lxNHV5ekJCNXdMWVgKcGU3SnE1MmdMSE1oS1hqNFJWbVdmSExOUTFubTZVZlJLaW5MQ0dBSmYzRkJsbUgwTHdxeXpEQ1hUc3lRWlZvWUVMb2h5N0NLOVdmSQpNamZUdlRCa21jZE9iaXV4SWN0YzNZak5Fb3pMc295R00yVDVHRzdJOG1VMVpCay9vQ2hMd0pNWkxsSUMvNElzWTZrbzcyNXZsNzIwCkNzYnlNVnlJNVcwTXdqTFhjOHJWbTdDODM5Y1hZWm1wWnhJR2dyRE1rbmVxQm9Ld3pPUmh0TTdZZWtsYWwzMUJmZlhJSG5LMUpNSXkKYzREeFp4VFBTS251cDJHdVkzT1dMUURMM0lZcjNodXdMRUh5VElldzdDREhQSVJsUnFybUo4QXlzWjFQam5ZRnlYa2hJaDhDc015dgpMekw2VnplYmFzY2pBTXV3OUdKMWdFaW9yY3FkZWdHV0dSc2ljU0FBeTdSb0hoTmdtUVlKRFM3Q01tOC9NOWFCV0dhcW00SzFRQ3dqCkVLQkt6aHV4VExTVnV6T1FhZ3VWV1ZlM1FCT1dNZGFwdmRsTldLYXVJMGZ6Qkk0Q2NIMlVYVGRobVRHVGt2SWJzUXdybWVBYnNVd0wKSDFJd2xtbWhRUEZtTFBONFZPVUVZNW1SRTVWWHI3aE1GL2E4R010MGFMTjdTVGc0WnU3T2hpd3prZEJHOUdhSW9XZGJBN0xNR1c3MQplaURMdkdmc0xYOVRsbUhWaXhhVVpWaWtsQXJLTXJlaEJPcW1MTlBLUnhXVVpSSDJSaitVWmNvSTFjdmpLbm1qTkpMMTFFRlpobktICnc4cW1MRE03UTRmMnBpd3phczJLKzZBc3M0Q1hDc1NnSjhPZFlJdXpGMldaSzZkMEdWZW9NUUxLdVEwM1l2a1lUYUpDYnh6eGNneFkKL3VMVmY5ZUZBMi8zMHc1R0RXdUd3cHVidm0yOE1wNXdtWHJFb2l0M2R4dDd3Wlc3bWF1YnJkd2RNTjVvNVdsVXc0dXNQQjBaM0lCawoxNmtmc3ZLTWQrNEdLMDlHNHU2OXhNVGRWT1hwOHBJWFZCbEZZMVErbWFuTU42VGxRQ3BETmNKSTlVMVVEdER0QmlwRHU4VWhMVURGCjJmV3ZOMDhadG1uR3Nwb3VkUEYzQXFiTVBOSXFiNVp5ZHVYTVppbkR3SFphZ1ZLbXB0NGg4UTFESTUwYXF4aWhsTkVSWTZ4MG5lQ0sKdGU4RlVrYmhBc0d3d1ZFT1BOTEdLSmRvOUh4VGxDR2NZb2c0SU1yVUI5ZDVHTXJBSjYwWFFMbTBjQ0xOVHk3UmxEZnd5VXd3T1FHNgo2Y2xJUXlzN1pYZ3lLZ0thR2NzTTZ4WFRPbTUwTW15azhRVTV1WVRRTDhESnlFa2htdkxpSnFNVUp2cm1jbnBGcWtFWlI3OUJLRG9SCklmdUNKdGRnT1FZem1WRzlOUTR5R1hvUFpvbHZZaklTT1BTNkE1Z01DVXEzSTA5SlViZDI3b1ZMN2srUUVFMUx4bTZNakFjc0dRZG0KYU81bUpUZEwxallxdVVYUHpTQWxOODlTTDFJeVd0eEZZb0drWkdoWW1Pb3pKeG41NTZGLzM3TXBWMW1QdmlHc2ZvZEpUTUZJUmxmMQpyckQ0cnBqQXNpK0hiQXNmeXpBRmEvT1JzUmY3b2R4NFpBUmNsRUUwSFJtT0FSbnNBVWVHdms0bExSY2JHZGZhWFF0QlNDb0ZLazBCCmRRYXFJRDFnZ1BrR0k2dGlySDdiWEdScUJwem1ZZWF6QzF6eGdpTDNhQWtTVE9SZC9oNUk1RzRveG91SXpBWXFQSmFCeUtkWTJUemsKNGdMWUZ3NjVCaDR5YU1nZzlETFZHRERrVmc3b05WaklCSzF3eGFLSy9CWk56NEtFM0VLdGVvT1FZU3pFR1p1RFRQWUsxeS9HSU9PMwoySmJpeGlCWEYyTnNDaks4TkhXR2RDS1N1ZXVscGRkbUlDT0x3Ynh3SUpCQnRlRjNGZ1RrRW0zWGJ3QnkyYzM3ekQ5R2hZWkltc1lmCmsyWm1odkdtSDI4WVVjQ1B5NGlwejZrNUdBaHF2ZEhIZk8wc0RlTzhBclljNWRzQlB0Njg3NXQ3akpveTFSdTZLS2RrVDB1aUhtY2sKcEl4c3Zwb0xPVTRWekdQa1padTNVaSsvTGhibkRUek9YYXIrelR1R2dSQjk0WTV6Tk1hOGFjY2YwenlyQ3cvc3VKb01HYXpqeGdGVgpOWDRiZGN6V0NtSEVYSWo1Z1VXdVFUckdPNTJOSzk2ZzQ0Wkt0NmVlc2tJTW00T2ZrREhIaUM0OTVpTnZ5dkZpTWpSOTI1RGo2azdlCm0zRThWQUw2Umh4L1RKakxnamNoanBPbjVTQWNXMmY2NGh0UExxTnN4TFFsR1o0b3lNeVNUWUo5bmJTTGRURmdJbWxKVVUyNDhmUkMKTHVER0VTZC9vNDJsK3pwazR4R3RDZ3cyenRIaTlzVTE3cXF5T0ZoakN4TTMxWmhKQUpVcEhxZ3hreDVSbFlqRnI2R2ptMmlNdHlJWgo5TENCeGlnSlcrWTZrR2VNOTlrTEVYMGxIUHUwcHRrMDQyS3ZLV0RHT1h5QVlCbXpSdDBqYnFDTVVlL1dWVzFKVHdtTEdyNlNtMk9NCmdqT2psQytNc1NYZFFURnVEQktrQXpIbXFvcGxxamZFV0FxU1VRN0VHQkhVajNWYVB4Ump5am1mc0lUc2lWclIySTQxQkxEVTZuSXgKUHJpdi92ZjM5TzR4K281WVNKdGlYS2NiVGdiRU9GaGxtMkhjY2tocEw0UXhBZ2pGMUVsNjFjQmRVTTBUQUdNU09Lb05JWlVIOGtKTgpndXRtWUFpcUd2VGlscDNKdTlqRkxiUUZSaGNqM1VxOVo1Q0xrYU9VQnZ3Q0Y3ZG1mSTlqNTFDTDBzTXhrUmo5aHlPeEY5amltU0s1CkxCc1JzWFVjYVBGS0NpQzhtTVV3c21vaWtNVXIrbmNFc1JnZ1YyK3dYZlNWUEtjR3JoakZXQXJlZVN2OEE5TnhONng0VHJkRURsYngKcHZNR2doaG9DcnFYTjZsNFBQWm93Z2loTUhOeHdTbmVoaHRUSE1aTktSNmV3VGQ5R0NKZXJuNXZTREhFdHdyazJEaVQ0YVJDRko4LwpMMEp4R0RlZ21IRGxWUStmZUFSVzVNWVRRNHdzTXBEcHhLTTVZeDEwWWhpbWVickhLNDFlMzhFbUhxRk9DaER4YU01aDNtUmljS2NDCmFZelhld2IyUDdqRStHdzJlamV3eExQWm1RNHNNUTNsd2hJemZwM2VVT0laSkNjemlhZmJnUVdTT0ZxSDMwQmljQmlWblRhUEdKcE0KSmhxTkk0YjZrdmZ3cGhGdllGYkFpSWxjWkRyTUxPTHBEL1dGSWthcFVqSWhORXJuMU1RMFNNUXdaRWZQTjRpWVJzeEV3U0VHMDRrSwpFbU9JVjdFRGVGT0kxOTBXRVI0TFVjOGpIUWd4Uys3eUcwRU1QQmREWEVFZ1J2cGVsUm9HRUVlejlSZC9lQVpITmZERHk4dXFUUjltCmxTQnh4QWMrYk5iMFJnL2poRlkvNE9GVkpObDljWWZ4dWJGWUxyRERLMHBoZ2pwOEhXWXpoMmNrWkFNNVBKMmEybnpoR0FaZXdHR28KWFVVME5tOFk1TEErTG83d3FCNUxiOXh3RC9adkdKRzFacXc3WU1QVW5NLzZaZzBqZ2ZTNDZUQkNIZmc3R1VnOEpjQncyZlFGR2taaQpLa3FuUlVOOGxIVFltR0drdUpwNzFXMHRUM2VnZTBPR2V4U1dCV040RzI3RThER2FNTndOTjlwOFd5eHBrMm0yR3pBTUtEN3h1VjZRCm9LQXAwSXYwVktxTDhsNXdZWkNqVk5SdXRqQldQQUpXR2kyTXRWQk9iN0F3VmxPcDlNTVZ4cG9yOE1QOHlxckZCQytxY0xNb1kwT0YKZ1JscTdTQ0ZSOUN0RDFFWWdpWWlKUU1vekxXWlM5dFkxa3h5YVpsdm5EQzlzZFFPVFZncjJYNWd3bHpyanZ4bUNXTlZ2SXdtNXEyRwpRUVg5UmdsWEt6TmZKR0VBcE9LOCtYMUVIbXh6aEQ4N09qOStSeWZxLzM4WTRTOTQ0RDl5NVBydDcvMmozLy8xZldBYzZBOS94Zi81CnMvL3JMMy9SRC96MGg1Ly85SC81NWYvVnNkdno3ZS85czEvKzdDOS9ZNi8vNFM5Ky9kTi8rc3RmL2Z6TDcvLzYydjZQL2NZLy9hdGYKL3ArLytPVnYvdlNmL2VGdi9yM3B4MUczOE1kKzRILzdpNDlUK3A5KytZdC84Mi8vK28veWttUFRQL3k3UC8yNFFmL2pYLzNoOS8vUgpiWC82NVYvLzlYL3l4cmpJajd2eUY3LzgrLytNYS96eEQzKzVyeEZWM1IvRDR0OTZqZi83WC96NVgvL2IzM3lXLy9DSC8rYnYvNlB5CnAvL3c5My91L2ZCM3c5OS8ray8rOFB0Lyt2R1MvZlhIZS9hNzM4bjhEMzc1TngvWGRmM0RELy9rMytGZnB2N2xIL3pWZi9qMy96YU8KODkvK2sxLys1cHYvK0piK3V4K2ViMy8vNC8vKzVkLzg4QjkrZUlHaG4yLy84OGQvL044ZnByLzVWci85NDIvL3gvLzVmUHR6YlBuUApmdmpkQktPUS8rL1gvUWZxZ3JDUS93a1cvRUZ4N2g4emYrenkwMzJjbjM3NC9jZXgvOWNmNEZ3endmVkFmNWIxSDFoK1Fwby9vTndGCkRPaGp5ZmV4OHNKL2ZJekRuUmJHNXY3bG4rR1lrTkpYMUgweGlKVSt4aG1lSmNaM2xHb2ZNNHhWMkt1SkFNTEhEOVpQeHE1MmNELy8KOERZREZmSHhDKytqb3BqbFkreDVuNEdOT3NDUU9QNjlyWU5QNzZNZTQrc01qdms2MjNQVTY3cSszSU9mZi9qWFB3Q3N0T0JrZ2lySwpmQmpVUFFWVEsybmhINjcyUkluRXgvSVhtWEFVSUMwVWNYN2MxL1I4KzhmN0VjS1BUY1FuUDM0Rk9EdTAyd3dqWk1YUUlLcHIyY2RNCjlEWW1wVDk0YVpmNUVTWGlkZFNQNldqaEpYaWRRUmgvL3UwVCs4dVBLNDUvWVAwVEpybE1rRTRjdTl4bW53V1dySk5GRkwyblQwYnIKaC9ZWjIweVFWLy8yT21yRGVxR1ViNjh6Q09QUHYzMWlQdVAvK2dMLzhSZTR6cHBOU3B1TXBIeXN1NEd3UVRGQnhidjdNUTRRQnRpZgpnZGc2NFFFWUxEUTJBSE9ITFA2blcwdEJSV3J2VTRBb2dVdWkrMlF2NDMxaGwvbmNoT3VvNTNaZFozRGYydWpmOE41MmtxdjI2YWpICitEcURZNzdPOWh6MXVxNHY5K0R2T0RiOGpxY3lRTHo3ZEY5eDJ0QnJ2SDRmRjRnby9ldE1MK045VlpmNTNJSHJxT2RlWFdkdzMxZjgKQkZ6bjk3YkladVpQcit4bGZKM0JNVjluZTQ1NlhkZVhlL0JkWGxsMjlYcmE1L0VMZ3c0cTFsN2pWMlBZcXJ6SHI4dDRqMStYK1l4Zgo1NmpYK0hYTzREVis5U3hGOW50YmxuWitQdW94M21kd21jL1pucU5lMS9YMUh2eXNvUkp6Q0pRK24yNE81cENuZkRvSXBvdktMK1FlCjNJL3hOYmdmODdtTWM5VHJnczhadkc0T1pyeUJRT0pyVy9MKzE2ZWpIdVByOFJ6ejlTajNVZStIL3VVZStPWmN6KzJlcTY5bmZPYnEKOHpaY2MvVmx2T2ZxeTN6bTZuUFVhNjQrWi9DYXE4OHp2cmZkYjhOOTFHTzh6K0F5bjdPOTNzZHpYVi92d1pjMzUzVnpybWQ4T1RMNwpiYmdkbVdOOE9UTEhmQzdqSFBXNjRITUdyNXR6bnZHOTdYNGI3cU1lNCt2eEhQUDFLTS83ZUQzMEwvZmc1ODhlU0dNZmkvYlpBd256Cnk2dG9UTEYvY2tzdzIwaVA4VFpia1BjK0trdVgxbnYrRCtNbkQrVGVkbnNWOTFHUDhYVUd4M3lkN1RucWRWMWY3c0hmZlpvOFUrL3IKdmg1SDRmcjk0MUpjWjNvWjc2dTZ6T2NPWEVjOTkrbzZnL3UrSGtmaDNuYTdGUGRSai9GMUJzZDhuZTA1Nm5WZFgrN0JkNWtteit6Nwp1clhIVjdoTzRYZ1YxOGxleHZ2Q0x2TzVDZGRSeisyNnp1Qyt0Y2RYdUxmZFhzVjkxR044bmNFeFgyZDdqbnBkMTVkNzhIZC9aYzluCmdFOW5sQzlEUVpoZm4zZEhxWW85Z21Qc2dvRjhHZ3B3cVBxTTkxREFaaGFwdmovRU1INGFDdTV0OStkOUgvVVlYdz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJWjNETTE5bWVvMTdYOWVVZWZPZkZ5T3ZXbnUvMk9vWHpoVjhuZXhudkM3dk01eVpjUnoyMzZ6cUQrOWFlNy9iZWRuL2g5MUdQOFhVRwp4M3lkN1RucWRWMWY3c0gzWEl5ODd1djVhSy9mUDUvM2RhYVg4YjZxeTN6dXdIWFVjNit1TTdqdjYvbG83MjMzNTMwZjlSaGZaM0RNCjE5bWVvMTdYOWVVZWVHb0hXUWdKbkU5K3p4QSsvNVB6WklYNzI4MDZ4cGRMZHN6SFF6bEh2WHlaY3dZdnYrZnJpVGtjTXI2NDl6eHMKK2JUMjRRbG8yMnMxY1l5dmxjY3hIMGY4SFBWeTJjY1h6LzUxT2pqRmY2NVE2ei84L1orL0FxMy9LZkhYOG5lTHYvcU9mUXJDbmxncgozckEvWW94OWYvcHl0Qk9LL1RzSEMvSHVkcTNlcVh3cForN0lqUFdGMmZNQmlKVmVaNmYyeVlnMWVXMW43ckFaNi9kUnY3MlAycFQrCmY1K0JqWHZ1V0dOODJuWkk2ZjArNmpHK3p1Q1lyN005UjcydTY4czkrRzV6Qi83OTA2MmxOMUUrblFMOURyN1kxOGxleHZ2Q0x2TzUKQ2RkUnorMjZ6dUMrdGMwNjIvZTJVMEsxOTFHUDhYVUd4M3lkN1RucWRWMWY3c0YzbVR0WXRmSHB2dkswODZkWGxoZFlQcjJ5bC9HKwpxc3Q4N3NCMTFIT3Zyak80N3l0K292YithZHRwS2NQcnFNZjRPb05qdnM3MkhQVzZyaS8zNExzRnNsQVo1ZEd6ckJPT1lJdkFiZjZkClJ0dzhhZ3ptWlh3eW1oYTh3eEUyUHlvWWVSMlZnM2VhMzE1bkVNWWRqb0JvOGIxdGtScjJmZFJqdk0vZ01wK3pQVWU5cnV2clBiakMKRVUyZTczMXpPSmUyVHdmaHROblQrK2N1NDMxcWwvbGN4am5xZGNIbkRGNDNCelAvbk92VHRrVWxZZStqSHVQcjhSeno5U2ozVWUrSAovdVVlZkljVjkzNDVJbHQ1V1R6aHYxOUN1d2J2aDJYanA5ZmwzbmEvQXZkUmp6RjlmbGZIU1ZEdFJ4U25lRm5Pd2E1WDRmenNkY3Z1ClU3eHU3N1h0ZmhEM1VZOHhmWDVqZklyZjhjT1BYL3YwNFlmNWRZTjREYXQrTXZwNlA5M011RGV2bzM2S1Erb012c1FoOVNRL3hTSDEKME82akh1TjlCcGY1bk8wMW5KenIrbm9Qdm56NHI1dHpmYUxuSU9mUlhEOTNHZTlUdTh6bk1zNVJQOFVoZFFaZjRwQjZoejdGSWV2bgptM01aWDQvbm1LOUhlWWFUNjZGL3VRZmZZU0pQMGkxK3VxL1YzVHZmOTlYZDY5NzM5UmhmOS9XWXp4MDRSLzJVcU5ZWmZFbFV2MC9zClNsU1B2bGNYTVFYZzJDbmZacDlGbiszVEZIQ01yeW5nbU05Z2ZZNTZEZXZuREY1VHdOY1QrejdEd3ZhTXcrWDd0RG9JODh2anB5Zm8KNU1BeDJoUDh0RHFRMzdxRHpENnFQZHozR2RqNGFYVndiN3M5L3Z1b3gvZzZnMk8renZZYzlicXVML2ZnK3dTWjVSYS83dXR4NHEvZgpQKzcrZGFhWDhiNnF5M3p1d0hYVWM2K3VNN2p2NjNIaTcyMjN1MzhmOVJoZlozRE0xOW1lbzE3WDllVWVmSzhnc3ozajE2MDlmdngxCkNzZmp2MDcyTXQ0WGRwblBUYmlPZW03WGRRYjNyVDErL0wzdDl2anZveDdqNnd5TytUcmJjOVRydXI3Y2crOFRaTzRSaFpzajljOUQKUVpoZm56ZGpZUG5UVU1CNFdadWZod0ljQ28yRTNrZEZGTzc5R2NyMGFSZzQyKzBQK3o3ZU1iNSsrNWl2OHp6SHZLN295OVYvNXhEQgo2NmFlTC9ZNmhmTnRYeWQ3R2U4THU4em5KbHhIalp0MS9mNjVxZWRyUGR2dHIvbyszakcrZnZ1WXIvTTh4N3l1Nk12VmY4L2d3T3VPCm5nLzErdjN6U1Y5bmVobnZxN3JNNXc1Y1I0MDdkZjMrdWFQbkl6M2I3WS81UHQ0eHZuNzdtSy96UE1lOHJ1akwxZi84bngvOS9PZS8KLy8yZi9mckxuMzhicjhqbmYwYnNzK1lGYVMyazV2Z1BNR2wraFJXNE45U3pIL05Qbjh6dFk5SFRxOHpuR0w5dDNZZjRQYy90ZXdoVApYK2N5MUlKN256bmNRSnJseThrNGJIdjZyTGExNTJOaFFXTjZxRytYbWJXR05MTkYrK2NyOTYvOUJEK3pFdVVHTGdCNmxINmNlcDgrCkRkUzNmTHpxTkpQQUxDUDlRUDBrcWdwa0pMSkJQemhMbk1kZ1AwQnQybVAzanlGcCtkSlFSaVBqeHdyVXY4OWF2OWo5K2ZnUS9mc2YKYjVvdmVlMkRLdEl2bzI4TldSQnhGOWpTeDNjc04yL0ptbTM5UHFveGZMOHdubXJMUkxxbHpPUWk2cmJnZWZxazBKRlZScFRmK2FxZQpNSDQ0OXVmeTBSalo1Lzh4SHNlbWJYai9jd00rUFlBZjlXVHl3dzVpdEdmMGF2N1ZWcmFTcHJVcGxDL3JTUDQ1ZmVNeXJoWGI1dDYvCi9kWlI0OWZtbjlUMCtCK2VqNFdCZjI3dTE3R3JlNnFOV1FjQjdHcHVtMTREZzBGL2pQM0hpQzJmN0UzWnhVZkhaSmp4dDM0L1Rnek4KWVBTRTBXYWtGcDhZY0p5NnVLWWlVaHRSKzJmamFtRjhZc1BGK3h1YkxwOXY3M3QzRkJqS0JvVDJiLzcrZit6NXNORUt6ZXhuRUErSQp3RlZ2WGVOWlZML1BiTGd3LzdZSDlBQTNuUDJkZmJ4YU1kS2gyVW4zUzQxMXFXMTdhR0R2WEJqQjBXditKTmd5N01mWVArVnNNMG9DCjQ2RHhwZGFoczMzWURPTExkNzZFRHRQdkkxTm8yOXpuMVBmdTcvUDNoU1hVdHlYZmRiYUEvelhNVCt1WCtTZWJpYXlSK1dNMStzM0cKN2tmTTFoTzJvUkJkeGhUajQ5ZGY4MEFJTGdES1RmVVBZTjM5YW5NQ25rU0h3WXRnWTA3K0tqaDgyUWpJc0o3YzhnY0FhNHJ4TFkweAp2T25UWTNRaGM4REc5SGgwWUdvNURoQVBzK3RSeDdZamJnNGV4bTlld1hsMXh0TThtTEtUWGJ3NnJGV1Z1UTNQZXl6STJXYmdER3ljCmNjVWx4dU12eDQxSE9sV0FyWnUya3VlMlpCcTB6TlgzY3FvUzA4K3B0REEyRHpDRFk4RW40OHc5NzcxekdOdGEzMzd6NTMxZTZBUFMKdTZiMDUxRk14ZGJxTDRQUm1EQjZXbGdqNVczci9nUldxejR2ZHV2TVBmYlhKNlFXbmkxKzY5ci8rdms0cmUxcGdEQ2FQQVV2QUJwawpiQ3ZHRVJobjgzTm9WWGVMeHNldkNFSDhYNHhsZVdiODhsdCsvUWtnS2I1bkJYbWlYOFA4ekI3bXdXdWpjYVRmTU9ZUnhuai9VWFpaCnVzZlpqS1lETm83d3VQQ3AvT1lKK082d0VWb002dXlTK0t2Tk9SZWZCRWtZTXNhOGp6ZXNaaHViUHhaOGJUNHhTYTFHekVJbE52MVkKVmVUM3JQTDFCTTUzeFQ0akdoTFgzSjhWdTk3RWlOajhxYkFOaDQwbHZwK1AxN1Nlc1ROR1ZLNUlQWHBxZW53SVMyMnhxZWJjTDc5Lwo3dGo3Z24vOURXdjlqVnZ6TVhyOXE3amxvNGNaczhwUFlVWnJKcG5yRTNlSHpXTmtMSG4ra1Z1dXQyeXFiU2x2SlNlUlg4T2N3azFnCnRiMk1wTHZLT0hRZldQd2JiZ1lCS2ovK0VPWmNZdHVSWXR2Wi9HTk43OExYRTRneks1TEllSnpQZnBqczlWNUx2RkRObjJFQmd6S0YKZVNUOVhoRml6a2FOUlYrUDZ4OUV4ZmFZNjlyNlY1dkRKMmppSmRyWTloQ3A3K1hEMXNyK3RSYnpHOHg1blRQcnNTMGJHK2drMGd4agppZy9XbzZSL0MyT2dqeHUvVld1TGcyclErWHIrY1dHZ2J6emorckZmd3h4dUdLdWlaUHVZWDFaTTVuT0ZjV3lmc1V3UFhEQzNlQklzCkU3Y3hMbUZsVGE2d1BUR1FrTXo3NDIrZmxrZStpYTQyc1lDaDkvQ3J6ZWxKSHRXSEozNFlTN0ZuUmVLSmpSNDB3TGZ0OXF5bWNVSTYKYnRJUzRzTlllNDhmKzFqU2Yvdk5NN2g5dnZnNStORXh3SEM5ZHp3NUcvTzR2TFBmSGg5c0JZN0wxaGJ6ZTdncDJIL0ZvUE5IUEw0eAp0eU9adHNjNFJoaWY0NGUrVHYrOCtuUXFOUkd1dUs1b2R5TnppMitOMkM5TjhaT1VjZG02YjRHUDhKdUg5ZStoajBiekJYOThnZlpHCjBPOWlMMGNuOENRL2hmbXA0M29ZUHNLb05ZeHkrTDRjTmk0dmlZYjErZkt5ZUFOeUV6U0N3N2E5WjFJeFpVdzlKaEIrS3ZFQ2svUW0KTXhhQk5xNjhEMURpQVBtSjUwNmN3WSsvZlY3bkN5QSswUzl3S2VjTHVONXJyV0cvdnV6LzZtL2Y5blhjZi9IeGcvLzlmNkFmZ2llNAovQVRwcVB4cU0yTWtOc3Y1WEJoK2l1OStEQk5zNFJhL09CNnZ1OUVldWxhL2NzUjdhZE0wVXR5a3NjSklKaFYvS2NXeWNMSi9RYnlECm5uUUFYdW5KSHdJYlBNaEl1SitNTlc3eVhBcXY2SzE0dFBZaG1pVU93RmZGUm9TRS9aanJPWVB6SlgxNGFIRW5XdzczWWE0bkJxUDgKSkwrcDlrdDgxejErRHF2SlpRelBGWlRPMzN3NnNUdFYxL3FTUGFiU3VIek1qdzh0NzkvM2htbFB4YS9CN0ZrZU40ZldhdlFIZ0JtUwpMVUlzUThRLzdUKzBMS3M3cm1WanhNU2VHbGZQNXVNeWdtd1J1N01wbDNZSE52QW5tL3Z4bjNLT084QndudzVCTWY0bkk1c094WEZqCm1UTGtUc3Y0NGR2NldwTlgzOU5YbzZPMnZUdkRVSDRBK3ZweFVpc21BNzVNY2N6WVhjVE4rUGxZVVFONEdWZkZodHArVzNNY2dDdEMKais5eFRoOXJtSFZ0R0VjbHprbmZ3SGoyK2RkNFYrWlNGQVN0SWVIdzdjRkwrL2Y3dFh6OHJOSERjUHBPalRTbmphM0h3MmE4VUFkbwplOGdmNnM0dTQxbysxK0xRR1VoSkk4V1lXTUpabWVnc0VZZGx1RURHUEZNOGdPR0p0d3FPcnhONHdpdEF4OXhTWXJUSGZLd2JXLytrCjFVOURMWmxLeGMrZ3lBa0NRNzV1WDMrVnVDOVZuZjg4TmloSUFVNVRibkd1Y0VYOFF5M09kWnpIRFZ6TW5INWVYZE14anByaWpXOTEKeGxrOS9VbVhNUTdBVm1lK3J1bTVsQTJSNHoyeUl6ZEpieDZmWHMxOFhRR2ZzUTZicnhlK1o0M0UwKzNpUER3cUxEdXprTXIrcFlqcgpUaEQvWW5BaWNROUdFRnppVko4d3hWZUlTZDhmNFRDNU4zd3l4NFRHQ2Z1TlAzRlllcHlBaGRsUDNyRHVlU0E4eXc5ckhmc3I4ZzM0Clk4ZTBaem5VV0dIdlgrTXI2SzBYYjNzQzdsdzRlTXZWWTJJdXBlOERuQmhjckRySFdSTVp6Z3NqSnJWOUExTHlYUjJhQVgydTAyTWUKZXNpbEo4SVZjdnJIRUxIVkg1eEdZclNUV1BHdytabnBxSWlzeDB6UWNuRjhpQTN0NG8wamtSTkd0SnlJRXl0ZVlZeXFySnVudmVvNQorc05jZWpoTzRTdU84aWZka2VLNWwrTURYWGhqd3h4ZjEyQy90ZmhtS0xxaGtSQXgvNWFtVGRLQlp6eFpMRWgxZ0x5RDgwQnZhdHdICjRLbUhCeDNCWDlBQjkvRFFQbFk1K3dEaE8yQ0k3RzI3amdNZ2MyMDk4dHhtemlQMjBWSTlqdVp2KzUrRXV2ckYwZlNOUTZTMXg0N1MKdy9qRTlORkxPQkFmWmc3bEh2ODFKckt0eTlxdjR6ckdKKzc1TTN3QXRFR2Y4ZWFSOHZhVHpXY0VqVFV2eElNbEZnUGtVOGxJRXBzbgpDM1lvMEFIR2RpSStwb2djQjlnZmVzU1MwTW5RVXdpQXFSRkx3Z0hLZnFFMXJtUFRGZ3VYK002Nm1VSWVKMHJlKzNPNXBQMzdpbTE1CjZSNFVGRHpyVTExdy9JQ3pYeHkwTTZ3eFVueDhXbjd1NkNMZFl1RkNud3JHRGE5U0FGQm4yMVZsWm1PTUlLd3pDLzl3UFRNTzhPekoKVllNcWRpOWxSNEdxWGE3dUZKWEgyaWNlR0ZDdjhTTEVZTjNWZTZxRzEremR0eDlaKzdQMlVjTzUwT3BSTmhMci9FdDZCL0E3MitGYwpaZXpkQ1dDTGp6L3ZreW85bmxlTXk5MWtQRCtESEtmRmhoYTZWNGlBN3VQbUZ0UEZxaHdYZTFPSGFXN0xrVUxHbUxCdnB3Zm0wajIzCnNsdk5UemFIM3oyMVhJQVJoT1BoUmNLSHQ5bHRqRWtmdzBmeE5BSnozdDlvejluYlB2dkQ1UkFJSXpwaHJIQXh0VkNWdWZad01MencKak5LaTk1c0JldWJhazN0NHpwMkl1bmkyOWpyWStpL2M2VjZWaWUxWjVWa2U4Q00yakFPTVdJM0dSQTR1K2Q1MkpFM1BhTnkraC91NQo5MDg3YkFqZlh1NEZhKzduL2tBMW52VUh6YzlqS0NnUk1rRnZ6QkYrVjNPMjhjTTQrZ2x0K0t4Y1Z1YlpjZFo5Z0RialN5Z2Erc2oyCm0vdWo4YkJ4d216K05tSi9FcmM5dHpXUHlSQkE5cGdnbVdpRkVWVGZ4eTlNVEdQTmlRRVA2dUc0d0h4bVFyeTBQOWxjOGhPclZTeW0Kdy96c1lFN3ZXbTAxbjd3TzhXZ04yWEE2TVVhc0h1Tko2MmoyR1c2cElyMTlSMzA4cFA1T1lkcDZ1NmtSR1g5bThvWHBVb3VwOFR3aAp1K21rd2JjZUgwek16czNOVlR6NE55OVZBSUhmdHpEbVp4anovc0sxMUFTMTd3blhONVY5QjgrSE1HUFhlV0ljTTg3ejJkUHlUSEZHCllHK2YyNmxmZVhaQXg3RHREeU1BaWc1cFd2TEJlUXN3YzZUQlpQYmNTU1IrZklQaDhLQzliTjNSdlNlOGVZTEY0dz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJdUI5UElRSmJRK2hoMzM0Tnh1RHg1NUNkSkh0WDdEVVdRL0ZVYnNUbXNTTlFqZ3JVZHNVUGxpTjUwU1hBeHNqT1YxTmcrV001NnliVwphZ1MwN3pUL3J2dWlZbndIZUQ5dkI5ZnBPR3hiOTFRdzlhSVEwYi9kNjVUMi9vOUZMZmh0amZuc2JyeUhNRHdnR2JzanNYWU45VmkyCmN6alZhTnViOXIwcFdtVDVvRSs0T1FsQnB4OWoveDNWSVJCWXhxZEZzREdWRmNZMFkrVkdUeTBDY3ZQWmQzcHB2QVdyY2p2TlZCajgKN285SDlNRDhDbGVQcTBjWlc4cWZyd3NBOXUwNjdWaEpQUU91b3hhL1U3eDA3a1dHbzEwSTltK1p3RmxuSW80YVg4WU95ajlxa1BpYQpjcGlXeU8vWXFzeHhZZWQrbDdVWGxIWnliSXdCM3owVFphMGVnYVlXdDc5amp1WjhSVHdWR2J0ajJjQzlacDhBRUxKN2Vvc29QUkcrCjRmNVovRU1lYkd6WVl1SEVCdUF4T2JHM3ZIZmZBWXltbTFxc0x2TFB4MHFpM0Q3U2JCcEdQb3lNWHR1ZlV2UUFMZE42eExDSUs5Y0IKMEY0Z1hoZjY4RExXczU1VHhoOHQ5cmJNNm1PSkdQdlhLOXdWVThXSE1hMklBRVdTb1h5ODdqdHNUKzlZQjhCWHRGZHpVdzU4S1hJVgpkQUpacnhBeVdjOStnMklZNFA1N1JWb2o1MFVKNXZGSGJhekhHMjFuOTdiMnp6OG52M2FrV21VcXFTaVNmOGpnMm9yRHhzM3VFRDJzCmZkd1B6Mk03RFR2RmZQei94eTR0K3JLUGU2RWZhZXUrWXNBY3JVU0t1NjBZYjJPaHo3NkFFUkk1TDFaV2FrWFdPRmY0WXR2cDhPQlMKM0wzTXYxL1BBYzRhYWorWExOMmMzeXl0Zk5GUDU0bnh1WTRucmlEZEFTK0hrR0RjOFI5R0VuVFU0Mk1PYUpQaUFCeldYODRZT3Y3RQp1cWdVWi80VGN2ZzdZcHpxM2o4UyttN3I0VzFQeWp2dVMySkhLTnYydC9WZ3RvbmZ6d3BWb012ZEUyL1JJMmVTc3ExSXp1UWMzbWhlClhDTyt2b3g4Ui9LTDE3QXc3dFg4Y1lQUW4zUkZSS0dYV00xL21NdStMWFhya3ZLU1BNN20wTVNGbnN5OU9XUnNPdzFFYlVVSTVVYUoKUVkvaHRKOXNQbTRPeTNYQ2ZBSkp1WjF0VnppRFQ1UFVBai9uaSt0YXkzakwwbXc4amxLZWV3SEJsbFo4T3pJKzRkQWZ6YWw1SHUweQpaZ3dRSi9aUDg3ak5YNDBmRC9wZmVOc1dHWUZsalJyYlVLVklFL1FTUnJiVDFaYW9Zb3ZmWWxkVVhTM2NJQmtqYnNvK05TTU9zRU9CClIvbVd4M1pBaG54akdQc1ZzaXJkZWtkMG00Nmg4NFFqY3Q5KzRjbFU1SHVlS1UrSm81WTlTN2tkZ013blpzWEE0MDgyaC9CaDdLZzgKRy9SVW41anl6dG1kOVh5dU1TV3dCWEI0S3pVcFVZNmZ5aUUxWkVCRFc0WUdjbHdyYkpqM29pSWxUUjh3bnNCaGt5NkFYWU4zc21WRgpoamkzVzhNY0F0R0szNDJiK1AreDk3WHRiZHpHb3VmemZSNzlCL2EyYnB3bXBCZFlBTHNiSjIwc3lYYWR5ckZyNWNVOWJhcERrU3ViCk1VV3FKT1hFK2VQMzQ3a3pBd3dBdmk5bFN5SnA5c1VpaDhBQU13QUdnNW5Cd01WNFNHVTl5QTVyeGlRb0gzV0Vvc2N4VVpIRjJpSlYKTHJaVDJjY2xuWkR6ODFCRlpqc241L0VWbVpTM2VwbzVDTVJuQWgzS2hBV2ZsRDZPSTdNTzlDTUh6aFJIcUJvWDZDTFJsTWhIZWVVOApCUkpQeDF3L1k3c2NQdDBvZUxwUUxua0g5R0plT1pNVUFuM2tBRVhGV2dUQ1Iwc0V3eDRBcFdMaklybkI2amJhMUZ0SWhYZnR5Y1JtClhROHM1TmhVSmJKSm9aaFlvNVVGdXBnVGZDYlFtemhTTHpkRWlCak03TE1rRmtpaGFCWm9NZ2JxbkoxcjVOZndrWDNldWNaR1BIcUUKbEtNTEtiV01CZEliaTJGcVdRU1pmZi9hclRwN0doUE9VZWZZYVBWSWtVVnVZM3AxeVllRmVzcG9OK05vMHl6M3prempnaE9OalZOMAprOVk2cU9oVnk4eUoxQ0xqdVlSbGplRTRlcmRoUmpHc3h2dVRoWWtGZFNwQ3ZHcnVLQXVCNUZTV3lSWE95dzFBZXFMWmtoQWp3QVhCCnM5bnVnOEk5VGVFa2o0Y1Y3T0tqc0d5dW4yamVyNVQwbldXL0c0WWhXaE9EMFA3NGpJOWY4ekZKdUhnZnl4bkZiZ1NCd29mRk9zY2sKNFpPZ0diTUx4S2gwd05SSkRtZm9aTHpCSFVablprYkE0ZFBzVEVKZzdqY2dIMWlySXc5VllzKysrTTZKYngvV3RXMGZYN3VRdkZ1aQo4ZExXVjk1UmpmY1NiQndOdm5YcHdob1FhQmdyekh3NXhWazhmZk5oTjVXK01jRGx4WnppMEdDWVVTS2FuWXlBM2x0eGE1OE45ZlNHCnJRL1F3ZGRlR0J5V1E2cFVBUE0raWo1ZTYyY1NvSDhIRjZxd1J6aDhwOTQ1YS9FeFNNb0U0c29heGt1dk5GcWdOOEJ6aUQvQ0ZKK3IKM1B1d0RxMzNnN0NqUzZUV05PdGtuWnNJcWUyTGxmWVo3MWY4T3E5VFNtMVJhZk5jV1ozT0JVMUxlc1dROTBXT0twWTJ1TkFpZFpHVgpJdlp6K2ttUFQwejZRemdmb1FWS2NGYUoyWDJLUlROdnN5eHNGQWdDdGRjdGZFQzZqRHdvaVJ0dllSVm0yL3ZNS2tjaXNZNWNOMTBFCno2SWtzck56L0NXKzVaSDdaWkM0VzBTRnRSdTZrZVoxUVBIZU9WOUFLUXpIYzhFMFk2VUw5NXAvY0ZtdlNyRjVKSEZQUjduZFJuSnMKS3MxZVMxWWMyK29Wamx6N0tGaS9nMUVRVWQyRnJ1WFI1bUdyNTlZNzRCYUg1S0tzeDZIV2FsV2JKSThGdHpZQkFia2luRERVcmlnSgpDamQ5N0RZeDc3WkVjQUNoZmRuZHhNcDlzQ3Z1OTRhdlc4Z3NrTW9HYWdRTDlyOUk3YTltQkpkZnFxeHFnbGk5QjEvNWUwWDRzQXlqCjlYSDRXYlFoc2M2WlpKR3pqTjdIc1FqUXBzUENyQWozdzlDMHg5SFFIUEdReE1ZVjRaejFpRUJ5VUIvczNLbnZtSDErMHdzZDExdk4KeDAwaG1kM1NCR1U2Qy9YcHdVWGJBY054TzhSRzZUYWF0SmczdUc3R1NDOXlaS3FpS1ZNNEJCUXp5SmNjS0FHY2JjNmY0bkFxdTdPMAo4YzRLQkdxdmlBamg1N2V6c2hucmplRUpydDB4MEZnaDY0QStSTm80cDN0UzJIZDRDYWo4aFNrRU8rK1VzU1kzQjVRY2o4MHEvYXpiCkYyN2xLaVpCUzA5WFhyRDZIMkV0Y3U0QjN3L0RrcWxoWU02bkxSUW9obnRBandOWklNY2FHL3NNa0FVYWQydzJWZ2d4QXZLbldMRE8KM1BnS3diWmhaNG16UlRsWXlkaGJVN1lnV3hxTjlSc2V1UHJrc1NRd1Nnekd5dTV5ekNpWm1nRE8rWGpKZDUwQVNJRzh5dCtUc0VDVApGVzQ1cE9IeUVOcFU4b3g1YXhnQmgwWVpLK0FkMXN6ZnMvRDNFbEhZRytZWTM2MmhmWWxQMkh4RXArZkFEZk9yQ0pzVis4S01EY2x3Cm14VnJuc3JaTUxGNjdxZDk2alYxTkhaeCsvVE1tZHMvL1UwSXIzU2hHNGVCdEJueFhpdWRwZzdkY3Q1QWZBZzdaeDAxMVlwM2NPbWMKMGlZNmc1QmlrUHZCTFZnem9CeWxLcjZMc2VBK2xPU3JqdVF2dFVBT2hhRFhibGx0eTNtdzBpd29YWEFBWVFLODBtWVM3aE41c3B6YQphdGdZa3JENFJLZ3pXMmovbG8xVmtpVVB0MDBrTTZaUUc3c1pXS0RSR2ZkS2E1NFlicGJZTGpnN01LcjV6a0dFWGNnWnFFSVBOQjhPCjUxK1hZeFhSK0VBeVBGTW8xc2hGNms5TGlXZGhjT2NKcDdNcmUwdWdZSUtENHpHNmhrZE9UT2F0YyttSTNGOVE5QmM3SFRnVGZuNHIKUHB3RmtlWk1PaUlmVy9nY3VJZmdqT1ZrbGl0dWl3M2Z4bDdENUpiNGdpNnBraTFHSUpnSlh1L0w3ZHV3YnJkd0N6eW5KeE1kVWhOMQp3Ri9zby90S1J3NmNKaXdvS1pDVzBYcUpsdVRjRm5zRWpGV2dHRy9xVDR3eTk1ZmtWRmhoeXQ5OVU4YmZ2UEZlZUJHMGllaHlZdTZ0CmxzWjdzTEZiWHFnSDh3MGlVTXhGVnNnQWFEU1BMYXVwTSs3Wk9iQ0xJRGIybnR0NFdXTXRQUmFZdXhCb1krMmNiRThRZmd2aElEV1IKMitnY08rT1Vab09FczZXNjYxNWNuM0wvaDBWcWdieFRPS3NWQS8ya1Q5bXZobWFLY0QrVGRlcWk0YStHRmU3YUJGbytKTjhPTFRnQwpHODBrTEdRVGR6aEdJNHZNK2FxS2xteGtrZjQybnZSSENnQUxMN3pEdVE3QlJlYVhqTC9qelRKU0ZuYXJSSmdMUXpPUmpZVEFPZ2JQCkxEdXpaRUF3VnBhN2xlWGFuNW10OUpUQ3FpUmpITVRIRlhsSGtKcERWUW1hOHc2ZVNHOXRDOWZpNmJLZ0JXWUpLMTFTMm10ZUFHUjMKWVh6UlVlSWpodHdhNytzU1BibWVYenBueTZCSWVhTVEzak9HQnNQQzMrZDFZWWI0ckxTL3V3NHJLbk5BY3R3NEVyd0RJWTF1YUJYdQpEQXZBUEdmMWpQWTNMcGt3MEhzWHNhenhWNTU0enFUK1pJWjNZKzNxd2pjaEN6WWVKWkVabEk0amRzbzd1NTd5c1VQYTV6REFoOXo1CmJsYnVUNVpvbk0zODN1RUhCaDl5bHJ3dnBnVmpEVWZMeE4zNGxtamY4SHNFcmhoR1MrWWVaVy9lZXdlSzltdE9Xd1d4VG1icklLUlQKTGRqdWJkd2xMTHlSbndack9vVkcyT1lTdzZaNzZXK0lzZjBOamZ4K0VFTkFnRVM3VzhSRU8yUFE3dWN2ZithR2ZTSjhZMWpiZ0NQMgpLR2gvWTVFamdoQm9XSFJ6akw3RVFBYkRVd05uTHlNb25LVnFyQWVGUDVOd3BBbTZhaFJQWkZXd2xvM2VIczFya1I0VnQ4QndTWTdOCnhua3NqaEsyYVdHNkJwMTZpWjV3MlZUd0ZVYStaVGMvM3dNN1lMUS9SOHFjNzVGcGVvaVR5MFdUMEZmV25IK0JacjUzZGlVOGpUT1YKTWxIc2V0QStRUWMveG03SHhYdUt3bG5lWlhCWVVKK0RET0tjQWVqYmN6R3FtQmRDYzFxSmNNL1NuVzNucHBvd3prS2tmV0FnT2gxegpuNGNnRVp4cmdyWEFlRlR3eFhxdGZWOVRMbHV3R2t3M2QyMUJ0dnk1WkFOY1h4dSsvbGs0YXhRaVZTb2VBd3MwN2s2UXRpZEdSaEN1ClZYTllUaHFPYWJyaHRBU3NML2dlTG1rc3ZyN3pxbWtNOEdGWE1Qa1ZDT2p1VXdDTVVrTW92aGp1UGNrcDAwOWI0SkVEODdrY0pZYkgKQ2dzZ1k2QU51MFd2dGVadVNSMDg1TnJuUzZBWUFVYkxKMVh0cjFjQ01OTktNVEJMUGRCMWxwUis3emYzYzlCcFA0alRlQWE0S1l3RgppMEt4ZU9mcGl1NTQ3Zk1jT0w1STlwQWJObFZqTUlGa2ZZVGN6Tjd0SCs0UDI3V0tSWFBKbmRlS2d4RVNrekhReHlSUjNBSFhWKzVHCklyK2RiSUZ1TDhVK0dXWnFHdWFLOUs0RjkrcTdBL29iek01RU8rdkN2d1ZuT1NlWFlUOGhCa240MVdhY1RvdWhIMTZJMHJwbEJPR0kKeHZHaStFQzE1T1dldW1nMURCTGg1VXAzcmpoMGhHOWphT3NyY3ZVRmI4VSt6aWIxT29xMmxsTkdRRWNIVzFaN0JHSFQ0bHRWc3k2SAp1N0x1YUlHN1F5NTlVQXp0ZHVOTEhpK2Q4eW1DWFVHcGlzNWNwTUZidk1ydlpYaGU1ZXFxOE9mRGxIRVdMbjdIYnZ4Y20wM3k3c0JqCmdXem8xdmFoYVF1a3kyQ09yTUo0QlBSeXRwT0RCUmVWL3BLL3RwNC9Lc2pYd3BYM3BXRUlWUkRaN2hvZ0FqUFd3S1h6cGFYYVBtZHUKRVlTSUZPMVZsMmdRdFhYbVdtQWlHQ3NsUkhWck1OU1hJZWNRWDhKREJCbXJqMlM4WUREYjhJTktoQmdNVDI0T2NNQVlNSmM0UnR0bgp0VDI1eWllb2NOWTFCRW8rekxMMmhWajVXT0FOSGRnK0wwUDdxcUhqQ3lkd1VPNE1oZUZxR2VzTU1tSHRGY0ZlOGFFSXB5TUgxczYxCnJuMHdiR3E4ZVJFWngwRjRmUCtCUm9NSEVTM1VmbTVrZkZjaGpTTS82R2FGQmRKdEtHWk02b0JCZmZSbkU0UTZodzJnVFZ3Z0lzYWcKZXNXQnc5am1aNUF3UEk4eTNqZlFzczl5RC9iRm5JRWVRZUhQN1FET0ZmY3JrM3hvU3d0TzU2VHhxR2haVTNoUGJUamlBekQzaHp2cAo0eHNMNnd0MlN6SHpzWlFoSFFOTEtEeUsrbk9CaUNJc3M1eVhRdWJTZmlBQ3IvMFo1N0ZBWU1vSDdOeTc1MVRpVFZzaHA1WUtsNjl4Cjl0aHBPRCtoaE00SzFuVmRwRFpkNEdmYm1NZzFJK0RBRTJObERTTmdLV21zRk9leTNxeUVscVIvN00xRVVhY3cyVVR6dEpmT2VJSFoKQmdyMjFKS0gzRFltZkxTejl2ZTM4VUs5NWdPZU1vYXYzcy9NVTVGRzlza2s4U0hNS3RWZXNiZUdLWXhMVnB6anp0OXhSS2czbExCYgptNHI2ODRKTFVVVEpwN080Sll0QVJjbFVjdWxqb0lPeldtYzJya21GNkJzVEJSQUJtT05NUXNZcHhPb1RRSkd0eUFMWmRVdG5tOXdqClVJblhvS1JrQkR6bmpMMEtVS2U0ZE9sOHN0cWFnQzBDN1NOd3RZM0lPM0pndmlha3ZmVmJhVGEyaEF4ekNvZFordz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJNHhYTGI0VlRUZmw5eVlTeVh0U2prdktESzZ1OGM0UXNqWFVic1MrOGNRK2RJeGFvbkhLTWRtYjI5S25NTG0wM2E1VXJLbjNNQXp2MwpWZWFqeTdTMW8zUDlZUEpMM0kxMVJPQ042aXBKR0t2eGxramFqUmxCSmpsVlZPb1ViT1hDOGxWc25sUzV2MTZnYmRBQ0krRHJnZHE2ClhQamFBbnNGM1pIZG91Q0R1clkzV3kxUTVrSFdpM0FkUXBvZ2tyU3pJNm5jK3lhMERWRjNRTzltNDZ0MUNtV3FGd2dwWDFoVGhRMkEKY3R4MUlUeXFpSncrSnMwWmcwNjl3eUcxOFFrS1hWK1M5UnMrZkdDNmRpbjk2WmNka3pxSlVzQzVHenA0K0dHaG1EclJBY0RDRzFISQpZWHZncW1mZXI1bmtWaUFBa0ROQ09JbGlnZXdZMWRhV3p3aGtFYlpYd2JkYWd0NlRPWE1nQUhQRG94RHVmbUJacGtvSEFncldPL24rCmxvNlBkR1RwNStxNW5reG9xTVBWVTdyOTUyQWg4eUdwYXJhKzhMbWtjQnUyR3o0bDNPY3pyY3VWQjdEUWZlMTduM3FzMmtaWUlWRFoKNkRNcmQ0eFBjY1hDSDg5amZNa1Y4eGFiekNzY2ZCMHF6RmN0RmRlWFB1eFArS3RxbUF0TDhtQlRrSjhGY3U4TjV5UFRYbUNReW00cgpHNS8yUmR0SW1pTUhscEkzVUhkdXdJeG1pYzlJNXBSK0JFcldwRlVZVXVQRnNmYVplYlNKNW85MFNoQ1d6SVNiS0ltUG0wU3dZSjFQCjV0WUJnNWZKQkV2TjFLVzEwb1p2MHVNNVBhclBWKzIwdlczQWROSDFHTmJqY29laEVJWjc0QzZwWWJDTVR5eVhzLzFDWjlGSlVSVCsKVnA3TGoySkw4NDI0M01iMnVMS09Cem1lRi9pa21QTjFYZ1Jyemh2SmpuMmQrN0IzWktLMUZ1RmR2OEx2YU40d28xR1J5L2lvNkt6QgpKdkZpeU9XZnNzQ2N4U09wZ1ZRZmJ6RjZrVWNYNzQ4Y09KdytpUGQxdWtmSjdsRE52akVqdkJQTW5WMHNXc0hCTTdyaEwzRUdzNHd6CkpDUE03NGJLYjVKR2VGMUgrL1JRQmswbG5HK1M4MndZNFNNWXRKVjhqQ0FzVGZLSFc2S2t0ZXJhS2VPc05VYmF5NWRPNHRpNVpWTHIKV2JZTU5LeVpFWmpYcHQwT1Rlb3ZQbXViamF4dXI5eEtOa0dDdXNCTUNUZHh0UlVUUnc2Y3kzeGl2aGh0WTAwY1pRbGZVaGFLWjJ4MApxZHhFcDMxSzcxdW51OXVaNEFYcW9ueE1jTmRwdTh4cy9aQmhGMXZWWERRWEV4WUV2SlB1VFJBVXNzRDFNejhHOW9pRVY5cUQzOWdkCkdoQ1lDWC91WVhNTFhYL1A0elhBbC8yRkMyclEzdmxoQ3NwUzZHYTc0TGJZZGE5dHVnbEdtOHZDSDZCenpubVFSRVorVHErRWFSTzAKOFhZTmUwYktaSlNKa1NKV0NDK21idkNtUUZZK01NMkRadXNTQjR3QU1DUWJwY1hMQ0RJdlkwbFMySTZsTmlUYmtwRVduRlBDeXowWApRNWNwbTREYnpUaGVjVkNTZzI1MGRLY2NTa3QvK0JMYUpTRlJVVXBrWjU3S1VPVk8vVEdQRTNBb20rVEVpZFBDVGRtTVpLUGt5V1ZOCjE1bTJkeGpkZ05uOUtBUFJ6WjJsK0J5TEZrOEFpdXVuVms5Qm9HWlhxbklPL2N3RUJuZ0RYMmFpaEsycDA2S3pMSElyQ1plMUtzdDgKWWhSdGc0SXNnaXlLWUVoZHh0Y3M5eWx4dFUzMFo0RjhGZFVkWlN5Q1BOcm5OQWV5Wm5sa05jdGRMQkVCL2VHVGsySHdpYVZRSWJFTQpweFF4L3VvTUF2M0IxU2U4eU5tSGlTY0xsazFRTkZpR09JWXlLNkpvQk1xelpJRmFlMCtadit5RW1XRWttMmdwbTJMSWJPTXo1cnA0ClF3UjZ0ZHhaY3pPMEh2aTAwNFl2MldJYW5jemJocHdYRllBcVJMYTRTNXM1SHQ1OWVzU1FyeWZ4dVV1MFRlVmhnWm5rSUNCUldQRUUKd09DbUNxb09ndjJ4anpYdFBMSFhhQzFXbDNNRGdWNWtCTmJtd2tjZEI4TU1wUkZpTGtwM1ZzaEZISnRUOERrSXdkNmFXTGd6VXg0dQp3bW1iaHF4T09Zc1NyK21RRXNBSVFrTEozSXJZWFBpNFJEdzE1dHlCTkFuV3ZUeDBJSUJaelVDa0tXc1UybDNkeFpKZUxaTSt2UStWCjVXVkFKMnZYMmNJYmxKMUZHMU14OGRLa2JkcldsLzd5cnJaSE9nZFVYckYwbHhrcGxSTjNsT09yRVNpOVBvRm5sU01IOXJ1QmRyZHMKRWViRkk0c21BSEllRWxSKzJOMmFvNEJXdnF6aHNsbkJDNG50d1FBTWpwSW9KWnVNWEIwc3MvTTAwcjRveFlNRmh2eWxSSXRGZ0ZZWgp2Nk1uWEoram9aMVRZYksrRDdSQmFPWXpWNGVXQk0vQjNOMGZBeUEvRWVEeVhuTjk2YlUvc2gwNm9KOXFMdmxkNnFORVlpbElZSi8xCm5KTUtwdDR2UEk3QXUyOXlIMHVjcHo0bFJGUldScm82WjNqQkFmREdWUm5OaThLa1hrK3pkNWNRcVRmc2NUSXRHaFJtUU1oN2hYd3gKcktjSVRocVorbXhpSVNJRmdHeUlOWGJ6WXdSaEsrS1luRnpGeHFQY09wc3dvWnBQOTA5UG4xc0V5c2R6NHc1bHpRdDViR1ppZDIrTwpoaWpXVVh6TUFlYXY4MWRUcEJKY256SWhxZGh5ZzhBUURPR2pWQkJCTURlNnpSVGJ5dmtjeXlsdXFBTitaQVdibVhMalUxR0YzUUN6CjdSVXNYM25ud3J4OFJ2aStzcEtSWjFIb1lwSTVkcG1RY05pTFRBeVU5bFlpbnlZb056NWJGRTZ1akRQTm9VR2VsUlFPZE1mc3R6NWsKcitBc21GRjRoTC9YbnhmK0htWXdNQ05RcC83TW5qQ0M2QkVGdzJweFFVK3orRGxyVjBjaHJBRkVXVXVaMVFhS2NLNElrUmhGR3FsRAp1Wk10Q0N5OFI4YWR3UUNZaDRBL3pWWllCQWMzaFkvSExKVDN1cU9OS01rOU9OTWNXc1ZpRHpVcDd6TFVMdmtReldudkFHTDloZVFYCnN5c2NibmkxT1EzRVlxVm9LTGJSR0VlRThkZXFYVVNvUld2c25VWVZXOU9KZGN4d3VzeHFnU0Q0T1RiTU82SEkyR3ppWWJUOXdtd0sKYkh0M3I5RlljT0N2ZFBtSDZQcUVkOHk0b05JaTg5ZjF0RFZXSHpnRVJaWk02QXFZbmNjYnJsMk9Uc3cySVRsckFCMUxiWDJYQmNXcApGVzUrNUQ2aGl1R2NRcHlWMFZJbzJDZzNMMlYvbW5LR0JYNkxoakxyV0lxZEU2L0lRbUt1M0R1ajZVNlJ6OE9ZUlp4U0lSY1FaMHFtCnkwS2M1SVB5aEFlMityektxWTAvUVF3NVh3dmttdzUwcWNXbjB4UjhjNVd2cDlteTdzMkJ6TDg0RStYa3hRdGdmSW1kOWdhZUJibFAKMmVXenlaTVE0T1JIV1NKNElvSVU1cWJjL1JZc3FUZ1RRT0ZqMFFzWFFPNEl0eFlGUkJDeVdXWitkcHB3b1paVFY1QVAxRi93VnpuWApWNFZQNE9RT3VXVHQ5d2thL2MwcG1qdDhiNGZNZUE3b2N6VFFWUW9MVEhOT29oVTg0cVErZXdRdUJvYzJBbjRveFVzdTdZTXMzWXpnCmRhLzlGWEM2cE9qa2hyK09xMTAwZlRILzdRcWZTNXoxMkVJMWZBSlpUaElCc0pBQ2k2NHJIRGpCVldTY0Y0WHZpaGNxem1mcER2UUkKZEJsZzNMTnRYazRhbndEVk9TUlFKQ3UrVWxpd25FWWxKRXhPUGg4Z1dETUZWZ2tycEw5eEdsSVRJVEF0L0pwaEpiSUlJYVdaVjhJSwoxRmo1cWgyY0U1UURxcHdUUmxORU9TTlF2RzdKdEdoaDRRWS8rNDBMWVUrbGJwbjVJUlRldmg1eXJTQ0N6TThCdTMvVDVzWEpta1RtCkpRU0FDNTlvMWFXcktVU2M1MVZuRFBUWk5LbFRYRDljZGN5ZERST0JCVjlMejl6UkZZRDhva2h1azEwd2duQi96eWtnQUl1U1VMa1kKcWdJOXJueTFOZHlKS1pJb01RM2QySEJsQmFmbzVFd1NtQWZjTUsvOVUxdEZlT1lxOTJrWXB0T0wvMlB2YkUvVURwM2lHaVN5d2czeQpmQWJZOElrbUJ1YXpnRjZaazlFTmJBNnZHTXVPUzIrcTFlT3prOHZnM09MNm5yNm9xQXJKS3p6T0NRSmM2bms2S2ZLVllweEdqakswCjFQSUZaT1VQb0J4NWt6VmNBalE4RmFjc0pCUnJBWFNBOWhja25VaWtvdjd1c2JzMGhEaDk3bXE2VWVZUkpEeWJwZFBsaEErMnhUdVAKR2RlZjZEN1RsZHBKUUFLTFRLTThZa1hCYm5GMmVDQlFlL3UxTXczSXlENUhPZEVQcHVwek5wbzg5UmZldFQzTjF2bXM1RjB6bkFpVwp3TjVqVlBnekdDZlFEdFpqQXZJWmxqYWpDSUdjYnN5N2dVUkFPczRCWk0yZnZ0OUwzSnllT21PZU05aUg2ZWFhVWFYQk51dkNSeENvCnh1SnkvQkV0dkdsUzhCbVhuN0h6MFQ3elQzalN2NmpHbmg4NjR2cUQ2N0lqcWpUZUlzT3pKQ1FlZENlT21mU0haOW9tN2xnc2VVY3YKOWZmSTNEVVpCRXAyNFpJZVVGOTh5V0xtSFltUWZvVURCOGFCbkpwbnhwV1FNMmU0RHVsZ0tkWGp1UWZQU0VVc295ZllDbmF4VCtNNAo4bSt3VGVTTzREZlkwb0szWE9tQ3BNZHlSMUNpZFFmVUxLYkkyblhBQ0xSUDJzSzN0RXg0R3BMdllNeEtYc0hQc2sya1B1Qm4yYlJYCk1WS2ZVQlBBSVJrWDU2ZENvRTlBUkM2S21YaTV3ZFRlR0ozWUhCRHNjM2R4Vm5vQyt1eE1ibnJPVDNNUVV2aWxMbUNjRVBpVUFESFEKNXpOZ1BXRzZYMGZoNWFLeHZHejhjQkZmR1VhdzVyeHVRWkhtQ0V6MG9mbnNWeG1JbUphckh4SW9zQjBvRFJkZFFyNy9HWG5oN01LYgp5dnQwN3NEK1lqMWZMcE9adjdxUk5WekVrc3lpYS9uQlhJSFZNMVpPcFl0N3dLYUt4QVBkdmFDcDlxUG5aOXlwT0xjaHMrSGxKZW5CCkNiK2NGTXJ5YXhiemt5R3l1eVAzQVpzSWpFdldaNzlUTTdOYlIvNXB6cEE2bFk3Ri9EUW5CemI0WFZWbTNpU1grU3VuOHpsWkdNNlYKeFR1NHpDUEZrNU41VEhlQTN5Y2lOWXdQc2tiNHQyUHp3ajgyNHRPZ0U5Z1hkdStTRUpCbk5SK0ZreXpLZEJFZUg1aHFMVHhoTzFIYwpkOE1uMTZVem5lK0dUMnFnWE5aT0JHWWgzWWd4ODdyQkRZYUUxM1NUYUVtRG1UOHArL2VXTXA5NHlyOEdONFUxdkFMRjkwZHc1WXZ3CjhpZm5PblZKc3Z6empab2xxUmFDVTM4WTVWOEZkamxCcC9HeUNFeHNXaVA3QTZwKzV3NmNwUDZwME55L1laZjdqSytjMUIweGUxSkMKdXRMNVBRN1puL2o1QXhFbmx1ZUhnS1k3eGoyV0RjbUdaSm53VzZ4Q2VEZVQyN2c1RFVBUkxJWjgzUnZUc0hDZ1dlS3lEU0lDeFc4bwpKb2tJdC9qVGNJT04zL1FVM2lRVll2dW0raFUyR1JPaXgvaE5XN3h6WDdEN2g1MXRWSlNOLzduMk1CL1BRUWxOZUl2SWZEUWxSNTRnCnNQQldlbmNVbTJxZlpYWnExN2RpNitJNVF3VjcwQ2djNzhpQjB4RGVKMU8rM3loOVVBajNkd290TjZkdDFLamQ2WXgvMnhkVHhiR0cKRVI2ZVFMRGdrNzcwcjM5TUkyRzVhYUlRQXUySk1UNjd0YlladFRucG5uZXhrU0ovTkJQRmtYL2pMbWliZEgyQW4vZ0tGOWpDeFExTQovNXNHejdUZ21HS0tjN2VvMDR5QkUzaDV6eXA4dm1wbjVqOTM0RlJ6bUFiN25URzRVZm43SjRYbTRFWmp2SldlRFZCWU5IaDkrYlhBCndsc0JkY2hyUE5VQjFrdVR5TjFDRjRiT0hUZzhSb3ZCcHh6L0VSNEpwY2pnbzlrNGp1Z3grYUoyOTlQYXl4L0hQczE3WUY0ajhPVGIKZnUvNW9OTWJkWHF2Nm5VTHBuZm40eC8ydnIzQVgwUmlmenIrNGZHalRoZlE3TjN6SDJ0ZjdOMTcrZlRvMjM2N3hJK0huZGFvMCs4MQpCKzhXL1hDL2R2Zlg4MjRQZnFwRHR3YWQwOHRST2Z5MDl2bmV2UWVEUVhPaVJPdDFwOXNlbEQzOFhkYnVQZW1Od20vNHoramRSWW0vCjNRVk41TTZudFh2Zjl6b3RBQjhEM3Q2cjhhSnZtOTFMVy9hWFRudjBlbkhoWHZPY3lrSlhYT25QMTVtaTEyWG4xZXRSWlpLNCtJM1QKMUQvOXVXeU45dnVYdlRiMGI3Ly9hMVVDejJpK1FkSFJzREtWWTNWdW5OUUhUMDRlZEM5ZU4wOUVWUm83YlNpNWhDWXNjK09rVkorSAo3eW9QenJ1MXBtUEp2SXpvK0pYL0x1N3V1b2pKMGVYZzlMSmI5bHBsVlZiWXFoVzV3ZTNjOU1EQ0VhOHFQYWZOWWZsb1VQN25FcGhRCmZicE8xTHB4Q21WVjhucVg1ODlhbytiYnNycWNqS3ZjT0dHOS92R29NMm90Mlk0RGZVTXEvVjJudXdLQlkzVnVuRUpjY2xXcEc1VEQKeTI3MWZaeUxWNUZBYzdvdUZuUjk5bTRVYmNybGR4WEZTZWp6QXZhdjhiaDBla3NXWUx4Rlk5a2JuMldkWGxWYStoZmxvRG5xRHlvVApGQ3JjT0ZYSC9jdEJxM3c4YUY2ODdyU3FEOVlLWTNXTGkrZWdmMzdSSDNaR0s2eWQ2K2dIYWNsVnUzRHZzRHlyM2Q4ZEFkZVBvdDBSCmNBYVZhM0lFVkxzajRBeENka2ZBV3hHVFo0TW1hUHZkYi91ZDRaWWRBaXRiV2piekRGaFppdXpPZ0xzejRPNE11QT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJT3dQdXpvQzdNK0RIZGdaVVczY0dYSUdpVFRrRHdzRm92M3hiZG85Zk45djlYN2JBUTFhWDIzSkFXb1dTclQwaVZkYTBoNlAyWWZtMgowOFFPcmFDS3hwVnVmSVJQdTVkTFJQMEgwRVZ2UlVjZ1k4dTJhUWlQbTVmRFlhZloyMTg2Yk91b1lGZGVTZTNxWXJHOTFvZnZkbldwCjJQNzFGZ2pwbjUwTnk5SHkyYlI1UW1BVndiWXBxLzhaamRibXJmc3VhcFlZWGRqcWQvdURMMzU1dmZTSUUyK3E3N3JWclkydTlJM1AKdHNvQko4UEx3Vm16VlI2M21xdFFOVmJweG9rYlhwU3RaNWRMNXQxT1FveEppQnYzRFZhZWdEQ1lsOTNtNE9HdkYvMWUyYXMrVHRNVgpiNTdLVllrODZQZUdvK1lWaUF3Vk4rbWtBc2MxK0U5Vkp2MVdtU3UvM2NiUlU2eEN5NW9mby9VS3BIendjL1MxcUNMUCs1M2U2R2dWCkE5UDEyQ3JMWTdkaWo1eU9zWG5hMFpXT3F6dnZ3MjE0SDdaVUUxcVJyRTA1TGwzQm5iSXVNcUh5YnZGbWlVNFVqUVVXdmZrNGpNcUUKTExHcHhJU29kZFk5MzZUVkNVblhtcERxZTh5YjI5aGlWcFphNjc1bk5nZWQwZXZ6Y2xUZHNiMUplMmUzTTNyZTdDdzdpMjNlNXJtTApTS2k0aFc3T09YcDFxL2ltak9mVGN2Q3FSRTV1bmtxMHF2elk0aUc1dm43c0FvOCtqSTRsZG9GSDZ4OTQ5SEZkUGpubzk3djdnN0w4CnJiTHJiWDBEckZhWWpPdHVHYTVNeU5iR1Y3VTczV1oxZi9BbUhYa3EyM00zNjZ4enZaRlY2enBHSkEwckVuSWJRbEUwS3FlRkdEVGIKbmN2cVd4Y1h2ejBWdVQrNGVOM3Y5bDlWRnVicmMyelpYdWwyL1hlWTFsWVVyTGxNcTM2TGFTZlRkakx0S3ZyM3RnVHlubGIyaG15SwpFRnZoQnVPYUM3SFZMZ0t0SXNWdWFjbHZhdmp1OXVZSXFMeTdiR2FPZ01wUnlic2NBZE1FM202T2dOUHFpcyttYkV6VjVmbTY3MHlWCngyWlRkcVpOenRxd0pOd21FZ0tyM2JtNHBjc1dLMHl1dFE5b09hMDhOanNodHI1anMrNUdnZ2VWWFVFSHI1dTlYdGs5THJ0bGF4VWoKMjNURkd5ZnlSV1UzMFZXSm5LNTRhOXZSWVdkNDBXMjJ5dk95TjNyYXZOaThQZW04Q2FncXU1TTM0cXhVNC8vV3BqNktzWTlWcWFaUAoxZFZ4TG43emdyS3lzV3RqTnJIcW9uL2RON0hWY21sdWdDWitnRGVrbjFZUUgrc285cXJmejl6RVRDbVZyU2tiSXdlcXI1NTFsd09WCngrWWE1TUM2ckw2emxZSzd6anJkN2lyQmE5M2JVRHFXcUFlUmZSWWZwYXB1bDdXbGIvN0dTbVd4RnlqenpYOUwvYTlJNFVTdFd6RFEKOWlyUHhHYXJkWGwrdVR4S0lpWXZxbkx6VnZYS3M3SmRQVW1UTFh2anRBeEtPbWhWSHFwMnV6UHF2RjFob0h5RjliM25kamJvbjFlWApoRlI0ZlQwNW8zNzFrMlQvRmdocGRuOXB2cXU4Z0VBMUdqVUhLNmxTdHZ3dDNHN3JsYzNLMTRWYXpXN3JhYi82bFkrb3dpMmRUSnE5Cnp2a0tFdnFhN3Foc2R2cTdlcjR0WVRPdFhkak11aDZGcWcvTnBwaEVkbUV6OHpidzJ3cWIyZmIzRmF0blU5c0Z6c3l5MDkxbTRFeHIKNndKblZwRG82NzQzN1FKbjFtaC9xcXlOYmtiZ3pBcVRhKzBEWjFwYkZ6aXpSVUpzRnppekM1elpCYzdzQW1ldUdEZ2pQcGJBbWRiVwpCYzZzSVByWGZSUGJCYzZzazlqYjZzQ1oxdFlGenF5d2V0WmREdHhtNE13bXVJZzJKL3huaGFGY2RWTGUwbEJ1Y0xMQ0ZRTFNkb094CnVYazlObWNzcnE4ZnQ5dUhyVWtaK2VESnlTR2xDanBaemI2MFpVR3MyNXN1NldieVJLL3I1ZHVQSVQzUFRyNVZrbTltSjk5MjhtMUQKNUZ2bHVicVRienY1OW5BQWdJOWJmU3VSQlR2cHRpSFNiYWU5N2FUYml0THRvMWJlZHRKdGs2VGJUbmZiU2JmSzBpMTJHNTJzNWh6ZgpNaUZYbWZnUDRvdmVLQy9oYmhHdHNJaXlqM2tSVlNaK3Q0aDJpeWkrNTUzVWRPVkFRRXYyaXhWaUFhTWFONjZPZlZ5dmJUM3YvRnAyCm4zZWI3MDVXdTQrNVpYSndVSjczbDZXTDJPV2t3WTdjVms2YWlrSmtsNUJtTVhtM21aQkdWSitUdTR3MHQ1aVJabHR6bnd3dk1QdEoKVmJyZUsvZkpEVlBXNmJYTHMwNXY2ZnZYOGFoZGxNM1I0UXJMTEtweDg1S2pKdTdMcENZMC9KdlU0UC8zNFRQOHZROC8xSzc5UHNxdApIRnRXVG1TekxxclV6UjRwYnpwZWRvVzMxamZsbHNBV1BwYTV5akI5cEJjR05zTnpzKzRYNEpjdGhNMTBzN1g2NXhmOUlXZ1R6eTZYCnlLL05rM1lyaVlZTmliTS80UEhhUExsUTJZajRab2w5S2hvTExIcno5cGJLaEN4eFhNV0VxTnZRdFNzVHNpUXNKeVlrWFd0Q3F1OHkKYjI1ams3bVNncmJ1TzJkejBCbTlQaTlIMWJXQlRkMUJ0eTRINVZYVWc0OXhLOTBjOThlVnB1dW1ET251RnVMTy83enpQeThpZEMzOAp6NnZsWE56NW4zZis1NTMvK2NPVHVmTS9VOUdkLzNubmYvN2dkTjNnMnhzNy8vT0hWemZSQXkyVCt5dXBuanVmODg3bi9MN0U3WHpPClZ6TTNyUEV3N1h6T2ErVUFhSGZPemk2SDVVRy9CNnBCci9yeW1hcDM0NVB1WGRudDluK3BTbWUzOCtyMUNINnZ0ekFKYVdVeUo2dmQKL1BaYldieGZEczVBS1Q1ZTdTR0FzVXJyNjZheXdubzEyc2JxM0RocGJuMXMyK1oxclNFRTZ6MUVXL3dzOGM0RXQrNG11RlcycjUwZApibzN0Y0x1WGlYZDJ1SjBkYm1lSHUrSng1LzZyUVZuMjdvTWFWdDRIaWp1dit2ZmZkdnJkY25SL1VMYnY5d2ZOM2pJLys4NUFkOU01CmJpcGJUTXN1ZkZuSlBCZlZ1UG10TEs5TVdQTzN6dm5sYU1tTGxySGc1L0szWnYwNTdKQlo0d2pWcmx1T25UbTB4NVFqcHdGdTNnSUEKeWJUdFZocXgxV2FhNFVYWkFvVjVzTHNTc2RiMmpCVW1vUnZRaDc5ZXdGbHJCYXZ2ZE1WYmlHUllsY3FWYmR2VEZYZkduSjB4WjJmTQoyUmx6ZHNhY25URm5aOHpaR1hNK0FIMW91ckhHSEdmWkladk96cGl6M21mWm5USG5mWXc1dDZGbmJWdGMwaHBacG83ZE9XbHpUVk5iCmViMTRPeE56YkxFUjZncWtiY29GMUExT3oxRTloOEl1UGNlNkViTG02VG1xRTdMbTZUbFdEYUZiKzcxenUxTnpkRHVqNTgzT01rdjQKNW0yZ04vTTJ6bTRMdlQ0NXQ5dEMxMDJwV2ZNdGRHc3lYRjFKK2Q5dG8rdXdqVzVkZHF0VjlZT1BjUXZkbkVDQWxhZnBwZ3puTHF2Vgo5bVcxK3JoU1B4Mi9icmI3djN6Yzd3NVZUbnExUzF5d0h0ckJUU1F1dUtVZFpiTXYrMWQrRHJSZCtUVmFLbnJqTTZ3NklVdTJoNWlRClgyK0JrUDdaMmJBYzRXd2FsTzJWVnN5bUNJTnR6Q1gvakVidG96b2pYSDJpYnNxZ1h1R3dzQzZEczlWbTdkMGhidnNPY1VJbGQ2ck8KMDE4NjdSV0N5RnpwbXpjenA5VXBlbDJ1RXBQbGk5Kzhjdkl4SHJXdkljWHlEZE5TRjdyeVZLeXU1OStHbXI4S0pkVVYvVjgzeS94aApkdWFQelRyeDdNd2YvZlZVay9OdE1YOVVKMlJuL3RpWlAzYm1qNTM1WTJmKytJakdaV2YrV0hQengwZDJzQjQxVjRqdjJrWVA5dG1nCjJSbzF1OS8yTzlWRDRHM2xpbVBNTGQxMHRHdWpjaWFaMCthd2ZEUW8vM05aOWxyVnRldUpXamR2MWFzY3o5dTdQSDhHWS94MmhhdlYKY1pVYnA2elhQeDUxUnEwbGh0WFl1SUNsdit0MFZ5QndyTTZOVTlpcWJNbmJsTE5FNi9vQzlOWjJiSGJKdERjby85SUtRbjZYcm1neAplYmVacm1pWHJXaUZnYnE5YkVVcmFGOW5nLzU1ZGVGQmhXK0JuTW92VkkzNjFUWGovaTJRc3NzalJadjhMby9VL0R4U3QySk5Xam1iCjByVllrcjY3SEp4ZWRrRkYyRmhUNHk0UHpBWmN2bHZoakxFaHB1QXIzRTdibVdFWFduZTJMZ3B0QllwMlVXZ3pxTHgxWTNuWUhFK1cKWEt6ZmdFaTA2cE54dmVQUXF0T3h0VkZvbzRwSzI2WTVNSkl0OTJCVURoWGFPVENtQ2J4ZEJ3WXV1V3QzWWR5U0tyczdBKzdPZ0d1MgpoSGFud0pYNnNUc0Y3azZCTjBqVFIzc0tyS3lmN2s2QmEwUEgxcDRDdHplUXJYSkdpYzA4QmxZbWIzY00zQjBEZDhmQTNURndLUzI3ClkrRHVHTGhWeDBDOWRjZkFGU2phSFFOblVIbnJ4OEFmKy8zMnEwR3p1bEJlMnpOZ1hXekxLWEFWU3JiMkhGajVPTEhMU2JFZVYwZHUKNW9yc0dnL1VwcnphdDlrWk5uWUpSaGNSc3N1d2NldFNZTTBsV3I5Q1pvM05rMmtmTEYvSVRWdTd1NkIvMTF2OWJuL3d4V20zMlhwegp2MlpCL1l0bXF6TjY5OFVLWnVQaDZGMjN1aG5jbGI3NW1HbWtkZHNFeEVwRWJjcWFlb1FUY2ZPVzFQdmswZG5aVG0vRGRycjlDc1JxCjhtSE5OWWdoWlRFOTJFYVJ0OEh2RzFaTzNPRGVTVDNvOStqeDl1cG5pOGw2Tno3eGZubTl3dVhKcm5zSXZsNWg3VVZVVGxhN2NTSXIKQitNTUx3ZG56Vlo1M0dxdW92V05WYnA1ZjhGcWduMDEyc2JxM0RocEt6NC92Q2s3MXpZZGZWZDlJWHA3ODhLWXlrbW55aTU4V2NtMApIdFc0ZWZtU1ZoYWZ6ZDg2NTVjcnVGaDkrUnNuaXJhazI4eG1kQzJxMW1HSDFJaWpWWnpDMTVRdDROREtoU08zOVcrZTdyZFRqRFpkCk1ickN5OHM3RGVJVzlwZksreVlQNk1OZkwvcTljb1ZqMW5URjlkWFN1YThybnlXbksrNjBwNTMyZEgzYTAwNTV1amJsNmRndDVjM1YKbm5aUjFodmpLZGhpTmVrS3BHMXhIUG02eUliS3F0Q2JKU1dqc2NDaU4zLzlyREloUytJTllrTFVXaE95SkxsUlRFaTYxb1JVMzJ2ZQozTVpXczZwWmRlMzN6dWFnTTNwOVhxN3dvc1FtN2FIZHp1aDVzN1Bzc0xaNUcraFdQOUd6d1Z0b2RUbTMyMExYVGFsWjh5MjBPaUZyCnZvVmVTZm5mYmFPN2JmVDI2Zm9ZZDlETk1WWHZIcFZjWTgxb1c1ZmFocjRudVM3VFlsc3pJRzE5SXR6ZFUzNmJtd0twYXBxZ3pWUG8KcnVUZTJveU5acE56TzUwM0FWWGwzQ0tiSU45RkxYSC9uZlhKUTZxU1RKK3Fpdzh1ZnVOa1A0YXF3K1d4WnBzbk9GWVhpWnNpTitqdQowdE1LQzNBZEJjZFdKMGJaNWt1QVc3d1JiM1pLa1hybGM4bTY1eFNwYjAxU2tXZGJmeWQ0bTQxeW01cU80K3F6YnYzZE1kc1pFWWhtCmZSeXY3MjRpaGZHNm55dzJSVHhzY0RTRHFQNGk5aWJxMy9GeXFuemxjRlBXMDFWa3hhWXNxYzNXd0hGa1hwNlZnMGVkd2RhWlVkWkIKaXEvTE9JK2FwOVg1c0FrMlQxbXI3UE1oMm45WXphZzVWdWYyRW9GZDlsb3ZOaytvYk4xa2EyUzFwUFp4VExmSHUrbDIrOU5OZkN6QwpiZitXQTFYb1BJU1h2YjhiTkh2RHMrcXZYYXpQN0w5aTlQM09hSEpiUmhNN1lOdW9jRi9sTUxFcHg3d050cHhRTk42RGJ2ZmFwOXZtCkhJZXV0ZzQzWmE1dWFCam9kZlRoS2s5WTNYbndSQ1FuRDN0dC81UVZnalJDVHI3dDk1NERDc3JIVkxmZy9mSlZweGYvc1BmdEJlRlEKOXFmamQrZW4vZTdlM1FmdGR1MVI4MjEvZ0VKa0w2azlnUCsvL0dYdkV2NmIxSjd0SlExVFpIQ3FiUWlWcTh6RzdEU0VTYkpjd1FlVApKVHJQNFVPZUc1bnAyc3ZtWG9qeGVma092bndESDM0RzBDODFrZFNlMXY3NVUxSnJZd3N2OXVwSlF5a2o4NkltUlNQWFN0Zk85K3JDCk5FU1JLQ2pjRUZxb1dsMnFoaTdTdklhbHBjaWhqYnJVV0RHdDFZdUdFYmt3dFlPOUFCT3lZZklrcXgzdFlkVk1GMUJWSm8wa1VRVjkKa0Zyamg3U1I1QWJRaTZ5Ukdwa1NKRFdGcUxXb0R6cHpNSWRVTjNKcHBJVkFWd2tpbE5JQmd2V1NScEZMRlpVcUdsS1pCTnVURFNscQpkVUNUNU5pK3lCdENxQlI3N3JsUUY2SUJ6UnJvdW1vVXd1aFE3R2d2YjZTSTBPS0JocElpU1VORFFnRmRjY3V0UFFBVktiYnB5MmdZCnJWd0dxb0JNWlFvWmt5NEsrSVRNWnY3QTM5eGtXV0FoRG9kT1plRHp3WjRIOFhBY0VVZ1ZORUxhQ0MycFdxb05BUklGTXdZQkVzZW0KZ000ZzB3aFBrZVRZVmlOTnRDRThSYU1vbElsQktjNjFGRkRqNE9aWlVVdEZJODBLb0QwRHBoaVRJNEQ3azBvcHNZc2VCTDB1OGxSWgpQREI1TGNzSWhHeVJCQ2pzTU1EVUVCb0hENHFtS1l3YThBZG1weWdNZ1ZRS0k0VFRRSnZNQXNaR2dnR3RQZWhYWWxJZFFDbndRbVRZClVvYWpxbXZSSElBQk5pS2xpYUdnUHlyblVraGZrU1JwRWZDRVNSZ2F3OGxMREk1S1FRZUV5RUtuY1ZvbE1Lc2l3Zz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJY0sya1F1cEFmUjE1WnFRT0RLcW5NcXd4Z2tBblBZeVpEZXNPYWhwZ2dXakl4Q1FXZ1lHeFF0NklBbm5qeWVVK3d1QkRZYTJ6bXN5aApycW1waGxFNVRDQnBZTVVBd3cwc0NLVjFEWlo1a2lvSkZUd0VhRWhTYkJmNkM0c2lqU0N3SGtWUlNJbWdYQUE2WFA0UzBjS2NTZU9PCnNBUTYyRHZiKzM2UGhGZDd6OVR1ZmxwNytlUGVuWk5ab2dxZ1Z4UldVSE9HdUVMbzFRU1c3Y2xWUkJiV3ZJclFpamtTaWEwN0o5T0MKNjg3SnlxTHJ6c21WaEJkVXU0cjR1bk15UTRCWjRNb2lqS3BOQ2pFQVRvdXhPeWRYRW1SUWJWcVVFYTdWaFJudzZ5cmk3TTdKRlFVYQpUSm9yaVRRN3ZhOGcxT3lLdW9wWWc1b3pCQnRDcnlEYVlQeFhGVzUzVHFiRkd3elhsSUM3YzNJVkVYZm5wQWZhNjkwSHZYNnZWa2hECk1zNHBlMUM5S05JQ1dDMThzRGJvZElRTW1BYnp4ZVFGU2orR3dKQVdLcVhWRDNJQVZwU1lCZUo2UjZST3dtUkpaNEZ3a1Jja05MamUKTklSNGxwRnU0SG93RFFtMWFCQnhlS1lnb2ZsSjJvNW1id0hUTEFpd2lHSVlwV2syQkdCb0JJZHVpaFVSTUhRNTFKNEZDK1NIL3N5Qwp4WFduMlJKZ2NXZW1XUk5OSGVMTDl3Q0JRK05vN0d4TWdnWFdURkZUTU9FTlNFT2xZZlZSZTFKSmU0aTQ5NkpzZG0zSU5WUUFsRTlFCitoeE9vK1dnVnh4M096YnpLcHhhSGc4NjdiK1ZGRHQ1NTBTN00xZFUrQVdjWllhakFjVkhmT2VPWDhERzJyMzlmcjg3VnZKaEQrM0wKank4N2JYdllCZnFtMFdHV3pjRW9JSUpqMThsZXdiUEFuOERzMlduR2FXci9jalRxOTA3NmIrRjRGeCttL25RSmZEdDBpMnpPQVVtTgpuNCtTMnFzOWtCaEpJbkNQeFRXWDB3YzgyZmhQSUdhay9iMXVkd3FaNUxnbjRaZk1LbWcxcTVUSkd2MkkyR3dsM1BrTGxOQXdNQUpWCk1QcDd4RzNTWnl3SnV3Wjg1dnE2UmhoQnA2WVdqdmE0MlFKT2g2NDRkaWZxT1NwVkNSQ2ZDcWg0am45Z1dtall6VUVvRzQyYmVjTEYKNFpQdFNPTElkQit3WUlZOWdCNG5FcVU0NFRDNDZSQmFwRlRZRHRFSC9GWExyT2FyZ3FKVHMzeHpUZFFKdGU5bVlvOGIxQi84eGtpdwpDWXY1d0JKd3RMZC9pbXZnK3g2ZTBOdTFWNE5tdTFQQ05Fby9wVUd0RnpqQUlycnRJbXI3ci9DY2wrQi9VS21CM2hnOE5CTUFtc3NGClNQTmNBRWRlbm84VjFETUxTdEJiOWxzVk1lNVh3UWpuZWNTSXc3Uy92L2VuNzJIR3czYWl3elNOMkhRZU04OTlxTS84RkhOK2JFeVkKbjNYSDBMSGhuQnByT3dzT3duU1kvc3R6cDdzWFRha3d6OXdNNFFrU0QyMDg1QkdSclhtRExDc1BNaFFDVFcrTTB6a09pWmdjNUhSbQpRZFRlSmdaNVBzYjlLaGlGRWRFZ3o1SGNxZ1pUUVlEdWVRTkNXdHlXa0Q0WWxPM09xSGJRSExUbkN1bHJNM3RKUStzVlJzeDlza3RGCkZuVHdrMVowQ3diUUYrTUVPUjYxVWxMNTdUZjRBcnFhKzBybkZ2cmdrYmtQaUJUYWtxaFoycjhrNnZpM3FJcEZZMlY3d0Q3V3N1dVEKKzhCWW92NDdxbGpvZ3hZQXhjL3Bid1pyRGRRTjZmNktBZ3ZEdndmRUMvaUFyQWcvMXFNNmRZc0hTeFp4MzZhK1VkL09YREhiNlhQMwp6VmhXMCtIQkllVVAxSnFodjhTak9uVW0vam11NTdBZDdFV05ISTAxaVYwQU1UcFhQUUxOcUFhYXZCRGJyQXNkTmtmbG8wN1piVStyClEzYUphV0VVTFRLVkNnWDZaZlFoeWJRQzdSYktKSEJDbmZXQjFoeXN3R3FyTGlQVm8yN3NmZ01EakpNaDR6OFpEUmdneTNScWNJRnIKYVpUMmQxVkJNMDV4bjB3YVdacEpQYjNlNFF5SDJMTWFUYkhNYmpPRy85Z1pDZHJkSHU2K3RodlVNUDVGclZyN1AyYStlcUVYN2p6dwpBKzVjdWhhMkFSRDRDcVIrbHVHR2srQjVSTTh1a2NQQkVuZUdoVGoyRitPQTAwYllXNGllYzA4ZS9sV1dQaFdvdlpJV3RhQ0xaaW1aCnlWSXl6Vkl5ZFVUbUpWR0dtbmtkTFJKSUthcWpqbUwrSytiVGFvcEFySnBKYkk1VEF2K0tMTVhtbFNNU1ZhcjRoMXc1eXFZcjdNK3MKWU9MeGdsK2twVUphSWhMYmQvZEhMcWFnanROblpTSWlmVVdrRThSa2k0aFpVSEdTS0cySjBwWW9OeUR1ejRJcFNFU2w3MGVTR1M5UQpKRlZKTW90SVN0MTBFMjY2Q1RmTjB2RDNRMDIzSko1dTJUZzhGOVBVSlBGc215Zy9TWVMwTkVoTFFtSjc3djU4d01tV3pGc3h5WndWCms4eGJNYk9Jc081S083bEV6YkhmL2ZsZ2t5dFp0bDZTT2VzbFdiWmVwa2hLN055U2RncEpPNk1TLytjRHpTdVR4WU9pSnVENUZDRmMKZm45VytZbitTK28rYWJjMG14TDM3NGViVXVPOXo4YmhNMWJGZU8remhiMG5xeXJOSEZtelBMZi9mcWk1Tk43M2FIYmJ6azh2aC9ITwpUMVlZNnozSm4vTTlKMzYwLzBNV1Yvdm5ROHdkTllmN2FnNzMxUnp1cStuKzQ5elJORk0welpyVS9mc0I1NDZhTS9QVm5KbXY1c3o4CkdiM1gxSHVyUTFxZTIzOC8yTnk1TnM1Lzd3OFUvdkNkTkFvcGhmQXVDUFNzQ0kxbmNGQzdCVVdPS0s5MnhTdkZxMkRDcXZPQWpYYVoKYzk1WGVKY1IvRWZ5UVUzVUhseFEwNnJtbFhvOFFyaElsWXoxKzFpeGQrcitIUDVtaS9YMUNha3NzbkZkTTdWellsS3BJTFYwUnRGQwpXZFcyR3RaSmpXTWVWcU9YMjR0U3FDd1MvaWR0V0p2aHRoNW9CLzJMZHYrWEdlWjlzaDBsT0lsV3NQSUx0dktUcVZPamQwaVRsL3A4CkNuTGtJWFhUVVBRaEF1WGt0VlZrN3RRWnVhaVZxKzVLTU9CZ0Q3M0xOcmFnOElpOE5kVERNQ3dBaXVtQU8wQk13TVd3ME0xRklJK0sKbXl0Y0dkOG5CbEI0QnpWU2VEUk1IRU9ZZXNZNnlUSTBRTTJjc25kUmFHZEpWcGhQUTV6ZS92NkRWdXZ5L0VWLzVHL2FRdVc0WnUzZQp0LzNSaTdMVkg3UmhuZHQ1U0hvNC9ERXBuS0ZOYW5BUnBVVmlwaGJBd1lNbmo1MWsrTzZzUHpqblhFTTBDMkdPdHZ1bjVjbURKOFVKCmRQZDQ5SzVibm9TbW83bUtMYjVzbzhpUlZ6ZzZ3eXBtZnliSlJ1WjY3cWNkam5haUMrTkJNQ0ZzbWF4aDZBY1BDR3oyb0docUJoaFcKcENHM2lPR0RtMkYrSHVaK1Bwa3dvUmtSMXBOMkhpbzMzQVhYUjhUNTVMSTQyTXVuMWc1RG1BaEd5bFFhUDVVOFRaTzhxV2F2V0RBagpyTlFYTkV1RHFQVWZKSm5walNBUFJDNjBYWWkwQVdDRUM0Yk16S3VVQWxraXlhTmF1Qk9zMnRKK2haWnlNZDZJMnhwMnEyek9LdnZUCm5FMXp4NXNmcHp5TWs2djJmRzlxYVllRjdCZi9oSENZRWlEeGZoZUV5a3pZdElTYWxHRlRjbTZKN0l1MndBVWdMMW1uWk8ra0RKb3AKbGlabFZ4Q1pESm1XZnBNYlpSVmY1M0xSbHMwVE9GYWpsRTdnbUNRU2JXS3V3S0ZLS21IUnhyVkl0SzNZMG42Rmx2Smt2SkdQVXJRdApkbTZQTGQ5d2JrTlBxY3JSaTJOU2dUNVJBNmMxc3AzclBEVUNmd2ovbjNhVTBuR09GNUZ3aStoOEwrV1ZMUHk2U3ZCNFFlVzZNNm9jCnpWZjMzRkFueTBhTE9EVFBMOTdJc3d6RC9OeWZCUDFCN3M4V2U4b2ZkYnJuRXdjZGY5aFpjTWFaOUw3aElVZWtHUHdLekVNbGcxekMKY0VadHlCeGozUnpvS0lEd0EwWERIdm1LTTBDaDRoa2R2RENFTXlseVVsT2xrZVR5WXhDS1BTV290bWprR0VJOURlRnFjN1U5NVZhSQptcmxDWk43QStBQ01PaFUyK01nMHNqU25HQ1ZvQUlPSDRRQU8vUkVKbXRBSzNBSmtnWkpRWVNjeFVEblZqVlFxT2JPcVRGRFlwN0tXClM0bEIxWVpzZGhnSW5hTXpYamVVelBTY1ZnM00zRUpyYkRWdEpLbWt3S0Nza1JsUjBPYWxSWnJrczZ2cUhCRkxNalRqRm9JMUsvVlgKYUJBR1Jsc1BZMUlBZjZHN2ozeU1VUkFoYzliY3ZhZk40UnY2NUUvOFQzcHc4aDZWN1FsRHdFRzNjM0hSd2JkbXg4Q0huU0d1RVZmNgo1VmZ3enlYOG42NUh3Y3d1ditBdk5PZGZOSWQwcCtvRU9nVlM4akhKNy9KdGgyNHh2NnU5L0JZQS8vVERYU2U3Ty8zekU4Wk5wR2h6CmZ2bDZmaGtFMlhMMmYzazBmMVNON0U3WW5UdlVsOFBtcVBrRkxDT1o3YjE4OG4vKzY3My84Ly8rZCs1Ly9oLytQdi9uLy8zZm0vbDkKVHNkM3YrOSsvNjkxbUorTGYxKzJ2dDd2UHlnV1lKdEdvWUJ5N0s4c3RnRG1oZGEzYzBLTmd1WlExQjVkL3ZiYnV4cEsxVWdidUhPQwo0dGZyQkNjdlA3TUt6R0Ewb1hzY2RYcHZXSmJlSjRRbkU2aXNNSk1vUFpmcEEyUFI5ZDlQYWhJVHNmY290UDkwU1gxNWNFRUMvaG45Cit3cEJVMm9GM2hlWlVpd2lZS1JIaE9vemdYSDFNMEl4cFY1RXdLQk8yT2o4Y1JVandJS1NjZWNFMUF5a2FsVkZBM1M5SzZzYW9NdGUKWGRuQWl5bFhWamZ3NXRCVkZZNkt2WjZwY3R3NWVVVFRoYzV6WkpPWnAzRHc5WGZRQVI0OHFUMjRIUFZyZG9GMWZpdkQ2V0hxelBYcwpkRmdPM3BidEU5RHNUMnloWWJRc3dsMmJ3dDIxQ2U2Q3hNZWJKbW1HQnhyNElIV1NtK2dEZXNRVWhrSlAvbDNwdHJYQUF4cmVUSU1QClVoWTJmQ0dDSlJnRENYL3p4RTd3WE9VVUZ5M3NMd3c0c0JwMWtxb0FPeUtZRkVyRkZXVURCaWVQY0VjQTZvQkY1V0N5SVhEZ2pzWmgKYVVhdUIwWU9IN1RLTEM3YkJZWWdMdUhiSVpEMVBGaHlRa1ZQc1VjZVFhZ0xCek40WlE4WXpyMVR6ekJPMGFoUTVYd2NaaEhqM0JVNgpianhyNUhRWkxlbzBMT1BDNVBsWXIzR3RtandtdDJpSUxNdlNDSGtNNFY0SG1PLzFHTXlObzBQdUI4cDNJUnBpN21rMHdwNGNYekdRCjdIREhBQjdoS1Y1UmRLNkMzNVVSWXh5TVlaWklCZUpYNlRSaWhFSjVvTEl4RnVxR3pvdVlYVWQ3ZEdjMXlTSzJBcVRJa25qY0l3QXoKMElNQy95SVFrZWdSZXk3NDVpUDIrVzVHL1BQRStKcUJZSWM4QmpEL3BqaEYvTU9wanZjT1kvN0ZNRGUxR3lMbmxlU21QM1FpVitQcgpCcGNiYkl4ai9KTjRqem1McGlwQU1ySlBCZXd4aERrWVlJR0ZNWXpJOU1nOUozd1hZaW5EWFkybERCTVVwSXdubXFWTUJQQlNacEpiCnlFTVpNY2V4TUFZUmpiaC81anBpZy9CM29UMy9RTVRBYmpRdWVOQnNtWTd4RkdPSVpacEhTM2dNNHZnWHdUei94bUJJWWtET1hBaGQKQ1B6elBRM3M4OVF3S05Cck1jZmZIZSttdUlTc2d3MjRNT09zaTBGRW5nWU1PdWFVaGlhVUdaTitDamE5UkdZeDUxSWdKVWtqeHFVTgpvMENGQ29oamdHTmJBSG11eFNBa3plTmwybjNiZ1dXK2g0RmxuZ29HQlRvdDN2aTdZOWtVZDVCbE9VZ0VxY2UyakJoRWxPV1JxQ1RhCmMwQXBUQjZ6TEd2SU5FdGpqbVdnSjJUeFZtZ2FPV2hyT3VDTkFZNWpBZVE1Rm9PUU1vK1hTZWVtQThOOC93TERQQTBNQ2xSYXRQRjMKeDdBcDN0QnVLK3psNkloaE1ZZ0lFeUpzM1haNUN0QWM4N0h0UWVENlVXTWN3NWJUV0FoaTEraEN1MGNjQVJ6SEFzaHpMQVloYVI0dgowKzdianBZbDl6Q3d6RlBocTNrNkhkN291MlBaRkhmc3J1RFVGc3BIa1dleGhsZUF5cGc3UFlCVW9xSUJla0VlRkR6K0h1bDNESXJVCnUxRExLV2tCcndOdzI1RnlSd2NrazhXNm5aQjg3SEtJNGEvSzNJWkRqVE1nS0hZTWlmUzZVSXNwOTNnRGdObyttT1lPc1l6Vms0aGwKRFBLa3NlYmppWGZhVWNReTFxRWlsckdpNVd1eEt1YnhNaUJpbVFjRmxrVWdTeG9qOXNSejR4SExYQThqbGpFUnZwYW5uUEZHQUdiWgpKSGZHZExlSVpRenlwTEd5NDRsbmpTamlHU3RPRWM5WXUvTFZuUHJsOGJydkVjY1lFaGdXSUpZdVJ1b3A1NFlqZm5IM0lvWXhDYjZhCnA1c1JSd0JtMkNSdnhwUzFlRms2VUZnK2JwOE5DOHlwUHhIRFdFdUtHTWFxbEsvR3lwWkh6SUNJWlI0VWVCYUJMRzJNMkZQUGpjZnIKMG5VeFhwaU9qTEF3bVhhL01BUEFMOHdKL3NUYVdlQ1o5Qnl5bExFMnc2U3p3aE1ZNXRXaXdEQ3ZPekhJYTFlTTFnTUN3d0xJTXl3RwpFVjBlTVZQdUd3OE00eDRHZmpFTkRKR0JmWVExK3U2WU5jbVhXQjBMdkdJSUU4VnFERlBObWs3Z0ZhdERnVldzTVRHRU5Tckd5ZDhECm56ekVzeW1DRUQyTWsrbmxWZ09QdUdlQlI5eDNobmhxSGM3b3UrUFJKRDlpL1N2d2lDRk1UKzdGdnFXWGxadkFJdz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJcHdBRkZyR0t4QkJXb1JnbGZ3OHM4aERQb2doQzVEQk9KdGMxR2pqRS9Rb2N5b1BnSm9pbjFhR012anNPVFhJalZyZ0NoeGpDNUxDaQo0bGVjMDJVQ2gxamhDU3hpbmNqWGNUcVR4K20rQnhaNWlHZFJCTEZtV1llVDZlVldvNVhtZWhaNHhIMzNkWmhheGhtK094NU44bVB4CmxkN3I4bFVtMXVMOXdWeVdwa2IvL0lSM21OTmt0c3ZTbDBHUUxXZi9yZUN5aERGOVg0K2w4NnJ3Ly80M2ZIL2ZILzlyL0gvOGFmZWYKM1gvOGYyYk1vZi82TUxOdi9vOVgvYy9IN2hja24rQXN4OFlFdExKcnczbnpKcHdiRm5vRjk0YXRPT25nbUlDdTRPTEFtbE5PRGt2cgpWZHdjczNoblUzemh2c00rcTl3eDIvbGUwUUVDRldlNFFDYWcxWjBnVUhHR0d3U2dWM1NFVU0wcFY4Z0V0TG96aE9pYWRJY1E4Q29PCmtWbThtOC8wV1k2U0NlZ0tyaEtvT2NOWlF0QXJ1RXVvM3FURFpCeFkzV1ZDUkUwNVRRaDZGYmZKTE00dDRQSU1kOG9FZEFXSENxYWQKbkhhcEVQUktUaFdxT2VWV21ZQldkNndRWVZPdUZZSmV4Ymt5aTN2ek9UM0Q2VElPck94MndWU0owNDRYU3FCNEpkY0wxcHgydmt4QQpxN3RmTUZ2bmxBTUdTVjNkQlRPRGEvTVpQTU0xTXc2czdKekJtT2NwOXd4ZStMeUNnd2FyVGJsb3hvRlZuVFJJelpTYkJvR3JPMnBtCmNHcytZMmM0Y01hQmxWMDRHQVl6NmNTaHBMcXJ1M0V3SEdmS2tUTU9yT2pLUVZxbW5Ea0lYTjJkTTROWEM3U0thVGZQT0xDeW93ZXEKVGJ0NkNMaTZzNGVxVGJwN3hvRlZIVDVFemFUTGg0QXJPMzFtY0d2Um5qYmxESXFBSzdpRElwMDRtSFVpbFhnVmwxQ2srZ2J6emppdwpzbHNvS01QQnloUHB3bUlGMTlBTWJpMWc3TFRMS0FLdTREU0sxTjR4eGw3RmNSUXB0Mk9NdllyektPaTdZNHk5aWdOcEJyY3E2THBqCmpMMktheW5TYzhjNHU3cDdLYWl6WTJ5OWdvc3BVbkRIMkhvVk45TU1YbFZRYnNjRndSVWNVSkZpTzhiV3F6aWhJdlYxakxOWGNVUkYKR3UyNEtMaUNNMm9HdjVacnN6Rm5WM2RUUlpwc3pOWXJ1YW9pZlRWbTY1WGNWVUdGamJtNnVzdHFtay9MMWRlWW82czdzNExxR2pOMApkWWRXMEZCalpxN3UxQW82YTh6SjFSMWIwL3hacnEvR25GemQ1ZVYxMVppUnE3dTlna29hTTNKbDExZFFVbU0rcnU3K211Yk9jZ1UxCjV1UHFqckdnbk1hTVhOMDVGblRRbUpHck84aUNWaHB6Y25VbjJUUi81bk55WGphRWE0KzZ6eGRkTWx6MVJ1eGYrK2ZsWk5Mb2lVaisKNjhvY25hcEdsdEtEUEtrb0tLK3hCTW1hNGhzeTlHQ09wcEFDQnVIN01pckZyTWdpblEvQ1YwRVNROG14NkpxMHZXRUJ3RFNsZ0E3YgpKdG4vVWlta0RRNHVHaExJcUZFcG0zOWFnc0lqcmRhUW9HSVN3d2diWG9FaFFKRlBBNmhXUXBlNENYZUVlWkptaWcxSmJEVjg1b0xZCndLa1VIT0JvTCtSVzhEM01YVHI1R1NCZnJVNlk4M1FHQkJXdVJORTFkTThtQVdlM3JLQkUwYTVIb2RSRUg1ZmtnOFkzblVBYWFWcFgKb3FheVJxWXhzWUxHNTVTS2JVNnA5YnpaSzdzbkI5MytzTFJQWnp5YlRxMjE2dXNaUHErV29hRkNrd1pNRWpUVTEyeEszc0lGeE5rbgpzd3I2SDM2bGQ0SHdkaEtGNHRsa3pwU2d3LzdDTmFnRUphbXEyUXdjdGhVYmpHdkxnblpTQzU4UlgyR1RPMGN0UlMxR0hlVzg2VG1sCm5NdWhsS0JEQS81Vm1NMEQ0RG4yRC84UUdReXZoOEwxbk5xMEdmbU82Qy8rSk8yYlM3YUMvYkdlRXgzMW5EcnZmNGtxNUpZZithSmsKZDVXZnZoQTJSL3hZcWpsS1lacE12b29nWmhhVWlaak1jemNmNDM0VmpBS0UzOVRURjFtWVlzUWJtOHQ2ak45MVluaGdxMk5UM2ZJcAovUEZERWczVTJBakcvNFl5b2FJZFNvdlBqV2ZVYnRRZE41anYrM0FGWmlDV3lUaWZNSnRLVmt5bUl5eG1GeXp5eVNHYWozRy9Fa2FUCnpzd1lhWk0ydm5mNkVkbkk2VjRveUc1VUpGMDhxNUpvQytYZktFUXlsNFdvMmQvb2VRRCtCTCtrTUZZVXp6ZU9hbUZTa2l6WHNCRlYKU2twU1o0VGN3TGx2YWtaL1p2UTZGSnBDdGFDUEV1OTlpa0s5WCtJVWpmZG8zVC9xZlJKRWl0dmR6YTZmd0EzWXJ2c1gzMThzZU9OcQoxUlNZUGp0TVN0bW8wRVpEMlg5c1RsSlNwTkx3VWZxUDlhaEVQYzBibVgxcHFxNHdDMm5kUDNSbHY5ckliUHhJc2M3MEtUeVVSWlhwCi9TeEVTYzlWOGFjajN5MzdCWXJpQTFqd1pReUhRMzJ3eDgwZDdVWDlRSVhYVmNRdXhvVHlYbzhNcUtjRllUbDNuOXhUVnZReFBKeUUKeVM3OWswcVdCZlNjbFhRZkhaUHNBMHlXak1TeGlDcFNQY1Nacy9MaG1zV3UrQjc0RXZoMkV1WFh0QThxTVRNU3o2T0VSeWg4c3QzdwpuVHVLaGpheFRCVCtqUzFQSFhhRnlUN2dqbnlZbDdaeS80d0Q3dEpDNWcwOTc2MnRtVVZudjdZMUYrdjBlMXV6aTg1NmNTdFNPMkttCm5jZmNqSGdjR0I4R0l4cWp3R3RtTlE4cEQzbVlhQk1qRVk5UjFKSDNWeTd3RGF1SkhWNFdsblZqNzJKaCtubDZoR05tWWRqaHAvSWQKTDhTOFh4WHorQnRaWVltZDcwMnN2WWwxNmFkdTNjL2R5WFVXcjBBM1hBZlJhbzJXY0QwYTdqa01GKy94REpreU14Z3U3TXVvY3dwTApkSjR1ZjQ0c1lONnZpbm1jNGUrbHpOSENxbU82YnpmQU9LK0ZuYjBTbjRiTEdYcm04MzA3bnVGLzNYdENNa0tvL09qUFhIWDBlL2hrCmZ6NExJMG12cFBwcVlteWtKOGY4Ykg2QzdTSlRwZ2FuRkdDSTJ1WmNjODlCd3h3dFZpaXV6N1NHWXFHUmFIeWMrWHpQcGpjeEF0OHQKQnJtUUpvSk9YRm1DRDdQaTYyRDhtUjZ0TnlZTGtDTVBRYU1wZWxnaUNLcmVNSWt4elM2KzMwdHZkS09keDAwVFkrM2RCenh0UUd2SQpETnFPOGtaU2FHdVhLMHhtRFc1VVpBckFPSTVzTXQreFZ1cVQvYWhQZHZWZ3J6NU5UejBtMkZyL3hobFNqOWxWanpuWnN1L1V3VWxECjB4RVluNWZUalRSVHRYL1lsK3B5KzNxeXg0bFpPaWtLenZESEEwZVorOHFFQnNKbmZmV0ZBeDZ5TE1adFJNMkhidG1YNzdpL01TbHYKbmFvR0RNNDB4Zk9BY3BlYWxDNFNKWXBpcVJ6a3lFTmtabTNqUjlQVjdMMHRYNHg2Zis0aE5JejJjbkRtaHpYNkhnM0hIQURqUEpwcQpoY1FmbGduTjFzZStNdzZCV1U2RmIzVGlhNHdPSCs4enhFQW44dHczTnh3WlZuU200MW5mZmVsNlFFUmZHbHFsQlVQcWFCZEdneWk5CktwNkZJYU12RFMyVkVpamxKNzlvN2txb1BvRTV0SHBRNGRrK0JZUnJZWkhsNlZZYloxOGNINC9KWTdkclhxY2d4cWZYWUwyUllhdEkKYzVjWXhvSmd1U3JjQzBIWVpLa21QMWxPUGdtMGhoV0NYTGtXMEtJbkRaUXdvVWpodkxRZUNRTzRvZGFlQndGKysvYTdRNElkeUlVSQo3VENndGVmNzRzdHdiejJTU1lwYTh3d3U5MTQrUGZyK3lXSHRpOXJkVm1mUTZwWW42Y21uTmJwU0FTTUY1ZUhIc1ZzVk1Cb2duM0pCCkxsMlRxWlRlT2trYUtlaGdxZkV3OHUwb1NiSXV3NmZvRTNLNXFBUjFWMHpVSlZFR3B6Q1k2RnBPYVZBVjBvYS9KWGgrZ0xKSjZ2aU0KVDVvRE9sRW9HMUZvTlA2VTRQclJRdHBMN0JhR3dqTXp4anFEb0M4aUo0dGFnWkVHTmZ5YlpXZzhNN1E3VFJKeU1FVWFTcG9DSDduUApaVVF1TEZ3WVVCMlZBbGxwaWdRblltNW90T3FZYWR3R1JzTnZtVWtwRHNvb2RKalZjZUVMbmJ0K1d4ak9BMGtaMmdRSVQ1UFM5TWs0CjZNRHVuZkJMU205aWozZm9ZS3FMQzNRN2dWbU8wNXFDM1N0REk1MUFucEFocVNoMHZzMlM1YmhzRGxxdloyUVd2bWJwQWxzWExuRmsKc1JJdWJWSU9lMnRCenZGQ3A0YjBMbkxpWVF3aUJUckQ1cXFFOVg0TG9hMXdFVW9sR09xY0ZETExNQ0YxQnZNWW94QndvdU1Mc0RDeApDcE1VQ0xDMkg5eHpNUGNkckMvWVJrbEd3VWNCNnhMVDFtTzRHS0tCNnRBTGxFcEt1dldTcFFtNkFWeVRXS2xBeHoyY1ptQm1rcElGClBjMEtQUFJubU9HUXVvUEpEclY5UHpkTGhNMXZXR1JBSHI1aGF5alNHeVBQSkFHQUl4YlBCSGU2TkhXbkxtVVYwZldzR1prYTdiWFYKWnphRWFiV0J4T2lycVJGQzRPcGpSTkdWazZOa3d4aFhIU2VvTlQxU0ZLdTIrbGpaWU5lSjBYTEpLVmNkcnhuY1FseTR1M3hQWTBDRApjK2NrRE05N0RBdVFBRUlON1FDWjhqR3ZlTUFRTlR3OUZOcGZja20xZFV6WmtFaE92V25TcEVDTkc1UlI1WURqS09mQnp1aE15aFI4Ckg4VjFaQzZiNHArdVcyem9oaUJIUDdJYlJqcWxiVWZyUkVZZzBBcFRlaVZDWU41TWVybElGclIxNEFOYm9JL2lsWEk4aVNsN0FOTVkKZlFSSGtqU2g0MVZTb09NZmtHRXdCbXhZV2ttVjJ5clN3SGFwOE9WcEc3Mk9FeW1qd0FDODFRQVRML3ArUUdrYmNNOWxpR3lBcGx2ZwplQmlhaXJCdlpUaFkwRzBwaFV1aGd0RStDdHJBeFVXdlp4VGFuaGxncWtsQmk4THUwaGd1ckFHUHpYVUNyQ1NER0V4VmpWT1VJdGNUCmlzQjNYSm5pM01IZUl6ck9oeDlTRzJ0OERuc3Q5TThFQ0xRTzJBci8rRGllZHh2S0dEcDZHbVZjdmhVWVdMcGtadDhBQjRnUXVhSGEKN2hZVExIK0Z2OEFjVURtdUlFbzVVdVM0VXVHb29QSFpYL2lScWtsWTlpUllwRlBXOEoyQnRDQ25BTXdscmRHM2x5clkrdUd2SUFFQwo2cDBRTXZWRHdkOVJFMGh5bUJRZWdyUGFHQnlTSkpYb2RFZ3hISWVDWnV4N1dERGNDblVRTkpuaDZjbytOYUFLVkZkTlErblVwclFGClFXUjFVNHBNZ1Vya3A3T3gvTnFHaTlrNjJHQkNsemFBOVlJZWhiT0JYSmdCUW9CaTdKTGgyZ0FnSENHaExNaFlZWWVDUm9RUm1ScTAKZytseFhCenBnbjVQR0NpQm1WQXIrQlFWdmNBM3NmM01WcVZBM1VhdEMwNW5hUUVEcXpCRVc5dUR2ZFJiL2N6NjhlcytKWlNvSFRRSApNK3huMTI0NkV3MGJZb2ltWG1kTFNJUjlqaTJSYkUxSVJIVHNsNWtOS2hObzFrM0l0WVlkS3hCaXp4VVlJb1lQU0tLYlBLRkllb1RrClpBUWpPenJPZXcvQ2JjWG1yQUZJUnRFRzBCYU12aXpjZDl4UFFCZUhobE9xZ1FDWDdNeDJqaUZIRWNUWVorc2NTRkNXNVFJUEJOYlkKVTJocGJkdnVxbVhhOE1adXJJYStBR0tOaDZCbEg1WldqZ1kxaG1FMlk0bnhHNEM1U0FraEEraVZHMUkzUFFoNmhBSWtvRUhEczBWagptK0x2MXBKbnlWQytkUWRDUzQ3N2FxOGVLYjZPQ3BLSk5obURCNUdVcUVTYWFFc3JMTWN6elYrQjNhNGJEdUM2Q1VzT3pqM0dmMDJwCjBkWWVmNGZXOFFhS3IyeG56dGcwT3JBWm9BcVprdHhPckNxQlVUaHdFc1ZBMWdiTVYyM0R1U3lFaGlpbnQzKzUzalRFWTBJaFpkeFoKbHN1ZG8vRE44a0pFTlFNRTFNczhzV2tTWFRWNm1naDBuUmptSzZKTnJHSHZiSUo4VmJpM0EvN2NZWU50TmNzb0t0Q0RRbWU1M2pTRQpNWEd1UDlxR1F2YzlDSmNWWUkzbXNxUWd4bmd4QnZSVG1Kd0VyK2R1ZFpJR3lrK3AyQVl5WnpmVytQaE9EVlpiWm1pL2NkOFZMU1U4ClVEaEF6aTA0QkRUN1NkR3dUYmp2WkhMSU1EYzZGeENvL0dLSXBzZkFnTkFHUTdnWERnVjNjb0lNdEw1QTVVeEhoRUhWSWsxOEZWU3EKWVhRWUlYL2xGdm03NnhKWGRsMTJ1RDFGNkhWQ3M2a0RwSUthNE1yOGxYSHpkOWMwVjNZZEcrOTNhNEZoQVVwSVVKZzBLRUVaR3FkZwpiOWNKMlN3em5jaHQzZzIvYTU3dU53ZjFVZk4wT2tCbGxhQVVjdDJqaS9MY2ZpU1hPR21sS1lXQm9rbEkyMWdBL0VCT0c1TFg5SlY4CmU3Ujc4RmVzcFhQN0ZjYlJGbVdrSG1Bc0t2Y1ZWcVlUM1ZMUGcxQ1Y2R3R1TjB4RUtXM01DWWFpK043UXQ2aXo5QjMzQWhsOWhxckMKZlNYdkQrT2tMN2FMZFN1NS9jNmlKNzY1YnMxeFgrdnFFUnpDZFZ3N0FvTWJQd2RsMVQwc2k5bis5V1JBQnowUmxpK3BLUk5ONjNMQwp0NzFDcS90WGFIWEdTM01UOFI5ak0rSjhiM3JHak0ybmVLNU56VVEvUjYxVE1KNjhZL05haDdFZG0yalRrMUdOVGIzM0QxRmdacWN6CldLWThzNVBwSVNaK1prdHF3aUZtMWhDdjBPcitGVnFkTWNRdVhoVWxzQ0NsdXpCMHJRKzBiMG1SeVVXQ2xpazNCdz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJYkRoQ1VrelBDUjZKOHhuckxyeVh6S1duSWFIR21XMGpuVzZEYTUxUFlNVnYrUlRHYVVpb3NTQ3lBWFJ6MnB2b0w5bys4RFU5dWZXUAo2bjFYL2pwNk1DaWJKMmY5MXVWd1lvY2lEOXNMUEsvbHhnZzZwT1Y0b2NhZTJDZzBCclFiUlRjMmM1bnF0UGJ5d2V4TkRlWlRJVktRCkVWTjdXNFlPWEtYdDVoYStITGt2ZGZkdCtvdjdQS1JwWTBLVEtDNXptTHEvN0dVWVpLUGN2aG0rSExrdmRmZHQrb3Y3UEp5cjBxRHIKRmhRWWN1SFdDano2SlpRWUprOXV3Z2Q3WTVPRnNyZWRmTnZ2VVRnTTlMZGUzd3NKSCtNZjlyNjl3Rjl5Kzh2ejdpWDgrK3owNTdJMQoyck8zNUdyN2c4dmg2OXJUWnEvNXFoelVuZzNhcUE4dC9LMW1menhvZHJzZGtPUVhyenN0Vi9JN29QNWVMYTFkakJxMUYvM0xYdnZlCmRObFBhL1c5dStNVlJMS3d4bmhoWGJzZ0ZGRGhVYmM1NHZJd0daNzFnSjJ2eHdvZnZHNE9XdjFtdDFhdlBTOTdyVTZYaXhPS3RpMDYKVnFFNSttUUluM3V2TGtzdTZ3WnBFajJod0Nya2hoM2UrN1RXc0t5R3NSbGo5QWNlc0tsZXc1REUzWWF2bUhrVDl5VDcveFQzRHp3MwpZeEJNN2NHVGsvMEJUTjV1U1JpT09xZXdlazRPanFHa09VR09uaEJoei9zWWFIVkRKTTBaYktBa25ocjRGZWNLL2MvK1B5Z015YUsrClhxbnBkS0psT0lpTnRadGNVN3VhMnNXUm9HYmhnRVlORmZTL0NvMSt5SUdadGFwd3VrMHVLNENCV0t1eGZwZmRxL0YvY1h6dTFWejQKWk5pQ2hQK1VvQko0TTlUTVdjaEVrVjNFam81dnkxKzRjRTJNZjAybnZ1Si9jWm1wRkZRU1dqdTQzalI4a1JnRUFkcGhXa2pMZzJRdQpEejdzaUJiMkYzN21lYmgzNzIrOS9pODkrZ0liNWQwSDNYZkRZZlBrOGZHbnRYdmZ3b2pCcG5QdkFleWtiMHN1Y3UrZ2YzNkJVLzlSCnB3dUVZaVVZOUU2dlpndFlxRlhlNzdraW40UHVldStIenJBRCt4MGluTVp3UEdxMjNxeUFZYjg1N0xUaTZvUCttN0o2ZlVrL2RKOE4KWEVYQXVPaXA3WHUybU9OQXJiSnQyL2tlN2gyV1o3WDd0YjNhM1FnUGJ1ZjNhOVJzN2Y1ZTdkN3o1bUEwZzdLRGZxOTkyUmxWSVdvQgpGaVIyQmU0dTVBWGlDcHg0eGxQbTArbUpXL3VuUUR1VS9ZRSttU1RQUWVYQ3hGVmE2NElTTnZ4VXUxamxKV2d4emxIZkcrU250eHA5ClB5d2Z2aTE3ejlydGlteStUZ2JoTnB2a2lzTFg0Y1JXME9QeE9oUDJhVDZqOGVZdWFPTndqcVpuKy9KQ0NWQlJWL0doZkNpdUxHRFEKZnJmc3RUOFVod2paeXFzcGtCZnF6eVZrNzk3RFg4dldKZmFCZnFDNlU4S3VoKzdDZFpaejc5K0hpWEcwMjUwVGU4L096b2JsNkZNYQpnRG4xWFlVbjNlNGxuV3I2ZzBiekF0VHNlM1lud3B6eWpuMTN4NURXam9DVnRZZG5aN0JSUWVudk9xT3JDTjY3enk1SFF6Z2ZSZDdlCnc4N3dvdHQ4Wjc5K2VvM0MyUzhiQzdka1Blblo3bFFTS3B1MlpqNzBKdlRCSisrMVNta3llS1JGbmtlYTJHMEk0YTJaUlZ0RVUrWGQKcEphYWRMMTNsSjNtdkRhYTgwcTIvQThpaGNTSFVBV3RSbkE0NkYvVWpsODMyLzFmRmlzUVdOQ1dhelE3c3pXSE1WeGVWMWpJVEUvSgpSYk16Y0tTaEJiZDJGMS9OK1hTT2hQZG5GUEYrVEIyMnV0Um9sbkNyN2ViZ2paUHpGdkM2UC9pTkFHaGZjN0QrUmJNMU5neVh3L0w1CjhkRis5M0l3VnZjMEFNZ2UzQm9PV3ZIMzAyNlB4ZzJPRU01Z1RFTml0YTNhdzE4dm1pQmQ5OHV6L3FDcy9WQU9oaTRxN3BZM216RUgKNVMySTVrS2E5UmJOTzJWL3ArenZsUDJiMlhtdks1eDFkd3JZblFMYzVaTHIyMnBtaW5seVI5VU8rb01lN1BnZlNzeFBJSzJvbXpVRQpCclk2WlFZRGVpNkg4NmI1N2tDek5RZWFxM0ppWjZ4ZVJiRGs2NjNEN2xiam1xeEdWSEtTTk1NZ092Z2dkVUxPSmY2QUZnYUY5MnNtCi82NloyOG51VlBFRGs0djJOU3BuanlGemJRMlB5dWJvTmZLNTJsNkdVWmc2NTczc3hjSzk3Q09TUXNWT0N1MmswRWJwQkdzZ1NYSzgKZUx1VEpFNlM3SGN2eTlxMzVicDc0RzlabEdBb2R5b1QrOGFPeUdSV3VHajdFTWVkYVludnlZVElrWW1BYmdIREtpaWcyK2pwWUc3eAova0xvTm5paUU1TmhtSDlEWmpJM05pKzdTQXFLNWNicjY4TG1mNlRJTzJSTldraGg1ckpHYkJOcmpESDRTZ2ZNRzYwemtidnBrZ0pMCk1sUUJOWnU1c2dJL3plVUpKcGZjRnBaa3VhRzUwVkNTbmg1eEJqKzZBWUVzUVhzZnpxSE1vTVZ2TGtzd3ljclc4Q1RQMGpRWEZJK2EKRkJuZkV3SVd1WUEwV0Y1UzY3bThVQitHRVIvY0dIWXJLeTQxT3FWd2VwM1NnNzU0d2NzSzZrWnFweFJtRkRBcUl6R05VYjl5TG1PdgpaNFpkcjJNdnVnRjJEUTZLclpnajJxUjVnZk1nVFZKTWp1MFdtOTJYTUJtQXdGdHNxQ1NtbU1ocDN1d3dHemc3cE41TmoyWFRRNms4Cnh3MUs0bzBBT3pjMDc5Z0dVeVBpMU5EV1JETm5hbVNiT0RXdWRXYnNEc3M3QTNvNGNCNjhIdlRobVBuWHpxdlhYZmovYUtQT25ldmkKbFY5OFJXMmhUY1ZXb3RKWWVLNWRaUnI1MVdOSzdqMStkdnJ6QzVnTlg5VGkyM08xWlhUY2l5OWFZUTVkMTQ4UWcvV2c5NnBidmlnQgpHOHljNy9yNGs0L3pPdXdBS2NUWmlmS0g1UVhNNWVHejNsaTRGemxaZStXUXpFR0ZCMU9Oc1lJRSthRTU2UGhFWjJORTNmdSsxMm4xCjIyWDE2SmtYMVdNUTU5NFNUNlFTQmEzZzFmYWVaSkpiWTRReDJ6eHZsckJ1Wm1YR1BGYjMxdmM4bDVyM2hqYTkyOUYxdFV6b3VKMFYKQlQwWHJXQ1dpWlFDYnREbWdQcU9zOHhNZnBnLzBUQXIxZXJUN0VZT25WYWF1R0E0dkVMNm9lSXZ4bEJXc3pNclhodm4zYzQ1Y2dCegpKbUtxYmc1Q1BSdFNmQ3duRy9pNU43cW91QzUyd24rKzhKZWJLUHpkTW5NUjBYTlhYbXBrYm5ZaXZwcUlsMlNBM3F3VDcvV2RhUlprClRKc1RUckIvQ210cFJqNm9KRm1ZRVlwU0pHMVEyS1c4cG5qNGozMld1TGZrdG1lUzZCdU4vdDZBTVU3ejZ4L2lqODAyTW40RGEzUE0KSXJ2SW50dGF6dXRqckZ6UCs0alo4dnVJTjNIOWsyOHE2cW1iaXRsNzNGVFVremNWeGNSTlJiSFJOeFZ2VFF4L0ErSjJsM3RwSjRJcgo1MTdDQ1RNejh4Sm1YTUkzTStuZnBKYnFOR3VrR0JZa2lpSTFqVlFrK2lOSXZBUlN0S0JRcUtTUU5rU2pLQXkrdTBCME4zSmpNQlA2CjdlVDUrTmhrMjdOTDdQcmpidjhYVE5TNVdkNjNuWXpicVpuT3h1OW44WHRybVRHcWFrcm03YXFRNzZNZnlwMCtlQldaK1UrQU5pKzcKbzU4aWFYbmNPYi9vZW1rNUo3SEorenQyWnhFbzNOUjREdUo0RlBXYThvbys3TFZEVnRHbHFVbWZON3ZsYUZSUzM1K2ZWdTd0M1gvRworYlYvK3BTb2Z2bmIzaVI4NzNscm1pMTNmM3pkR1pYMnQrb0xCd1lUOWc3R09ETkgyTjBYai9kckw4cTJRNTBZZXNHVlNoc3RWTzdWCk15NzdqN0tMeTk0V056SXo1REFJdGl3dTkzaFFsajFYVEl1c3NJbnRHMExxMUlhNmU5S3c5TUc3SmhmTzg5UlFPR0ZtQ21HaWhMcSsKTUY2L2NJV2xLZXdWUUh6WjBtWHpGMk9GbnpaZmxiMVIwNVVIcFFvb1JPcXl2TWhJcTVLWnBMc0lpY21VdTVSZ2NncUZGWHc3UWRqNApWMEw1bFNqUzJ1T3YwcUsyLzVYU3pMWUVxaHFiZDE1SlJmaFRTYzhGSjBsU1VBTE5BcEZSNG9ZRVgrQWpoekpGeVZtMEVoajArQ3VaCkE5clUrQ0hMb0doS0kydnl6TjZIVEJKaHg1cWpuVlBmelRGOEFIcjhWWkZFK0xBdThKYWl4aE44bHhtUTVOcG9kNmx5S3RwWEVOMGUKSC9aUHdMK0FNQWtJcFZBVW9vOVBEdUk0WkNLMVVlcUFXNlgwbzRGcFdSaUtFQlFwTU4waDFOaEI3UEQrVjdwZ2hFcUwxUFVuRlhtdQpIQ1lYN1Y2aytCK2FSc1JNeGlTUmRTbnhMdVdSeGljSmM4dXdsS0pYWVdLbk5yQTU1OFNsR1haeENwMmdrWUJoak5CcHZLSWg3RjJOCjFFNmNJa2x6TzZtMXU0ZWFNZWVBV1lrdWVNS29CQWt0c0h1RzhXWEtDR3NlQjBRWlRRZDhTUU1qS0J2U3h0SGlBM0J1cGtqTFFZdFAKMDBEa0F0QmxpaGVOU2ZGVk1KeXFHcTlJVUU5VElOamVLdEdaMURSN3BNMFBZaEZSdHhUeTN6RC9nUTVhSG1tcThCVTVaQnFsd1lXRgpsaGh0eHhYRElCUnlRTnE4cnhHeUJIbW1lVlZrc05TMDdRRE0zU3kzekJjOGhwNDZPNUV0bWxSNTRvVHdpSEtsNko1TWtlVFVLNlV6ClRjRVpPQUV6MnkxL3FjaE1kY3ZnWWhVNlk2bTFXZ0lWd0tMc1ZNVmVTY21yS2M5MFNyelIwaWp2Nm9qQ1F2Z2FRdWlJU0xFamVjN2MKTG1DeDJOV3RGVFdmcEtwUU5neWZIaXJ4bWJZVGZNbE42Q3dNcHV1WkFieUs2Rk8yWXlTdVlieGdmZEdhVTFvU1JzRTNSUktlOWFuRgo2R1k5VFhvVUYraXU1RW1xSlhVQ3hJUndpNm13VTFWS2l2bFZRVHBpN0l5OWdtSm5mWUtMRWdZRWU4WURxUXF0cVE5QWVVRkJOYmlhCkVrdXd2UU1WaVIrV2ErN2FENittak1XdlVMeWFRUHdnT2lJcWt3bE5BNEZ2cU52NDlNSWtGTGhFRDZZblBEWHc3ZlBIWHlIRmhSY2EKQW1hYVphQXFwSDNmSnM4a3pZZlVyZnZBUHRzL0ZocVMrVmNrWWNmTjZPR2NCRjlXNWFVUTlnRXJYakhDQ0tkUHZBMmtOQTVTOEM0bgpjMXg3c0hxVkpQbU43OXJhWFRyajZXRndwMEQrZWZLQW16aHBjNXI3bmxNZ2xSVXRPc0NaMnRrTGROQzhNTG05YVc4c2xBU0d3a25qCmVhOXg2eE9wb3RXWmVkR1kyb0VERHRIR0RkeTJLd3prV0VGeTIyOVZMTWpUZUt2Q1o2dGhxOEloelQzU1RKTWlBc2lVSUtUQS9aeHcKd1Fhc0NKbVhhVzVBcE9ZOEFJQTB4NjdTaWpYYXM5RmtWcnJsOUZJcTNYNnhHbFFpQkYwbzhoTGNYMnBRTWhvZEZPTEFBRzFvbWJEUQpUSVV1eUVLakNwRmJ3WjNDN2tYVHA4Z0xDaWZqWE5uS2loWHNQYUR4VzRUQlpTeG95OGtsb3pVeXRmTS9Vd21oelZVQ24ybUhNSUlHCm0zZWVsUGRhdDNmRU93OXRQRjc0cGZaeFpMeGdLQkppQXJBVEh4Q25TM2ZFQkRmbXVPMjRPU1hHaHd1bktPM2JYck9BTWJJM3NnQzMKWlMxTWZhdFhBVlB3eFdkY21idzd1Z1VKU3ltd3RrQU9XTVl5WDFXV1dXR1l3VzVrN0NMTUJDMUxBMnViMkNpNXI0S1hWZUtDOFFncgo4VFVscVdzWGszWE1ramI5ZWMycXg1R3VQY3NoTzE0NDREaCs4MjVwVlN3VGFqd2J0RjUzMmtzcnVXS3VIcXUvKzYrcDBjdnpjejRlCkxtclhGcHVKNG5HLzJ5NTd0UmNVVzdVRVQxd1drYzAzMmtZSTBEaHJDMUtWUlRuMkp5cTVvbllYdS90NDBIeEgyYUNldjFycDBHUDMKV3BTZ2ZoK1QyaTVtZkMrVGtHallmbWk5dzduQkJuZWlnaVZtZkhCaUdlZVJ4Tm5wdDM5VEtDdWdVbnRmRjlZekxYa041eGVhaU9ILwpUbTlESlVLalJOSXMySTFPTTlwVU5DajZ0S0hDSGtwQnBpQ1liTWRTN3Mva0I0czBvN1dJU25ubVJTY0lYMUltdEVCaGdCK1NMQ05rCkVyWmIyczJVLzMrOFcrTy9LTmhZQXNHbXIwaVFvM0FwZFB3aHliVGI5TGxia3g4Y1lra1NrODQxOEMrdmJBbVNsOGhVV1c3Rklld2UKMm02NFJVNXFqdkgvSDl0OGREcStuOEd4alFTcmhIT1hzUW9QakxVOU4yVGNwY2tQRG1ObWQwalNKVEtXT3JDOUdPcWJRQTBzb3c4NgpkY2ZYM1AvZnpZdEUwYmFQZ2h2KzVWTk1yblJoSDAwUUtjMHpVSjR6NDg0MTNKZkpENndBSkhTWXdma3J3MEhyU3VsdzZOaEdlb25DCmdZVi9lVzM5V0o3V0R2cmQvZ0RPNmYzTEM3L0szR1FHQ2EzNDZoc2ZaaUlOdTRnVk1wTjZGVnQ2UlE4a2ZwS3hHWUhXQmVrNWJxUE8KV0EyUUZpTlBGYXRDMFo2ZGVSMEt5RXhwL3dBZW1kUVpHK1lkVXJXZU9xVGFQdGlSTEhCRXBVTWg4REViMGhUakE0aEZJWkdjTkhRQwpGbU5tdlRHcHpQQm1tOVVSN1ROMGZNMXRyQStTNW1uR1MwbkNTdGMwcTJTR3pNTG1UV2FjRXNmWDVTSkYwL0VrTDhMOEVoYlo4MzF2Cm8ySlQxQ3J2NWh4MWhxUFlQRGNlTXpEdDdJalRYY3k0aVJROHYvRUxQRk4yTldyMUtxLytpQ1IrUWhEUi9CZjA2QT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJY2pUcTk5d3p0OU1QMzA2OU0zajNlZi9pKzR2eFdrZzFVT3kvUDIvMnl1N0pRYmMvTEczQlo2NWNjMVErNnBUZE5oZDgxT21ldzU4WAp4MGp5Y2RtRTdSb1pNeWpiblJHK1JJOFBhMDI4VEgvM3I4QTBlb0N1WFh2VWZOc2ZrREh2THBINjZlUmJlSmJHK2J4eTQza0lwSjJYCnZSSDByNGtQQi9MMzJoZjBMYklSMjBlSnJWVjd2MXVXN2FQeWJQUkRFNjFvdGNrWC9wTGFXUmRmZ2VyQkhMZ1lsTU55OExhc0llRVgKMklmaDRncXRidWVpMXVxamtmZlgyZ0E2MmUrNUdsbjAzR0JjWTlBY3dteXJ2eTFiSTVCRnA4MXVzOWR5dmJyN3o2ZkEwY3Z6Mm90eQoyTzllT3FPcHo2OExpRVROMDN4Y2ppNHZLSnpjNG4yT1hSL1YwUERzdWh5aVNJQ0R0YWZsOEhYdEJUWGUrWTBNcjFFenRrYWFqTldBClpYRnhPVnBTSndsVVRuWHVxTmw3ZGRsOFZkWmdMbDVlMlBMZTJRRExEWWgvVVY1Y2RvY3h0bWpRWHVCeWkwWnQvTmZ2K2hmUmIvZGUKUGozNnR0OHVaODZGKzdXN3Y1NTNlL0J6SGRnMTZKekNnbmZEZE8vQkFKUXVXK3VhVVh3QS9GRXAwSmk3N1VIcEdNY3VHLzRWL3huNQpkeWp2L3JFM1BIbmJIQXp2UjlNcEx2bzJNSkxnd3pubGVuNTJ1WjRNeDc1dEtIZDYvVjVaZ1RIZGZ1dE4yYTdDR1M3NWdTYm1WZWs2CjdmVGEwRkZSZ1RhWUhMQm1yZkJZVGw5YytnTU4vM3R5UWl6a1JDWDZPL2pBYTVXSnYzUlVOMm1oZi9HMjhsTEhvcmM4bzVFOFVHOUcKL2ZQYmxXVFhOdysvR0RaUm1VQVZCNVpZMWVsNDdldmlHQjhqV0p1dWJNTXFIWjc5c3NhNzhTMHZneUcrNGIzaG8xeUhjN014ckxMTwpvL1NYVHB0dUN5OGRYMWZ3ZGdWd05acGVseTVqeDFLaXVPVHRVaVhSNDdHTXFIZFY2SGwzMjZUa3VwRExLUG0xa2ppNWJVcjhpWHNlCkdhZjlFZWdCZUxCL051aTg2dlNxVURWZFp3MzJmQkoyeC8zTFFhdmN4MERZVzkvMFlXdTY3UzZjbDZObUczU2c5KzFIOFo3OStIM2IKbVRTcXpLNm84T2V6dHFLeHVYUmNkdi9hSEIzMlcwZjlWck9MWjZraC9UNXIzdm15UUVzNWVISVlsNHgvL2c3MUkyelY5VjZvUnRKSQpvcTYvZWZEazBXVzN5M1lhRjdRSnY5b0t5bHRubnNNdkZ5V0ZlajhlZE5vbnVHUWVOVnVsejNTQVEreGVjWHZlNy9SR3lNMnBXc2RBCldiRGQwRUJNRnZtKzEzRzkxWGt5cjNVeUJEMzhkZVJadTZBczlqUXVxblNPd24xbTQ0KzYvZjdBaHUxUldkemRza1ZsOS8zTVdGcjAKQlJzQUZwVWt3cUlPNkxsa0VjNW5GODFXWi9SdU1VY0paK2lvTkJpdk5yc284aXB1UFM5eXNhQm9RS3JtOC8rSFR2a0x6TFhEem5BVQpMSnRHNjNRQllzK3JISk1UVVVES3NwazFJbk1rRlZqR09oTDNFNXhieEdUMzlCck44YmtMNHFEc2RnOUFXcnVDNlZ5Y1dQQzQ4eHVQCnh2eHUvclUvNlB6VzcvMDFVb21RYlhyUk1Idkd5VG1sdnZPeWJuN0RoR21TUWQ3YWJTTGJkYk0zNnRTYTNVNXpPRjB1dG5IM0wwZmQKVHErc2pjcGZlUlY2TTNIQk5tc1VTSCsvQkd5amQ3V2o4bTNaSGQ4NUFLVThPYjdvajhocDk3VGZYbUs2NXphSGRLdGl1RXlnRWRFVApFaTJwMVRXYndPZFBQYzRrUTVQbGgyYXZNM3dOcEVRemtWeCtlU3JNVWt6WWgrZmRacS9FU1JJTHJZVnJtMnBRY0h3SG1ZZExvWXlXClQxWXNYejRCejNmOWk3anJWZGRmUUxCUEtsV013MlNBQXhGVndUR0xnVm1ocXpFUVYvWnEvTHZzbGdPcitqM3B0Y3Rmajh0V3Y5ZGUKcmM2anptQzRwQm1hR3ZPSGFWNDFUODc3RGE1SGM4V3g5ZlduaGpiTFJMV2h0ZTYyNlpGbHlnOEcvUXYwVnRyTFpOT21pUW5OS1JjMApwYktwZHFPeEdXL0FKVlI2NnE1UGd5NzBZREE2N1RjSDdacVlUcjhVT2MyOHZIand3b2tRa0FvcUZncXcvci9ydjdDTld1TDd3NDdmCmpDVDNvM29WTVNIWW5neTVyODVqL2UyMHRzc2xZcFZ4Z21tcFA2ZGZOTnZ0Q1lGOVRvOXFqSUdHSUdzblFDQ2MyWnZKRzB6N290TVkKRittdGZuZmdWZEVIVDJvUExrZDk3elFzSnpDU201RFY1TnFiWHIvMUJnUjM3WlVOeVZoUXREUHNnOWd0YTZkNFdjY2x5Um9yWE5RdQptaGV3RHd3NzU1ZmRabkJReW1qbkdRMmF2ZUZGRTA0SHJYZlFacWNOcGJtTFdpcVpSMldiUEY5YUZEUWlvZVhJZXp5bldFVlVyeUtkCmExblpBVy94c1RJd282U0lPcmkwYU5TQnBXVjlCNFJKODlTWDVEUEVRYlAzdGprTUdvNFlHNy9uN0ZESCtJVGF3M1puMUxTQ2JVSVQKSTQrdWxUZVJVL2MrL3V3dmVrMU04Y2w3WUJNZWJ5RnJNQmtmY3g0YXZLcG1YZUNMbk42MjBoSHFFYkRDcUJKMWZMTFNlRXVpOXZENQo4Y3BOMlZyTDIxclZ3ODZ6OC9pSHg0LzZ2VkhRQU5Qd0F3eExxelBtZG5jUDZ2N3dHUHZ3ckdkekdFNys5ckk1dVVpcHd2bEYxKzlTCkU2M2o0VFppVzFUdCthdXpjZm9BZHZqZDRYUkJsQ2QvS3djVHl4bCtlTmdER2U1RlFkVHd3L1BUc20wbDBMaW9ndDhvTk9lN2FTdlQKMUFHak4wWHJWSkhYL1YvKzJtbFBFSDRFN2JKMGZ1TElXUjdZUWZOdVFUREh1RWFPVWhaVjhRZW9pc2NjOEdVSTN3RUdweHk0NEpRWApjWERLVk5GblRucytqclhuWkY2cDc3eGVIMGU1VUJITDlucy8yUENXL1RpOFJVd1VmVFlSWTFNbC9BV1hUR1UyWWVFbGZMSVlxekhLCmxsM0txZkZpczFsbHkxVGpsY00zUHlDcHFQWDZJV0NwMXVsUlFCSnFHS3haTFJHYnJxMTd3Zmg1NytmK2FZUFFOYnRkM2hHR2swYXoKcVFvZ2lXQ0hmVFZCd3p5OGkwc04zM1F1VG9FamI4YWx4R1N4QVp3Y0I4TVNxUmtzTGduN1dSQlRkNmVWd01ueVRIWkUwWDIvcXlHagp2K21mUHVtZDlXdkI0TGFFMGZONmR0b1puVGN4OUd4Uzd0dTlJaTUrOGVyOFRlTVVOOHYrMlZuRG1yUGRQajYzK0Rrb3djUEo0clBZClBvNzhjbGpDYmtNYnMxK2dUaUd0L1ZpZTN2c0JSRi8vM3RNKzdPZmxUNHZaaWF3dmlUTmptdlpVQjRhamJxTnRtNkJKd2tPNlpMU3cKbWlzZjdMRlY2bHkweitIbmJxOXlweTdhbFpIYk1BVmZZOWJZWDF3TVhMRUZZd0psWE90dW5JV2NPZEpRTG5JUlpzWGNVckhQVGVUegpTblhPWVRFM3VuQ09xMVp5MU9jQXYwSXRMamtJeldkNmJpOXQyWGpHM29YSkJ4SzFYVHQ5VnpzY2RON1NZMzRMQmdHeDlPS2RZYnFoCjFnVFg1aGVLbWJZQVZUK3lIUzVBTmxGc2F0Q3BGQjFXRm91MGRqbnN2T3JOT096TUZMbW56cm0wQ0NNVjdKOTFKczMyczJYNDBFcXUKeWlKMWJEaW1xZTRPR3VmZXpqZXZSS3Zmd3lSdGVGcGRRQXVXOUZ2aXFiMzBaTSt4TTBzUDJvMytBSlgzNXJUZVBWbndESlFGenNKRwo4YXd6UzEyNEUvNml1VUN0dm1vc25IeXVqQXU5RXNuY1VrUDB0VEN1cGVYZUxxWngyTHJvdHQ3TmwwcTJUS3MzYVFpYkxET0NzMTUwClZwOURINHhUdDNteG5BK3UzSUsrMHc1Vzl0QU50a2p1WXFraEoveFlPbk9wdUpYVFlXRlVxUU5UZm9TWllseFA4R21sZVhzMGlIaFUKRjhkbDBZSU5la21aMXFCL3NhUUlLbXNkVUYrV0ZCdEVtVHFXTllvR2c5UG1ZTGhnSE1kVmpMQzlWQ2c4aWtoYVZqYmFZeXJvUmFFYgpGUXI3YmxRb0czVmoxaW82NjQwYTdlNWlrV2ZMWEF6TytyMUY4ZzZMRFM5UGVUMm1zOFpvQ0lSNk44dk1VUnlDS29ySzY4SWl2ZkpWCk0xaHQ1eFRDRXdnb3RNUEZzd2JMd1hiVFc0eXJLeEJiMDN2YVpvLy9zREY4M1lSRFFMbUFTMWlvSEtIUGlIUDRSeGJmaVlManBiSloKY3Y3WGk4YlkvUTNxMnF4U2cwbmRudXhIczBxK21uRUttRlhPN1lMQndUWnJmb1Z5MWltMnVHUzNzMEJrUUFGMC9qWEhEdEp6Q3ZZdgpXZ3VrQ2hVWUxoaHhLdEMrWEdnVFdDQjVvZnBpTlFOT2RNUGxld1NWT3J2c3RSYk1FbHZHV1NONHBpelpHS2hPczlkalcvdnMwelNWClduWTBhSjFINnRMZDd4dkhqWnE5NUFpbjNIYnRYM2VQZjN6Mi9GK2YxdDdLSlllemM5RG1JcFZ2bGc0SlpmQjQ1ZjA0YzdyRDE2ZGEKNSs4V0hOdWpnbjM3SnZmMDJmb0JGNDlPMTdFdFJnZEw2UFBPcjJYM2VUbkFwR1JUMXBqajV0dnlLWnlkT2hmZDhzRzRIZU1LaC9WTwo3MDEzT0lKRjVmMyszT3NudlRjMXZNVTIzbDF2Vko4dzIxN2d4VHMzYmphbjJ2UERSODZhaFZwRC8ySmtUVkRqSnNKditxZTFaL2FuCnlPYVZaZU5HdUxoVU1NdmYyKzh3cFErT0Q1NDh5ZlZoaVRNQ2YxUi9lZmJIZjM3MjVZOWZmWEsvK2ZMemI5SS9QcXZ2ZnoxNGZQNzYKaTFlOTMzM3o2SGVmMy8za29OTnNEUDlndnYvclEvUDdMNzcrL3ZHZm42cS9mSEgwcjArZWZqMjRiR1dQSHNxbitSMmgxTytUWkhqNAo4K0dyejVNL2ZIMy8zNDAvZmYzbDV4ZkRyNGQvay9mMjdueDkvK2gzQXk3MHpXai8xVi8vZnZUMWw2bzhQdWg4OWVmV1lhUHh5YXVwCnBvN2EvNEQyc3NOSGQ3N0kvdnZ4NlBEbm4vYlZmOWMvZjNEZVB4ckM0STVlZi9abjgvdkxSNGZxRHovdS85ejk1TWU5TzRkbnlUZW4KTTVIOUlTdk9zaC8rL3M5L1BmanVvUEhEL0ViamNsLzg5UFdYYng3OTlQVVh3OGI1WjRlZjM3bDhkUGR4KzJ6dkRqSHIwZitjUExzOApQUHZweDJ5LyszWDM1UmRuKzY5SEI2K3oveFpqN1BpZlB4NjJ4TkYvdnY3eUw1LzhhUEZBbDRjSC8zNzE3ejU4K3VOL0RwKzBuL3h1CnY1Ny8vSWNIeC9YZjkyd2ZYamJibDN0M2lwL3ZmdFo2Mk5KL3YzdndXcDNjLy9MQm5mU1BuKzEvKy9uL2ZQYjF3U2ZmUHpvb0wvLzAKNXgrKytmM3IrNjFXOHcxKzZuejI4T3pvdFcxWkpQZWEyYUR6aC8vNW92UHZiOXI3M1R0LythUSsrT3hmbHcrT2p2LzRIK3ovcDEvZgovK1oxdW5mSDNQL2hwNjhmOUZxZm5ILzIxZFA3OTdMemYzM1Z5Yko3dzdQMHdhRDFSSHoyNWd2aE1iWU92eG4rQUd6TFBpbXpIOU9rCi9VWG40RjRUeGxjOC9lcHUvZk55djVzOVA3Y1UvT1BvenRjSFQ3NzgvWThQUHkvMEVNYmx5VC9ONy8rY0hmVC8vZG1YUDdULytZVTgKL2YxUGhQYlB2VHRBMEovTm4zNlBRL0pQODZQNWV3LzU5T2Y5TjUrYXVwdWFQN1NQRXZIVDc1OGUzbXQrK2NkSHYvdnN2d2ZZaXNFZgovazFZcU1qZW5lVDAvejVSOVBtelB6LzYwbjM2OHNlSGY3UEZEejUvK0Q4V21meUhmQUpUOTJYeTJaLy8vUEJ6ZWZpWFYxODVQRDkrCjllWDk5cy9mL3B0RzBuY1k4RDNiMTY0VktMVC9qZS9BVDZFRDR1NVhMN0JRcVFpbWY3ZC9lRUtzUGl5SGYxSG12ODNQclFmZkhmNzgKMmVIWnZiLzk1Mkd6K2NrZjlzM3A5Mzh2bnQ5NStmMkRad2Y3encvUGpqdi8rZm8vUDMzeGF1L08vMi92eTdmVFozSUZuNEIzQ1BzTwp0dG1Yc0dNZ1FCSUlFQ0FKTzRFRXdrNzM5UHh4bjMycXlydnhDbngzenAwejV6djlhNEtOVktXU1ZKSktLdVdDdmRhUUltWS9QT3NYCmg3aTdrd3Qyc3k5azRmZDltUC81RGZzVDMzL1dCWm4vZHVHQWdLbFJKTktjYlRsODBiZjlYelg3VW5OVnlZSnpWcVZvd3hDYTRuMncKK3FlZHIrRk9kOFo3YWtLcGNIU2NTYlJPcG16cjZYUytuSnFJc2p3Nk1BdlJQUmdaVUc5QWNsN3lKNE8xMko5WkY4UW9tUzVnNUdjbQpnRmdnT1VxU0JjQWRMbzg3dDQwTnhHc2xwQ3gvWVptRm9EZ252VHllRVpYQVhQaDBlcXFWc3NNbkhIRk0wcjFMakVqSGQ5V1h4Wkt0ClB1RzBESkxVUUlUa0NKK2JzVG5wc08yYytXVzR1U3E2YXo2UzQxUWdBTDB0MURCdnhSbmswQXdRcWo4Ym1KclptVjhzaThkSVl0cHUKWmlOOTRsMjhCcS9sZFVjQTIxUXFlajJUbU5TU3hGYnphdDVnemJicU16ZlFNS2xZSVZmcnJhUkdpOTdrdlZmcVJiNkIwQlFKakNnRgo2NWVjYzNvbG5hL3JCRmtJOVFsM3FqVHlHcXpjdk1Dc3B0OWtzUkNLNU1MZWx3NVNPRDY4M1BFZ3BBWC9hT2ZLL1o1bWY3bjFwclBOCnRwWmRDd0JSZGJNQWRrWFA5cGtnYmQ3SVI3YjV2YlNEbjMzWmNtRjNiVWxwUzJmaDIxNE9nOUZ1bDVRV0xIYTZaUT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJUm9VREJOV3ZWb0RNTEI2N1VNR1BDcFBnOGozYnRrNlB3dmRzMldicll4MzlYWHVUU0tOeEd3SEF3ajNmUG1ISjNNcXgreUdUSmR6QgowKzM5cG12TXB3bllTM2pLR3NjbTU2TGpjZi9PN1RTaXA0Q1RIYWZJQWd4di9uYnhQRHB5SnlySGI2Q3hwK1pRRGordlA3SnZvNmM4Ci9UU1dIV1dTNWJ3UHZETHFBQzFRcytYdy9ubVlmVHUzZ3R4VDlETFFZK0NMdjh4aEdyZFJxOFdYVDM4dm1YN0pieUxONzRVRG53emEKMllETmFDbENuczdqcFh3dEF6K2xzS2NTL29qTkovRTA3bkhrMCt4M0tlNFhCaXYzSnZvVy9wbURxakNQZm9qK0RML1ZpQVo4K2tqOQpta0dRaDkvbEtHRFpwSmVNaEx5RkpqSHM3NHJ3bFNSNkdmNVpNRmpaNGVYZ1M4OGNIQW9MeENjRWtXRUhuMkova1VDdndORzhvaUd4CjA4MmlnUmlzYUpyVWhPR2dJcS9sZWd0K2wwREFPQ3dJaEpoRXpKREZTTkdmTEx3M0dndjdhL1NiQkh5T3BwSG1TSWxlUjhPanFMaFoKSkJvc0NkNFFQVmtzU2RIU2dkVVhMcFRFMGw2eEVLSmxvTEZRdjRIRTRtQ2phU0E2Q2NueGlHYkYvWW1Bc1poTEVtUElTTTRscGI0awoxSkRSSnhZaWhWVDRKOFVXUVBQTE1ZWXNXOENYYSt5c09GYVJKQlo2QURqNWtsaVAxRnlSNUREa2VPVG1ERjkra1NLcVNGSlpBajVTCkZCTk5FOUVrTGdTUkZvNG16MkttZUZxRUZMM01TUjNnWkc2MUJLdWE0cmdXdlE0cGtaVVFsUVE3d2xkV2VWQk1paDdRc28vQTZpZTEKTXI4Z2tpTXFJc2cwajBrcFFEUTFWalQxc1NHMUpLd01VZG9TamJFWmp1TE9GL1NKSWorY0JobzgvS2N2TlAxYzJWYW51aUV6OW5rTApXUHJmQkgvRGlHVTNZSzljMU1oUnZSY25qUzRmMk1YZ3ZLTE1idSsxQU11bHNNcThtOXVML005Z21DbE9WM3NidFpYeHpJblE2VlhlCm5lR2JIZTUzNU00QVgwem8wS0NCRmhaZVo1b3kvVjRyems5dWp4TjRXNWc1MDdFN1l2bmx1ZGt2Vkt2N0hIOUN1ZUU4Mjl3VVhqSnYKZzhNRVdMRHJ6Qjh1eE9KR3ZrUDhHVnNQazk0UnVSVS85WnVjSDhBSjdleUtVMC9Mbnd0N0NDL1BiOFJ6azBWaDdpcVdPZHNLV2twUAo1eGhIR05vSys0eSs4RnczdmhFQlhGUG8yOGJXNVBhYk1zOHVBSFNENEdmZXJiL2UvTXpDY1FGTENWanJvZjR0em9rRzF3UmFTamM2Ckp4cGNFOXJxWXpuVUM2ZEd1Y3dDMzNldzRqeVU2TnAzS05OcjBMYXVhUHVvKzVSRFppeEhKdzdVLzF1ZUJYS2tHWCtxL0ZtbzVzSjIKZ01BNXlUVXlINjVjdy9wMVF1WXdWQlVSQ1RyeGZSSEU5cWx3MVZlby9FYkdITm1BWndFSlI1TS91eWxIT3V0YUsvdlNyZ0oyQjlKSgpNU2MzRURtbmdxSm5LaHgyc1FKUXlxM0RpdzlrL1J1c25QMS9PZEQ1UzZHMHNzNkJlRFdTTUtneEJaODhwOUxPTkluRjNJbmdzeEJzClRjWkpTZG9wRFZQS3ZxMHpidkRyeFI2Zk50TXZSS1p0ak5HZWFzczFCOFJhQlZXY2ZxSy9NdWVYbjhZNEdQQnd5S3orbHc5TTF3ZGsKUDdlcXU0RWo4dm9kWkFVa0RoMkRRVzVGUEJxNUJ5eXpZL0haM3hxRHkvUWs4SkhET1RKWi9QU3hVQ0xrNE10bEpvdWJNNUJLd2hyNwppMUtjNWJINFA2S1JhZTBwMTNqTmdOMmk5L2RNRC9UY3MyWWJ6MjhkNkdzekQ5NS9BelNOdHpZc3NqcFBYckhhenJjdUhWL21CeEZtCldpcEZ1TytOMldCbFdaTE1IQTdMZGpCZWYwOGpCQWtzblJoQjd5NlBmY2Z5RlI3c2wxMnVuQXVlY3hqdWFSK05nalg0R0dSamlhcVgKZmRBSzduMC9XZVNMRlQyWmcrbXBUTHFjbmlCUVYrL0F2L0hNTm1CM2FwTGswR2xjd3BrR01zbkpZSk41YjdodDhhWDc3UWRzZnJGZgp4T2M4N1h3UndDaDdDMDhIMTRqaXNVdU9NUlpUMUp1cy9BcUFhWk5lSXB5MW9SMFF4bUhVNURmQUJSMlZwWmMzRUNpOXdCWGNmdWQvCmpqOWhHRlh3ZmpTeHArSStMNEtvd2N2bmdXMFl3YzdOU0c4QW1DL1ZOWG9samtlTndPWW5uYjNYVTdiYXcyZlVNajVXbjJlRjJWL00Kd3pDZnd3VDg5RFJXeUpmTjFHYmszUnBUUGlvUVFFWFAzaDlEOGZuSU5xZnBWSDcxNTlhK0pnNkF2bTJRMldHd1VoaWYyOUd2NG5CZwovUUNEWHhneis5ekF3ZTVZUzVidmdOWU5XNnlBRXJFSzNITVd4WW0vL3lPMFlaREcva0MrTzcxZjF4YkFVb3E4MTNkdndyMmJlak9TCkRCVG54Y0hMWkFoc2t3UlVPTi9PNHRTTmZXYURqbGdEcUwvM0tHVUwwT2dENWt3eTNiWVZLbjgvSDdsUXArdkxObHl2aTJ5ejVRYWUKUmNsYStvcmtWdmpzd0RkVnFBM2wwVitvZk5SYzBOaG9vbGVBZGs2K1NRMCsyckpaM3NpaDJkWXJmQU42NWRaUmk2Znc1SEE2a0hIRAp5ajZ5SkJiV0ZlQ0ptQ254YlhsYlNpQU5nazIwZVN5NlhlRnYvdllHMTJvM3pBMHlIY3ZweEdLdWdTVmVHTU9uR3RrRW5CeHErYnlDClIzWWpWdmtvSldrUTdQNktJclQxMysvditJKzlVUWNtblNkTEZucGxsOVRVQk8rRjNBWnI0bXY3OGFuMFVzY1ZlWjRtWGtTdkpPWUQKNXdyRjBlTFBpOFJQMGJQdDQwQXpodkRzVzRqOEt2MmRYSGI0M2krallTNjR5SHdFZTBsOVNSa3k2WEMzbEgvT2Q5SWkzcUJQTHc3RwpEMkEyNzV0Z2tUTjdublZJZzhKOGdMenZPNE1WSFlCSXJJRVB5R2MxSEg0azkrVmtZVjBMY1VZd3ZZZ0RzN0h3L1RiYTVuOU1saEJnCjdPQkxkcE9xYktWNENLNExaTHFYN1hRWHEzLzc4ZXhMdkZqTkpISTd2dVZOanl6cHlCeThzVFBVeVpsczVHdjJYUGlPamZ6Ri92eGsKRTlFejludXd0OEMrUCtobHQ4c1hGNkNZa0ZsWWN3bjkrY2tOSGd3cVhlRnhTZW94SEpCaWtOZ3FXMnhsSTdFbU1odUhoZS9HRWV6SQpsS3FnUjFzMmsvbnMxNExNWnhiTnN1VVJyMlJqL2xWVytwV3M2emZUYVZYR1pMSnc0bzBHYUdLektSTi9ueTh5MGQxaGlPS1NsMWlBClErZENhd1c0NkhXcGRhYVVtU2VFa2l5dDYzL3VWS1JVQnZ2THZwL29zUXNWQUlxeWVJUmgrZ2Jnamw5YnB2UGRPdk5ncDhKUDU0S3YKT2ZObTRzKy9LNTV4RHY1cGhVM2tKazhmdmJEaXVzOUM3elgzQjNZL0FmbnRhLzl5UGhneHBKNEgrZVFvdjV3TDVjSHhXUEJNeUdMUwphYkcyQVMvMjlybS9sMVRva2w4YUpyQjlyZnJRVWtyZ0RxRG5nbFpncXJYOGhlL1dBVGg3MlBjZlR3SXJ4NjlSeVVvYXE1bURlWEFxCmZHOFBQZ21HallGZGMrR0VaenRkTXYrZERuRGlRL3N2MERpSXdFQXNaV0tSbHU3dkQwYUVWc3RDS1dXZEF4TWpGcVppc05OTy84aUMKVFpDT3l1d2RPcGVmVUVkMEMvUGtBTG9LWnpmbkFES25QQUdYd3hrTkhSTHZ3Q29xL1daZjhGd0F1Tm5wVlNhWjJwbjVzc2lZUWVEVAp6TStqSW5iMDlNT3BkckNZRFhtckRhZ284RXNzNkNVMDBBRkp0Q1QzSkJOWjJ4U25vUTNBN1BVNUpZaGx6MGJlNmlSWWc5NXJkcHY5CmRraGpBWlN2UnVWQU9JRDFoQzNpZFhjQTdLUXRtMUdUcEFyWW5sb1hPY1puZysvWUNRaHhhNVBGaURUWkFFdzF3b3JUM2lGVXlKUjMKZStabHp4WWFkR0dLa1VxOXpCb2RITkxXaGZ2eHFmL0VvdzdZZGI1eTYwakdnbHdKK2lBekRBOFhJcTR6MUJmTnVQYzdlV0JueWc5QgoxTXRPTExkZTcwWWlCNTdqTWQ2MlBTbE9zS1NkYjhIVEVNUFVnK3g2UEllbkVtWjRXSU5sbTl2YXFlQjUyYzhZUzJsMVprZk4zMThRCkZsdHhhZ3AvQVUvR2VDQ0wwV1paYkd6c3k4MGFjcFFUMzM4MkczRGJmOE9jTFNSaEFkU0J4aTc2MEdJRExBbzJSZUs5Nkg2eHV3RUIKQjE2bDkxSjFJSVpWQzhCTStxUXdHNndzN3ZkTWNrMDYrVGE0R05pYnZOeEJFZDdubjR1eEVkcFEzS2xqUDhZcFI2QXQ0WlFlSFExbgpEM29vei80ZmN6eEpHN1RNUytSdzdROERIUmxlWnlMZFJURWJMUjFQOE9qYlN6cWV2SjA4M3Y0N0p1WngyeCtZYzlQSng1emEveUVyCkV1cms5SFF1MUpibmJIU3lXL0MyQktSdys0MXhHZGg2V3l6eGZaNGZ4S3AzNnlyNGViOWdENFlSMHhpczRUMGVld1AyOWh0SlpoYUEKeWQvT3JaazYvNGFSMDR2b0FQMkFPbUNmZHdMWUk4bDY5czJUQWV1eWNHMzRXQkJ6RnFkbjB6QWI5ZnBNMENBTWk5Z0xiRWViZVM2NAptczNDbmZaWEp4cEo1OHY1NWNmTUJEMHNVeWJaQ0F3SzFXclN4QjRXaTM4RzdERnliQ3RtRWw5dFlIWkdHbTZNOE95blFNdjNWMkRQCi9kNWxtK3ZRdTBBSmo3dVpvN05yS2xTZkFvRHR6Ym1kbEVKbFR1MWYrNUhXOEx3eFdNR2IrY2ZDSWhRMkpUM256NTl3YXU4cUFpL0kKdFNlVDVKVG1SbFkvc2FxSjBVbTBIanZTVHNXcnpmMllpWmdLS0hjQURPUXJIM21iYlpQQUd0OVpCbDR1dUJtZnphYXRPREYydmViVwpYcnhWNnZhN0c3QXVweHdYemFOZWVSNU16dVRvNjd5RTJSWjI1QnQ1TjU1V0VDMEVmN0V4ZUxNMHRScmZmdTg3V1BpMkk3dVpMSTZzCmJoTkFIQkIvYUEvazVWZ0l3SGFBOFRvNEF3TDJyRUN0TmM3Y1U0ckgzck90ZHFURjBTNjJ5dnpXd016LzNnVWhTMGpsMFR2WW9uYlkKTVlzbG4zZThtQ2dpVnM2ZWJCVmNQLzVwMHRPcjVySlJUd1hDcy8yQXVTQlpaUTBpT2NvemkwTmJlRVZnVE9XbTJaZHFHUjZYTG5xUQpEb1JnU0EwVDJCem1ING54Ky9ZWGVLLys0cStWTE1hMlA4VkJkOWtHQ3NmYmszaDlGRzYvZlB6U0dxWkdmc3JDSnAybnhMWTREVHRECnViclQrUlBaVkJwdTZJbUxvOUVOc08vWFNUdGdaMHUvNk8xRkY3bmdlOERMVy8yZmdXZVJiUldPcnZDK09rNC9BdC9ZQVp5ckpDN0UKeDBKeFBRSjVtY1JYajRXdm41Nlp4MmdzSE9UV2d6M25UdzVFb0pGZlptYmVRbVdkZnhkdCtSalIrRFNUam1vdUN0Ymx0ZS9aOHVZdgppSU9IV2Mzd0EvM1BVSEhTS29ZNHpTakEzSWVHUTNtR0F0Wk1oS1FmUXpFVjZDTUhzSmt3NWhJdmprZS9udXdtYlh3bFI0NHZBZ3JEClorSEorSTF4dzJOZ0R3ZUp5a3U1R1k1MzJ4TXdsemxKbTRpQTFXaHQ4WVF0d09vRE04OEpFSHp5WS9YaHVQbExVMnBSS0RaMEYrdnUKR0pBNnR3ZklVT3RZbktiS0FGVGJ0clBFMnNVUFMyenhEbnhrTUxJeWpNdjdCdG5XY25xQ1kveXZGSnVDSjh4N0s2Q3J3elJrK1RrKwpLdXYxR1NXNGJ3OFB2QWFlT3F2WlpMS1NOVitqTHAwUURGTUxYd3ZrRUYyQlU5aitlME5kRGl2K3NXUnlzdlpyNTZXU09Sbk1UUDArCmowcXdpQi9RSkQvZVVhWDhQL09qSWh5Q2dvTXlUQ3ViS1lDRExyNVkveWdWbUdpNTNFY3lBWjhaT0hXTEUzblkvbVVQcDM5dkQ2dWMKU3ZFajgwUFlneWZQWmEvVE54VEpaN015djJzZGZ2N2dkU01LNmVjc1VjZUxlWVZmZWlFL0RlYW1lNjJ2OG1lcE5JVG1mTUVickJJOQpHRm9BTW1vZFJKTXJlM0MwbG9DQkhzYUgrY05wT1grZ0t4a2Z3TkpBSGpvKy9IczUzendjeC8rQ1FqYmVQUENGRWZMTHcvZ0l2K1p5ClpKbjdRSHdQN1NNQ0NmNFZBdnZQOXZ5d0E5ejlBS1JzVHJFcVFrMkJXOERlNUQ4Q1JKNEhnSXo5NlFhTS8rRzBoU0NtODRjZlZFNDkKZmxpUC93T3ZLUm52ZG9CdEtRaytucWRMT0x6S3BvQ3E4RGd3RkxZTklORVpqRzc3emFIL09UNmNOeXZZTk5pbnJHSVlzUUdncDRlZgpuWEk1QUVON0VvajQrM3dDTDJCVFgxYXFLOFlQVTE2dDlDcGJlcTQrQktTb2N2d1NJRm1OMERvQWFySlhpMGkvR0VRMG9JdVF0WEpmCmphdFpWVUQvZGhwdlpyQnppVUxsQmdPMnZ0MXNwNmdMakx3T1ZzSkY3UURnTVdCY1doSENuVU9ERGhUbzRPejBzSjJNVDdYeGYrWU0KZ1lPYVJzMVRaOVVmNXJvcmdwRFpOVmd0eUUyMkFvdHhzNVB0dnpUc0dJZ0Y1QlNvUHBYTjF5UGE1SVdpZEg2N21hSGl5OG9NVVB6bgorNGVwTWRDdzA4ZzNkRkhlb29VRUUzTkhXQWZCdUNYU1gvekNxZ0wyaWoycXFFQ3lLNHpZVU5IUUlVWjE0VGtTY05NSUtoSU9zcWs4CnA4a1ZUWXAzM2ZmNXJieWlMc1pBR1lQZGhMNTNraE5kamVoNHYzN1dla2tCODF1NlhmcC91Qi9xRXlSdEtwRm1SQT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJV0RBbU50RVVyUm5xNWdXNEN0eTlPakkvVUxwTVVrbEdSRVlaeDF1S2xoeEVNejdOVzh2ejMyUXovbGxyTU0xb3dXbnhMZ3BUMzhxQQpLWUtJME9KVk94TWh0Zm1BdCtlOGE3TVVkNkMzOHdTdTZIWnpha0lPMG1iRlNzbWlWR0VvMzlJRDBFWDNjMmsxemJsU1JPV3BJeTRUCnpWM24zc3ZUa0hwRS9XSUQxcklSaXJTYVdEL3BrMFBXa0FjK0szaUIwczE1MXAwVVZhL0J1NitnNFl2dWh0Nk54ZTRhZmNNV3hSb24KbHZFU2wwNXVndTFOSit5Z0JzZEpkVmFEdHhReHp3eG8vUHh2Skl2RzNLblFLT0pPZHlaK3pPK3VlOTNwNVNrQVB4SEJaQ01lWUI4MAoyRS9vUVNLUWJwMXloZTlZYVZVMk54L0g4T3dxeFQ0bDNJL044TkxvREpRZmpWNi92V213R3QycFZkTG9mTzdIako3bEQzZzArdllaCjNlZjRtOUZUN3hhTVhxeE9ZUDdIbmdPaER4bnp6a2J3U0J6cllIQ0ZWVEQ5TWtvRmN0RkFOTndQLy9WUjRnWUtpSEJQc2ZKd25qZFkKRDRmVTR5VHIyVDAvWmFxeFl5cGFUcjc3eUcwLzJDa2VQdnRZb1UvMld1Umo5bkdLdTdLUkRZMGxZR200ODE1WEUrQ3JoZVdtUzAzSQpGNmpGTElCaUZ5L1Zqb2RENHRnQ1NEd1Z6Qjk4bzZiQmpld1lKVThkWXJCZDJiQ1pEVWVZWHppd2h5L3NtQVN3bzJkM3FtUzBvWW1qCmRTbXNmUDVqdEJTTTdoTy80TS9TR3Z5NlZ4QWkvVHg4MVQ4YjBraExrVUVvWGhuNEpKRU9MTTgxZzFXRWxrTWEvcW1Xck5KSWswYkgKNFloYkQ5SklYL0hQb0ltSXV6aWtCaXVIOW1qMzFMMHlTRU5MeDlqZUswb2pEVG8vM1VsaUlUMVRFemtJR3F6bTltNWRrNW9yUnVhcQpHUm1rWWJObGMzQSt5aUR0RFREeSsvbU5RNHFLTEZtMEpXUFNoajhOVzVKSVMyV2lKVXRlb3A5cWpSQlN3SXVUb25CTjN3RW5mNTVUCk5ZaldlYm1xamw3Z1k0MDdBZExnOW9LVmFsaU9SdnBxdDR1UWhrSi93eDJIbE9Oa0N1M3c4TFhjdEdTUVpzYmhDR25CSlpFTzBxT20KSE5LeXdXb0pPQktmMG5OTkdyK081dVc4S1kyMGtYZW05cGEvbWhSU2QySWRUM0ZJd2JvSVdjbVY3bWRlcEpFR2V6Mk1qR0hQa2toTgo1Q0ppYWY0UkwxSklEVmFNL1BvaVplWWFObHRYbTNwZUR1a1lLM2xHSFdta0pTeHJuenNpUFlUVVlCVVQrR1QycEdta1BhOURST0QwCmMvQ1JKbS94YzBVS2tQYVRXQzNpeFNGU2x3aXB3WG8wbGVmYmNIUHNKUURheUU3TXY3V1AvbGdHYWRnY1djM0lnUnpTQWxaM2ZjVVEKVXNoam9ybFc5dkhNNytHNUtZbjBMV0VQeUNLdHp0OENtQlJTcVBtREgxN3NiZWcwU2MzMWFLcVc1ODhmZmFkREVtbkh2bG5JSW4xYgpOa1lUaE5SZ3ZaenJSd25yVkhkSmFhUzFnTFZOWnBLUDBraDNUeVlwcEVBblE3U2RZY2wwa2lId3h3djJucTRXcEpIV1U4WGhvUEgxCkpZbjA2MlZWUVVqaC9uSTUxOTllYUViS0lQMk1ZbC9IdFZjYTZmUHY3dThsRmcySWtNSlVBb2gyV1BGdVpBbDhzTDY1alRKSWUyMnMKK1BQM0pJazArdXcxR1ROZlhxREhBTnI0WGl3MDUyRmtTQ09kQkp3aW9YSDJhMk1YUWtyWVU0NnljS1kxYk9TS1p5RlNENGNVWUlGbwpBZGpmUGFQMEh3OWlwTWV0N1pGR2VrcTdSVE0xZm80L25CVFNYQSt2Q0JXaDUzQnNwNHdBQzBEcnU5UktGUythSzBDYVAxMm93cklwClRDRk40MVd2U0JGNmRzRm5hcWNKV09MNUtrSUtzZEJvTFlmRGVMS0JTREVSMHNNaE85OHkvUHRrRkNFOWhuN2o5RTZUampkOEl2S2EKdHZOUnkwRGJEL1B4TUN3Y1ZMbHRHMnpqc2s5N0RmeXZJL2QwaVpWSDFqUDM5RUx6QTlWYnNNbjhHcXlCeloxbnh2VTdqNGllaHFQNApzRVUvUGE2aUYxSVozaXhOWGFubmxGSjhyY1EvWlo5R0NWZHpKUDkwT1I3WVdZcGRQczhTdHY1VTltbk52VWtUOGs4bkw5OEo3cW1JClltSHppMms2S2N2OE9scTJsWlB0SS9YMDI3NlBpWDdiZHY4d3h1azNib3BmVUt3OWVYcmJTRDJudEZ6QnZUcklQbjIzVHZ4RythZWYKaGZnalF6R0o1eVBySUdLUmZmcDdldDJWWlordU9rU3V3VDI5b05qZmlrd041SDROaHRSSWhHU2ZQaEhCVkZlZVl0YnBadkpXay91MQp6V2lyZkxwa254YXo5Y2xjOXVrVGtUYmg4aFRMR2dtTE15N3pORlRHaW84dVpzNXhSMEwwMU4xcUhOUDAwN3d2S1piS2NtdFVjbVc1CjU4RmowTk1VZW1CNWJHYi95TlA2WjJSZHc2YzcyaDBsaHlGSzllUzJ4MmZxazBDUEVTY0w5RER6UnU5VHJBYzh6TjhXL01jSHZ5T04KbmtJekQvOTVSLzRiNjcxUk9vTEdOMjdtR00xM01CSDJ4MWN2cmMrQm55T3d4MUxtZ0IzODhPa1B5UWIwZEhnUzRhOUhOM2JneDNiUApRTFdhYkFEZmQ1TEZaL2IvUEU2Y1FEdVppb2Z6eU9jVnFOdUR5V0RsMENKUFJ3WnAyQXo5bkE5cHBNRmVYeFlwMkVSK2NaRTl4cDhyCjhuUmtrY0l0YnlxSGRNWkhHbndEUGpJUGJmUTU5OFpET3JQWnpCeFNaUDJ6U0FNaThrTHJuNTFwYVMxQTZ1d2g3NVdQVmtEZ1IwSVcKS2JMK1paQUNmeEJZL3dNT0taaUxZSzVmc2tnQmdZOUJlYVRRK3BkRmFyQkMrMzhwUGRlazBhZUV0R2FYUllwc0NnNHBsSDBCV21oVAp0QVNyT284eDZORW5laUdjK2Y3c1Q4dDdnL1BmaGkvN01tK0d6ZnRCc2Z1aStsNW9TZk1kclMxeVlNNmZXVnBiWG9qdXlQRUhxZFBrCkJXaFM1UGxBS3hmYlcwWWs4VEMxMGNQOWs5bzVaaTNhV1ljNmlmTDNVenRuY3NkQ2RDQVFxVmpaOG90R2tZcVZQZ3BBY1kyTEVIT0EKVTAwMCtsVFJTdi9qcVc5cEJNZ0VaaEN3dGlVWUQ1amM0NDU2U1JSOUFtb3Y1MS9PQzFiMm55YmZZcVpqWmkvc3l3V0lwY1NmN3VncApUY2VVd0pEYnIrQUxHelJvenk2R09wVGRUcXRqM2d4ZWJVSUNzaEUzTUdEc0tXUzFvbjhnUTc0THZTU3BRYTFpRmRHZytFTWFudTJBCmRlc2V3cDdHZUhFMFVUZ1FrUnhveTY5enJxcEdkUGdQUFhqS21aZVluOTBvT3orRGxac2gra2QyQlpuMWV6T3ByNStablorTDVqR3AKR1VManRhMUFMTzNydDBYOFNYa1dHb21sQUF4MzVYNUpXVkFHTGV6T0VDdmgxY1ZaSEY4SmRtU0tzMHFmZS8yVWw2UTdNRzc2TkNmZgpUSGtpMTQ4OUtkUGRJRThzb2VweFhxcWVRVkdvZWdLeXFzZWd4cnJGejhxQlQwQjJ5QUlDMmlqVkkwMjdBYnlLaGlHd3pIZzhSUS8xCkQwMDdmQ05OdTU3WEtLdTI1YVFTeGVNa3A5WXo2WjhhZnhkRGt3dWtPNjI2R3FsTFZSdDltaUE1a0lKYk5DditMc2FiMWZ6Vlo2TlgKLzBLTkZnR1d6bGJYaEtRMERPQWQ0TTUxZWJSbHhaRFA1eU9uRFF5dVc1QlpKczhPSDF2c1pUUUdLczUvSldFdytWMTZ1WFUvTXB6RAo0MlFVMUpFR2htc0ZKZ1VLMFoxM3l1TzZsTHN4cVZYdWxLVU83SlZqVS9lc3VKWm0zTlBHUGZDZkR6ZnZrT0tDTFlCbWRCU3JVc3NKCktNWmZVUGdQV0ZBdUVIM0pHMkIrckJhODVJMlhCanNrM3JqUVhFNGx5WkdsU3BPajNDUXoyUHpVOWw5WVlaZEx3bmw4ZGZmbGtzeEsKYWxhWVZ0V3ppaDROVnRtTlNZUE55TDBNckptUGsreTJaTERxV2Q4U3BFbFp2L1VrSmZ1emtsQlBTeENydnVVMlhvVWhuZEpQc252bApTNU1lanhhVERneEozcUJqbHM1ZzFiYUN3TXRYTkN6VWJIN0JDbTZzaW9hRmp2VXJ2ZjV4b0NoT3ZnSFkyMGJEdU9CVloxcUFDVGNVCnZlTmlUbmhwWUQxbEowYlBKUGxXM2MwVUd4N3VTREdoUnRNNXJwMHdEak9LSEM0YzExUHFlS1YxTERoL0FlTXBTem1EY2dhdDVBWk4KNUxwTG80b2U0eG5ZMGxKNVNwdnVKcFc1N3Q2aXoxR216bU12VnJJTWoweHFIRzJnSjY2Zk9qMlRUYXZ6d2RxV1l1cWtqdXkyckJwRwprRFlNeXlLbElDa3Y2c3VVT2lxN2VLS0IwSng4T1JRVkxhQnBJQ0xiOGpxYXFJZzlieUNVait5VzJhSVdaUmk2L3REaGsxT0hrc0lrCkl6YTNoL2c2VG55OGdEYjRWSUU4WDlTQlFDYW9BU3hCbzRJTkk2aytaQVNrb214MkdLeDZCbVcrVWdFSXRTVVV1YStUVlhsYjFxb0EKS3B3QzBPcnZ5OC9Qcm9Ia0JtMUVGOWdLNnZFTXNTWFB4ZnArSy9CUTcvMGVURlU0NGNXdlk0blRESUpjT0VuSFI4WW5CN3kvREdqbApUL3JFU29sWTJrVmMxdTFCWGhJZ2xrNFJGeENMRlhIMGk0QWx0dklMQmZ3SnprVW80cEpldDNwMENYQ3RTVnVFUkNtVzhDUU95WXBICm94U1NGVVZJL3A2RUZyeU1VNndla2dWVDR3a1N2ZnE2d3lSUE1DK2hyalc4d1hwSjRxRThuWVhiOGhYaERjQUhld0pOQ0dXcVhLeVcKOXJVUzdha3ljUitEVlNsSzkvY0VEM2Q3TjhWOUlGblVZMzBpVlNBVHI0SFVDV3ZpWko3ZUZFUWFkZ0pUT25NV205S0FEK1NEaWJSTwoxbUJNUXlwWHhhYTBIdHBSOWhnYWoxVjVQRnJqQzRGME8ySVhjUVRQRjlPMUVWWkZsdkIxOGhKdk9KV25wczduVlc3elkvZVhLNkxSCnU2cDQzNU9ia01HcXdPbUFkNFNiM2pVS0lOMjJoZ3dxYTY2Tk1FT1ZJTDFCdE5YSjJiS0FPcUtOVG0wZjR0dXkxRng0V3gwOHJMTHoKOHpmZ3JNQjNXcGhCVnVwNG5Kd0g0L0hwaTNsZnpybjdKclhiQ1U5Rk5SOUJBbUJ5OFZhcGFDdmxXY2pGV3lFd0hjSW43UzhCb1RGWQpiejZrUUt1bXZPVVpOTU1ST3BMNlJrT2ZpVk53YnBWQUNncnJUWEpRR0oyc0I0NytmWS8xOXlXQUNVNEk5VzJpd3ZOQk83SXVQQTZoCnhabEhhYXAzT1dISW8rUlRnMVZkRERWc054QVk0ZE45eGlkalJNQmNUcGNtVXZMTXovaGVzSXVKTmRweDVielFhTWVWK0FCUGcwYVQKakpEa0FXRXkrMXMxV3B2VGFJejNxc2VDRndOVDEyZ0dqU2RJRU5qMUdvMlZ5bEpuZXdlTkJsWk5TcVBwbG4wQVI3OUd1NGhkVUhCdQoxMmdReXUxbnJ3aU93bW1RSitkZ1QzSDhCcXVVTlNEWWhEcGJKUSthZjNRb2JhTUVQVTFodmlYd2VTNWk0L0M3V3c5Z21mM2wyNzZYClYwTWFMYk04a1BPWGs1UXdVeEY0ZldvV0FPc1lkU2xaZzFWV3pWNlovU0FVNWc3eXBRV2UrRFVHQ2xnMVVWS1RuSVpSaDZQTnRKZUYKZ3VJd0FNN3RLUkFJaW94RExUcDVWNGNqUEhUWEdGNldPRTFBd080UnE2YjJRakEvTjdRdWhMc2grTlo3aTMzUFk5S3hxWG04MmVQcgp2bXVOWnZGaUY3Szc0YnN1KzE0NUJndUIzVzdmZis2bDlrSzl1eGhjTmYwaHJjdGRETUs1eGI3blFXSDN3dXQzTVFSSHdyNlhnc0o2CnJ6Snd0TzZHeW5zaDBqQ2YrNXQzUThGZU9CU2ZFeU1zNE51N3BDTkIvU09aaDBYdmxZTGtLUzROUTlZV0dCNFVsb1JQU28rRzA3ZHUKOTVaWXRTak9ENERkS3QyOGNVbkl0bkt1dFFMRk5KbTd6RXBDTEhJZUVWaExueVk1VnpnOXpRTjZkdndLa1NzTjZYU2lJY2x5Qk1ydApVUlV2OGNhVTkza3Z0cVc4ejYvSnI5U3dNUkc1N2t3MlBVOCtjMDNHM3djakk3U1JVb053VFk3M3k3WUZ3R1RQYnRob2o5YUVlZ0FzCllFbFVhL2VJa0FDS1JmU1pHREk1aUhBbGh6NU5NVmdLbUl5dzl4U1RieW1PTUREeGUwMkQwc2dSRjhKRjc4aVU2SEw3V1NwVTMwaDYKRnZRYW9HcTU0OExvM1RTR1JrOW5VRFI2czRFQnJKc3JTbFhRVVRlMzNGNUR4OS9GTGl2b1JCVkRWOWZRS1ZmUUlaMThoeG82V2FTbwpnazYyV2xCbkRaMXlCUjIvV3ZDV0dqcmxDanFCMVhkRERaMXlCWjJnV3ZDR0dqcmxDanFGYWtGZE5YVEtGWFNvV3ZBT05YVEs3OUcxCjFUZlgwRjBJcnFDQ2p2VXNicXloVTY2Z1EvYVllZzJkSUNGWm9jTHMxVTVLV2R2eU9mRHlsVUNpWkJjTlE1S005QmJVRTdkZDJ1cWwKU0pHUGZIVXliRUZzL1VvRUI3UkdlajhLd3QxZTM5THh6dmdLNG9TTnErbVVjQW5ZVlZncnl1N3hEaTNGWVBQZmVVY3RpQ0k4NDFNQwpwcHlIcFcxK0tOYW5Wam1uZVg2aXlOV2x2R2dudWwvL2tHUXFIMVVpVjBwRGtpcVpnM1BSVlRTblNkY1VSYWtnWEc2UHZnS3FrNjVVCkVDcC9URElaUkgvWVdDNW9qRzRHdXpsZTFmT2FsYWRtMEZqc0pzeUUxQnNZUkp3TTF2eldpREZWN0NaM2JDUDBrZz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJMUlyZDVQMVQ1UU1IbnJZc0tpYURDRnhUTlRla0tLcG1FRlFLYXdNbVRNSENMMDlzSnNSZXJmSlJtODRhazdxY1hpU1ZjbTd2SkNDZgpRcW1yeEJUVnZ0VTFWaDJxKy9hQVdGSm4yYXc5ZGhrNlV3c2NycUk3VVpnRS9MWXRtVFI3eFlsVlNkYnNrcTBDNDFsSzRqb3dWYk5MCmN4M2ZXUzBIWGtjZDMwU3Qvc1VzQ0ZySmw2YkpGOEVvbTlLWE9mRDJ4NlZaYmxBWnFSSk4rZlZUellIWG5FVXdLd2tqbUpMcnA3V08KTDNwUXE0bFJZZ1poZGpvRWRyY0swUU4zOGlGWG1hSUhtRHJIYTZlWU1NQjZJOFZVeTBTMVQ1TFRhRmRSVEJqNEpYTGRubGVZNkZRVwpKZFpMVkhKcHMyVXZZcjZYYmhZcjZrM3B1S1Z5dlp3SWhBeUFsVW00STB1QUdCRURIUDR6VXBUdXNnWm5qL1g0Vkp5OVJWbXpzeWNIClFKeWplQVVJdGF0UndEcXp0MnBvSzVXN2FvV0dtUHIrd3BnMDBtSUJTOXpVZ3d3R3haQTByRXFUY2VJdTJGNnBSczZnVXVhczRjZ1QKVFVqNXloUERoWHVsWUVmR2p4ZXAvSTdDU1FQSmVTY2pjcHo4VzlFWDNwRndsU2hMU2FWQTdrTHJ5RmRFblNSMzh5dnNzWXBXaWVmawpYZFllKzYzb0MrL0lsOW1KTTRpdXB0TlNKZEpnRUxrUzhpeWdNeUlqR0pLZ0hoa01pdEFUL2xBWWtsQ1kxWGN4QlRvRnRRNUpPVHRkCnZTaE9hVWppdXp0OG92Z3ZWWkowajRqTUU0ckkzSmlsQml4aGk0YUlESDNHcDFLZVk0bjdiTGRFWkhqKy90UHRFUmtBd0tHUTNhR2oKRE8yYWlNeEZ0ZUR0RVJsWWhpYUt5TWhWcEtyVjV3VjFSV1FrNC94UEdzcHp0Qlhud0JJOUlIRHFuS3d0ZlErMjZzQ0V4bktWTTVibAo4OGExR011QmROdHQxc0FNeWpXSnUrcDlNaG5ndXNRYjl2c0VkY0RVNGc2Vm5GNHRaV2hYSnJEejl4ZFlRQ1lmWGRKUlBuYVJ1aUJaCkxhaFdWNmM3YWZZeVF4WFYxV25NMTFPc3ErT1ZqaXBVQ3FzSFFhdUtsMVR4cEpkbld5cW02cjFlM2tVS3Y5TzQwVEUxNzNLSlNmZXAKaDROWTdwRlRwMXdQcC8vK3NXdnE0YVN5b0YvLzdsMFBkME9kaFk1Nk9LVU0xZnZWdzhHbzlZMFNxS0VlVHVKR1VOa2lydXZyNFFUWgpVTXh2N1BldWh4UGZPMHBWeE4yN0hrNzFsb0M3MU1NSlRxdzBwRnBlVnc4bjlzWGtqblZnSmR2dGxmVndnN3RiVGlRQUpjeUpsTE10CnRlUkVkcmFhY2lMVlpQKzRDdHhxQnVSUmdzVHQxZWdJamtkdDlUWEMwVkpISWd1RnNzY1FuRHRVY2wxa01pamt3S3RyTkZoY0p4OFEKdTh4MzV2V3lrY2w0dHU5ZEZ4blA5cjNLUW9pRVVEYmEwKzNjSW9aYzhSRXZxbkNyR0FKZ2l0ZktTT2t4V1RIczdiU0tvWUkxRHVtdAp6MStVWkxUNzNBYU00T2dUSDVsNlpBRG5Mb1dRQmIrMlhVd1ZqdnlWd0RLM2FjbWxXVjllQ2F4Nkc1b3dLaTI2cmRIcHVZeGh3ZUl6CjVZdWRWQjFxdGlJVk4xMmJJTUticzl6RndsZFZwSTVOUXcxRnBCb3JVc2VtaVphUWdVcXAzMTBxVWovMzk2bEloWER1VVpFSzY4VnUKcjBpRlVPNVJrUXJoYUxzR1d1UVNTK1gxSVFHUnZ6UlZkNUtSMDB1dnZsQU11emVMb2FnVVRscVAzYnNVRHVYeksyYjAzS01VVG5KZAo3bDRLZDMzY1VrZ3haZDlkaDE5NVF5a2MvdzRpVkF6M2o1VENTVVFWL29GU09PbjRtRWIvcktka0dQSlZBZi8rWktYQ3A2VnNycXFXCkcrR0Y5bGplcCtJV2FVMzBncUJDbWlLS0dnTElFSmo4elhZNmJaaUxTNGIxSGk3d3F0RjdHbzl3bEc3bkJhcGNhc3Zqc0tnWE40dnIKNmo1bHI4TVJidzVNZEZSaWUrRGtGM2FOODBqaG85Y0F0YmhNdlN4TDY4NTRXRERQemtVeVpza015RmJxdFpqeG4reEE4NU90ZEtTSAoyb1lYK3NWREpsc090NTd5T2Q4MG44LzVxN0FKd2R1TzJZNnNhK0dRNllpVHNCWkxxdW9NZWtsMGpkS0hmTjFadEJGLzViT1hzTmd0Ck1YMnA4NFBQUEtTaHBjdWFORzdsS3V5Q3ZhNVNzZHZNTDRzVUkxczVwUW83Njh0UGZTeUhkS1NBdE9TTjhaQ0thN0hpN2lNdkNpY3UKZGd0Mmx6VzJNNkdvQk16a1VDcDJ3MzBpcE1KK2ZJay91UXE3c05tOEQ1OC81WXJkUHBTcXp2NlVLK3kyclpZc1VsdHR2cHpKSVowcgo5K05yZE9XUkZwOC9TckxrdFd3Q2lhRWMwb2F3d2c2dEtoQllldGJvRTgzbmNZM3ZKYVRlbzZJS2dqZURuelZORUlQT1YrbzlldXVzCmhTVU0wV2ZHUzBxUjU3VjRRMVdLSFd0SXVSVmFzTzROTlJmQkdkR3JiWHVmMGg3MURGVngxRVMrajlWZXc1QjQ1MklLZzFKTFRsWEwKODZDODEzdDJrcE5xT3lKeHA0cUc2SkpTSnpsZFViaVBndVlVU1pWcVNIUW5wSTY4UHJVbWNvcDVmZHI1U2FXSm5PejhwUHErcVRVYgowVG8vOVY0RG1vbXUxbWRFZEpmYURmM2p0TXRMYVM3ZmlFZzIzVlZyQXpybFNPODExWFRYeFdIMFZ0TkorUUZNTDg3N1ZkTnB2Qi9tCnhtbzZxWmlnV0Y1dXI2YVRxcVc3dHZKUnZwcE9LaFl2bldsL1N6V2RnQ3kwekVyZVAzWlROWjBVS0pVYlFxNm9wcnR5UjlaWlRTZDEKVHNQdWxYZXJwcE9xcGVQNysvZXBwcE9xcGRPWTI2T2ptazRxMXM1MFlMOWZOWjNVNnFKSTcxMnI2YVNNRzM3dTZIMnE2YVJxNldSdQptNytobXU1eVNFdXp2S1YwYlRXZGxIRnFzTjY3bWs1cS9TU3lvVzZzcGhPRFV1MHBmRlUxblp4dGVkOXFPdTBVdTZXYVRnUktmQ1orCnAycTZxeWltdTVwT3NjYnFidFYwMHJYVjk2Nm1rd0lBc055NW1rN3F0RVNVQTMrSGFqb3A5U0QwWHU5UlRhZHlNbktuYWpyMS9lVWUKMVhSU3hPQ3M4WHRWMDZsVmN0Mm5tazZxbGs2Mkg5L3REcUNYY3dBRi9jVjBYZDBrMzhYcnNrbWx1RGVIeHNLbnZZcXdDNGdmM01yMQpzcm0rWDkzRmtFN3dsT2ZlL2Vya3JRdHRkRHE1N2Jyb3hGRkprQWtKYXpKVkRRdU5MQ0FvVUpDcGVwWWJsR2hJV2xXQmh1NXl3b09wCnE0WUVLUVlHcGF2dHN0S1FwQk1wWkRXTUFwMFUyaTdMcUV5NGl3azlvalQrZEJSNVJBRkxiS2ZTMkZ3NU1zZDJ5MUpxZEhkem16dmUKUFZjYVRmSnIydHpKZHBlcmFxcFYwdGptVHE2U1Mxc2huYVlFQ2VYOFpLN1IzVzFyVmVydHRIU1pVWXhTYVdwenB4cFJoSVM1dWMwZApiY01vTjdxN3VjMGRWZnVtMHVoTzIrSFJybnFIZTY0QzZUYXV2SWphNnl5cWQwdFIybFU1ay92cVdoNHd0VWVuVnY2VVBlV0JEZXBVCmN3L1YrQk9XMFVIbldURUNyNm1RVGt0R3MwRzl3bEEraVVOemZTSEFvcEIycUNPSkRGSkhOdlFuNUdSdEhiWUFack5kWEU4RUwwMlYKbmJQVTNWQnk1ejJsMTc4ckM3c0UyVkNBcVZUeXdUVm5Rd0ZRcXZsam1yT2hBREJ0R2QzS2ljMUk5OTJsOHZIMm94RFlVVkRoT25CNgo5VFhDMGRUYlZRb0tMN1ByN1I0U2lLQmNWTEpMVmdxcjE3SWpZSm9LYStWNlFJZ0xhOTgybDRXMWI1djczUW9JZ2QybGtUSGlNVEJhCkxjcU12M2ZKa3JJbFJVclZmcTlLT2RTdXl5TmRXSWwzbVVHdDZJbkw1VkRQajZ1N1ZLYXdOeC9ydHlRdVFkWE85K3BnQ0I2OHloOFIKYTViOXRxNUcxWEtuYjdEeDJzM21CQVZGS2F0VEI1dzczQkpBd2JtMVd6VUZoUkZDcVJzTzllV3F0alVVTXVnNjRYVzZKY1N3bzZHUQpRVk1FL3VZT2QweDlwVnlQdXl2RVVDSzU0dHErMWZvNjNDbFZQdDRnaGd5ajBSM3U3dElwVDdXZVNGdW52RnZyaWRoT2ViZUxvVUtICk8yRmRrcGI2a0dzNjNDbjFlNFU5N3ZSM3VOTjZxem1zZnJxOXNQWnp6NWs1Y3Q2cjVzSmFBRXpkekRGb01YU28zblRYRmRhS0t4OUQKdDhhUFlIMWhYYkljV3Q4OVZ3ak9GWHJ6NG80SUNPY3U5WngxVEpzdnBncEh2aFpXVk1Sa1VMdG1BclhMMDFQZkxsWEV4RDhWaFFyQwpjeUdHY1lmS1FtaUlhekY5M3pTV01Xa3BZckkvRHNTZUtHOFgwMUxHSkp5a1N1eVVBOFd1aTJ3WlU5eWhxVUpkMFcxbnBUTHUwQ0tWCldvcVk3SThic2ZGOXJWL1oxVlhFSkpkQkJIc25LdXkwK2d6RExsM0RlOE90L0NMRFVPS3l4RzZQNmdGeGp4clh2RS8rVmpIb3YranQKU0tlcjNTTWlwYnc5MXJ2ZjFWUTlkUHAycHhyWG51elZWUHB0bU1sUlY3dEhsVTU1L2l0clhIbnl5YVpoYUtoNlZxOXhCVVBTWFBXcwpWT05LUjREZ1F0UWkwdmdZMHc5V3ZKVWZXNFVWbnMvNW45NEw1dm5UbThGYVNMdmZXby9ia1RzTVBwVmVVWFVmMmYwa1o0UTlaU3BRCkd3OEs3ZkppeC9RblFSSGVjN3JKUnlxb2h6TllqK1pPNzVVZnFoTDJZWXZuUDNveTlYQk8rU0s4dzNrVXg0VTZXVlNHaDdua2F2L0MKWmt1azZmeVNLOEw3bEVVSzVtSWlkd0hadVdJbGM3OHRpOVJlbWZnV2NuM1luQnhTdHBLTEkvQnJpT0FoRlphbUhlMFJHOWRITUNDcQpjblE2MGg5ckthUUdLeVN3dU9lY29BeHZMSzc5NDVPM21ueVZRUm8yVzRQUGhSRVhneFZYeEEwVmtKWXNZWG1rcFlhNUw0VVU5WDJMCmxnV2xsV0trVGFVK2d0V09QTkppc1UwS01yc0FXZ3Q4N21FLzBVV1laOWVqWDdqNk11OEY4cGpzZS96NlNtemtpbWMxUUhUSHQ2Y2kKdDAyQ09mZUNZcU9UUGF5aG96M0N6VE92RUNkbU56cU5hWk9BcUNFbk9nMFNkREZUVDV6VXNEY0QySS9pd2liVkNJbDhTZEpsYXBYcwprQ0FueXc4cXI2VzBTYjJ3Nlhpdnppd29vS3ZTbVVWckpLbWduRm9sdTNRWG5Wa0FnamM5S1doS1ZYZWlteWR2cUVwVHlkQ2txR1RRCnhrK2lReSs5ODJPajFyRHVUbmVYUlpraFhXUnBpZVZGTTlGMVpXa1pyRXFEa284VDZ4c1MwSmJ5ZVZyMGVDNXlZMFhxcXZpWmNna1AKcjR1WFBWT3VjeVVBN0lxR3E2OVZZckNENHIwdWIreDVqZHB1T05SUWphUVlYdFo2eWpNbzNuSVRMVmVUZUhGbDNGWEZidEpIMXJydQp0UjRVcjR3c0MyL1JoRldBdDE1Q0szVlhuR3k5bUpyWGNubFhuSUlESkIwZkV5YU5TQnl4amtsZC9RN2tOUXg1Tng5NVRJbzF6TFduCjNsVEJuWndjb3hNcjlmWjFncEdKNC96cUlUdlVqMDgycWhMY1h5UVFyS0lIL2ZhSVRPOG4rMk5YL25CUVh5SFpSVCtMRzlxeUtWY3kKNmFxeGl1bTY1NEEzSkZIOXk2eWtGRHRXdGNZRlErS2w2dE9uMVR5cDFWa0t1TEpvS09YazMzT2xVQXFvMXRKWVpmMjRrL2RaU2IxUQpSek16aVBvYVMzYVowUUZNcll1T1hWeGRxd0JNdEt2Y1JqSFZXaDd0a3hTZVhONUlNZFYrT3Jvb1ZndCt5Z0M3S0JlV3NnNXBpbDFaCkJhaTFCbER6UFNSeUJXS2FhZ0FWc3RNMVZBRnFyUUc4akNmcnFRTFVXZ1BJditGUWZ4V2cxaHBBRkxXK3VncFF3Q29LSHFZNEQxWmYKRmFEV0drQklzZXVyQURsNkt1c05ZWTJWM2lwQXJUV0FySTk4VlJXZ3pKQXVhZ0Q1NTVYVWVDNW5kWHRUUHUwZDJXNXB5c2VieXovWQpsTzhpcXZDUE5PVlQ2OGgybjZaOFZNMklzb0Z5ZTFNK2cxWENLcng3VTc3TC9zai9SRk0rK2Y3STkyektwNmwvNVMxTitmaFJCVGlvCnNPeWdhQktwbFFiTGQvVzcvVzZvcDN2Y0RhV3hyNSttdTZGdTd1dkhtOW9kN29hUzYrdW5MMC9wMnI1K3lsMzlycm9iU3FLdm4zSlUKU05vVDE5L1hUNXI1Rk8rR3VxS3Zuem9uMzZPdm4zSm1DQnU1dXJHdm4xb2wxNTBDdW9wZC9ReFdYUUZkMmI1K3lsTVR4UzZ1N3VzbgpHTWhGVjc4ck9vQkk5dlZUbnBCVWh1bzFmZjBreXhHVmJqWFhUaGpObGJLU2QwRmYwZGRQK2VZdjlrejh4cjUraWh0ZEh1MWlkK2pyCnB4d1cxblVEbFVKZlAyVlhWeklMK29xK2ZsSmxrcHpvM2RhUDd3NDE3N3I2K2lsRGdYSCtlL1QxVXo1UU1XaUdjMHZodTdnaTlkcSsKZmhLbUpxK3JINzg3QTNaRFh6K1JHR0xDcm42Q083dDBsNmRnYkY4LzFiclh1L1QxVSs3cXgzTHlqWDM5bEJPdWVSV3BOL1gxNCtxMwpwSGhSZE0vVjFYMzlsQW1JTE5nNzlQVlRrTFhqS25DbmZud3VaU2lhKy9HcHRKUFQzSS92cHI1K0xCUko4ZEZielhIUjEwK2g3a0UxCjIzYXV0Nitmc2lVUGJ6eTRSMTgvdVQyOGMzbVNlRjM5bGdaem5qbEpWQk5EdGI1K3l1Zk53aXlDNi92NkNha3Q5Zz09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJRnEvdHg2Y3ZTVU8rSDk4ZHhJZnQ2bmQ3UHo0dFJVeHF0emRjNW1yb2E4VW5ya2k5cmErZklMQjkwZFdQcWhpNnZhOGZXeXFsMUZmMAo1cjUreW1hT0RJL3A3dXVuM05YdjVsdWI2TDUrTjhiNk5QYjEwMUQzZW9lK2ZzcGQvWFQzNDd1cUNsZWtMUy83K2wxZkRNL3I2c2ZECmNsTmZ2OHRRTXIrcm45d3RaM3I3K2ltbmQ0bDJzYXY3K2lrbk9vbGlTbGYzOVpOWUYxNVhQK1Y3NGJUMzlicytiaW1rbVA2YUp4bS8KOG9hK2ZwemlrdXJxZDNYMm9LaXZueUpIOERxQTNOYlhUOWt3cEx6WDIvdjZLUmZFMGp2eXpYMzloSk1VZC9XN3NNYzAzMlFsN09zbgpid1JSTm96S1RWWWErL3Bwc21GdTd1dkhYOG5MQXh5RjZsb1orWlR1NjZlOE9TaFdjZDZ0SUpiYTkvMFMyME5meVVaN2FVdG5mSWp2CmxWcFNOeXFLOWtyd3JYeG9Wem54WGxTMktPQW1oc2U0MDV2VTQ0NWZCMC9GcG1oVURzRU82ZHR5aE1IOEwvTXdTODluZ1NkYU84TGEKTitLNE5JSnQ1Y25vL25pMllQN3VLa0s5Qk91cGpKWjZxdUxESEJ1amYvcXhDd1lPeXljeXRmNktOZG91aC9mUGFjL3RjMWg1OFp3MQo3OCs1c1BGelBBdUFUNk9NTlJSTmxHMzFsMzB6dEYvMVBneldTTWdYbkViclpOZFg5UjJNb1ZvcE9NbzFWKzMwN0swZWZsKzI1cytoCmZjY3gvN2E4WjUzQndxK3AxYXl1NHV0a2R6dFBPemI3WVdSdlBXUTI0V2ZqKzNQYWJnazRTbUhyOTBlbDRqd3Z6Ui9CN2VjOFRzcysKcXUxTXRWdHZIYVBQUGNnWWljVys0MDRHN0JtTXpGVnpHUGs5ZmNKS1lWdnpjQmpGSElkajlMMXlOQS9DazJObzh2SEtWbHEyM0k5Kwo3N3N2VUl1Wm1MSzNYLy9oK0xtRnplWmlacXEyK2xLSENPcExFLzNhTUphZE5uYlFvV1piUU1KK2t1Y1JiblZsTTdVbktXSWhZb0RwCm5teHdYUUlXbyt4Y1VVV2pZMnlmdjVvNy9WYktzam40U1JzUlhKek42NWx4Qml0Sm41amlVT1Bac3dzK3czeTErZ2JWSkJxelpLdGwKeFN6ekdmTDNYN2RDazMwbkVoOHd0ZGM4cjJpT2k3ZnlwZ2JVbWhRZFVtRnIvbXl3RnZya3ZJc2FhT2EvU3MxdStEay9NMlg4cCtSVAp4bitjSmNpWWVmVmFmTThFQm9Cc20xUnAzZWwrWnN0aDR3VEE2ZXdac0ZUN1RBZnVYa1ZnS1dOdmtFblVqQWMwcSt6ZkZuSnl0dnIrClBuUVhPOTB5L0FRbS9McjJ3YUpkRCtYV3AwSzlBL0tjTVAvSkFiTVJoaWRLRS90RFBqdnpDWGVnMkRHZ1NHUUQvb3k0VU5VdlVEaVYKSGZqejBZTTBqTmtPZHJHUEEvZ2k3Mk4rU1BySklsR1BBckJsekYzd1dNK2tvMXlwNEI3NzhxODRYZTFqbUQ4VmNhS0J3c0Y5NGE0OApuc2ovalAwNGVQRG81ajBZVy9LUEJpdnpLTy9sSGhHNWZqdk5QS2l3K0twOGZGNUxaY2tRNXRrSlZNWjJoWmRxcGpIN25adDcyV0RGClN3UGZsSDNrNWNFcDdlSVkvTTVQMjBlaFp3eFdHZjNoNVhDTmdIOFNGT3pKd01yQ2JyaXBWeVk3SEZyb0RTOHZCbXNoN0NrSFRMZHEKK0tpWHB1RThoTlBBWUhMWUFaK1dYOUNmTk5ocC93T24xNnBIdXYzMXQxVUFQRzE1MEZQQ0dZN1BHS1F0SDRNRmMxcWlHTEYrc3hZOQpNU2ZnRHF4ajRmdjdJd2Q5TEVjeHcwWDhpQTc1QUloK2l0a2w0QW56eHJWRHhIZ1FjYi81bUhTM0U0ZHdxaDE4emthK1pnNG9kVG5DCjJYOHpJbGFCRk90OUVPekNqd0tXWkhKRURwMGZWY0o1bnEyWXFiOTd1QVVqQ3VWSHlOUHZQb3BFaFg0Rmh4dTVoU2hNWDBMMHAzV2IKb0QrZFB3YTBiVWtVbmVNaC9ZbFloQ0NJRUFWaTJNOUFpSDBmck5mWUVzTjFEYU4rUFR3M2FkZ2paNWZsdGo3Qkc4MG9NZnRGRHhERgora0ZXS2llOHVZemVqWG00MHlSZ21rSXp0L1l0WE5uWDZYZXRVSzBZM3poRndoN201Tm5nZ0kwWGMrQk9Fbk1CNjdreVo4Yno1VWZUCkNOaUlkaENOTm1CTGZJVG9UNFh4RC90ZWdINnY4NWNWaitZbDMvb2lDMnZUTk50c2Zkb04xdUxFbTNtSG0zVVM1YlBSc24vYWhTbFoKRkpvT3drTmdtMEJ2c21ydFVtOHl1eGpVbkNLOUdmOTYyVHFLNzduNlU4NjVQc0JMQ3NMbFhCSHp0UzcxcHJqdHNCMU5IS2kxS0xxaQoxc21lOFFIMVQwK2p1M0pUcTVyckRvNllmMlh5K1g5TXI3YUFKZlozd2pDSDcwanJNYUF0VVNJNGlyZUNQNE5PVk9hTUZ6OHo4TSs0Ckd3YzdSd29xUXVnak13di9DWDdUZ1NxbDdFTjJIVXk5OGFGSUJGUkNNTkpROXN2RWxNcVl4T3JEQjFVSHpIM2R3em9MYkROaUZyVHEKb25TSUoyK2RzTjk1Nk8vYU9PVHBLdUNOU0tlY0g2MnlNNEZXcldGWWFGS0ZDMUhGK2Rvd3R3OGpPM254QW5VZlFORGJvcTBGVHYwegpDNy9ER2ZPc0ZxRXBVU0s5NkJYZ3lUWDM0TSthbjRFTmRTa2NEZENsbkxLbU5CK1lDMUNwWHMyc1JGbDRGeWNNZEhSRjNLQVdOYlIrCjlQL1NjWDdFYU5qY0ZQSnpaaVg2RHQ1YTBNQm0xazBCdkg1dzg4MGNCQ0taZnVNQnFIeDZmRUlBeTFSNzZLTHkrcG9uYUdDMkJSZEoKMUk3d096UDRMbnFtckV4Ym4zamltZHFVMlpWOEtiSUFHcGNBemhRQU1CY0tSTmxXNWx1OWdPZmQ4RVlFdEFiQUVIOG1ZSGtyMkpnOApaVGY4NUdPLzg3UGZnWFh4dk8yaGZYQ2dtQjJ3ZlorM2k5azQyd3YyekI0eEp0WWp3VmhYd0NpYldKcWZ3R0FJbHNROW8ra05BMDZJCnVtNGladVI2UjhOZTVFYnFKb29lc2pQcHZ0M3I5alBmQndGYko3MHVPV2ZWemR4dFVmN3ltWDdiWUFadUVpRDFlWkZZWDE1NlFWZjQKTWhRTFJGNVd0TlZMbkhITzRFWE53cUhiWUdKR3c3c0R4TVVqd2NjaE1PRmRRY0tTd0pudnp3YW93ZzRSd2VjVkVBRVYxMUZFR1BDSgpRQ3dhaUFqd1FaOVBBbEhyY2lEeEhBbTRmdUpDSW95VHp4d1JBaDlyUE1wclp2VjFuUGo0U0duRC8wdVdCT0srMVQ2Tys3dkdyYjlJCkVlR1E2MzFvNHdOME5UOWk3TE9SSTRIQmFnd2VQMndzRWJvS2ZBQXZMR1dvK0NuRlNySUF1RHlsM2s2Wkc5VjRFVWFKNWNZQTVVWEwKTklhSEs2ZkJSRWhRT09LMmFTd2xWNE5iQzBvcWxhYngrcm03amFkZmgzdFdXNHBBYUtNRUFERS9LazhEQUhCWkVDY3pJTkw1L1ZZQQpZbXRVSDRPaWRqcVlFQUJFc2Q0ZkJ3SXIxM3RUL3B1OVQ1Wi9lN3lGeDhpdnNqRG04dnAzTTQraDY4QnY0N0g1NlJZUUFNRGFlRE9QCmRUWTM4bGh2Szhkam1rRk1EdW9NMGhmdzJNVTBsamVTOG5WMTVuanNPaEM5b1FaeDdUTFJIbWtRRTNuZHAyME1jeDRwS1lycFhZM2UKVWwzaStXTUFjN2tZeGVyRzFlaHR6aUpTTWhUVFBvMkRpbXhJalVGUW01RHFuVTIzTVhiZmJGYmZrWW5qSndmQ2FPOHMzL2dnSnBOcgo5d0IyUjU3TTkycVVVQm5EVWtZK3dSaDQybEtKRXBQVjhWWnRPZG1jTk94RUN2dlFaSDlXSG9PNnRweWNqZncvcDJhVDRFK2JtWWwwCmxpa2ZFaDdMeFhoaGI4ZUhLd2hXM3pPY2RZMmUvYTVtOU5TN0w1UVJDSDdEUmNxNjBPTUw4MXd6bEU4eFAyV2l5QzVsWXpnRG5qYzUKdHZ4OVVoRVErMk12Uk5XOVFxOTc2SUcraXBlSlZuNGU0WjlzQUs1c1p6ODVLTWR1Zmx4QmE3eE0rYnZ3NE4rRHZHNzZ6N3pQUjduYgpURTR2OUxCWmR6eVE3dXh5ak5zYmRMREJSQ2MvZUJrN3NjRzlxcHYvb09abXc0WlZyeUNpNkJsRTJCQk1sY1AzRmJBa0Zsa0czd3ZPCkVZWU9VWlFlWGR4My9PaG9LZS9oUFJCRVIwc1ZId3dPdVFEdFB0MlVyLzExL0FXOFUycmk2TTlBdW0wRWY3NW1PTmhET216eFNpSnEKdTRDL01NOGh0d0NlMDBBdm9SWUZWdnZMQWNyTDY0c2Z4alk4QU1IZUF2NXNJN0F1S2lUaWYvMElzSkZKdHp0bFRwcmhVemRBNEFORwpTNi9HaFc1SERKWVJvSEc0N3kzNHgwbGJmTEd4dHcxV01sa00vdkxDNjFUd3ZkUnQ4SS9mbVRONDlyUW9Cc2E0eVV0QmxJSkg1U21wClFHUnV1a1FRblUvUlJpeGFJalAyZWF0UW1UMGFhYSs2MThVWlZtbnhBMzdPOVJEc2xYU0VxRGNPc2xNZkF5eW5HTDFna3hjVUV2SFEKNGZWSjIwOEhlU2RkREovVUtrN3c2UU9uNDFHVEFaR0tWUWl3VnBOeGdQazBDMUlSZUErOXRLc21ndWhGUitUZ3p5NFRsRnQ5WU15bgpBY2R0RThLZXJxWG8wYXhtQWQ2RGdURXdwT09TOWIyVm5jdnFMNHk4dGtBdUdvZ201Z1BuZDM0WkpsOXk2Nmc1S2hWcG9TYkUvVU5sCmJIT2htbFBYeHlLZG9vdzd5Q3luQVlhWDhJd0RmQnJqektjWkZ3S2Uwa0drMDIvd1lqU2hVNGQwT1ZPSlNNZHJxcE9qdWpWR0JVTnQKdzJNRWV5cTVRMGoydjhLMExIWXhNM0pTbGVPRCtxT0RMTVYweEFmMVJ3ZWw3dXRUaXcvcWp3NUNpdW1ORCtxUERsS2NyQzgreUk4TwpadjhyWllqaUVmd0IvZU52bnRmenc4dmhaL0d6ZWZBWUVnWi90b0xqN2Mxc1N4N204OWI4ZjUwSzIrbjViNzQ1UGNRZi9ObTNmS1VTCkRSWG0wKzFzL29DU21VS2pDS3MydkRTMzB2ek5QOUlXaEJoUnNEeFgrSTZWVm1WejgzRmMrTVo2S1o1WVVGYktyclUzZXBhL1piQ2gKdXFjK3RLdCtHRDBFK1daMGxJOGUrR2VQMnVVcElra2VyQ0t0NURJWDVvZmN1ZWl1MTk1RnB3UW9HQk1idFVwZ2V5aSs1K2JOalArNApTUHJMMlg2MTBDYzdieG4vQ2RzeUFVRjRuaW5JSHVDZGVrc2NrZ05ENW1Rek9wUFBRYVBYYisvQXcvSUNtSXVsRVBVYlBjNU1Cbjc3ClpIUTNUTTl3ZnMvd1Fkcm96UVptMEdvb0cxMTdNekRMeHZzb1gxWFlDRGN0Y3R4V1J3Nkh6SEsvYnBHYU5WRG54N2huc1VpaFl3TmEKWDBMeFF5Y1pqUGo1MFo4d3BkRkJmL3FkSStQQVNWc0Q5ajFzSVZOMjAzL0dIVjdLa0tHQ3p2Q0dHQnJFZHp0K1lpUzVnbkduajN3OQpydU1va3p2SU5GaGxqeks1QnplYkNkUXg4SUNQK3g4d0UxQmFIbTBvL0hObWdzR3F2SzNmeDB5Z1F0dWFJVjVwSmdCRGh6VVUvamt6CkFSbzZqS0h3ejVrSllDNnNvZkRQbVFrOGVabitjMmFDd2NvWkNtSXpRVGtqaE01Q3JNWGxOZ2RhL2J1K3lETjBwWmEvd0pYcURJcEEKS2I1M2pjN252b1BXbStmNEsxU3BaYUJMMHkyajgyZWRNbm8zalUrb1MyTndYN0NJM1N0cXdSNTdsS29EUXBOMUlJSGpEalhmZHZSTAo0NzJYU2Z3SU9yakVEelpYdzA1NWYwQmJ1bWx0Q1U5WWVOcVMzc3J0aEQxai9FTExEclZsM3VkQnQwOFRYK2RreGYvVFBma293K1BICkUzZWp0QzJneDRwUFVrWG53Tzk2cm9wV0h6NW9BeXlSQTZkYUtUMzJSWXVBU0sraWJCU2dVdUhJSFBBNFk1VmJtemFrMFBuQ09CdUcKNyt5VjRrN0lHM1ZrakNBRE5FcWQ1dU9sdGlQS1dqRzBTVlJhQkNIRm5uMjBSV0xKK0F0UHlTMEc0THhnbFBMa2FleFNtMEFMQWY1eAo4NnA2MkRSVzdpUVNLSE51OTBXTWVGR2d3WjcvaTFxcVVtbHB4VUZJZERqSXBlVlI1NHRlL3ZuaU5Gb1ZuUzhhalNjSEd6ODd2bDZjCkx3WmRKVit3bkdXTzJ4NjNUT3Ntd1VHb3Q4NGRCUkdPV0M4Z09BZ05tNDNXbktYQWdKamFMazVTYzM0ZUFKenNsbkIwNEVzbk5OQmkKRHpnZG1leituMVM3aUl3RHlHZ3B4T2ZNZDUwOTgxM3Y0UDk1MmJpNVJBdkVjZ0p6bnc2dENNT09Xa04rU0lYQkNkSG5udlQxK3E3TQp1MnZNSEVFaU81bytmVE5ZeFllUTZGYjA2NDhnblZLbmJ6QWtwUG44RGI4NVZMZUs3aGdpWkFJOElxQlRZWm9JUVQ5SEJEaWFGZThJCkV0MmtKMGNDSm9TYWpxODJEQkZjb2lOSTc0MUgwWThuN25oZWU5aVZ4d2ZwK090SncxRTBuV0lvZFJoTkZ4WlRWRVRueDFLc3BIQ2EKVFpkRUFnQmc5VFZ5NHdVSTFOUk4yeGlvMUp4TEVLZ2gxUzNUUUFuOGpFanhqclIxVEtNZDkrdEtETGlVU2svczVMcUZwNkZMN1JZQgpvQ21tbFJMUUEvZXFUZVB5YUo5ZkpJTjdkbmxNY2hvYVNRbFRLSEVFNEdncWxYTnV0cFdId1FvVEh2YThONEhiNzZUZkpIOXh0MFRUCkQ1clB4MFA3alR3R0RCVEhiVHhXQy9vNEFMSThwZ2hpa01GdTVUSDcwbkViajJFYnB3eVBhUVpSYzN0VUdZUVBBQT09DQoJXV0+DQoJPCFbQ0RBVEFbDQoJVFVMSVk0T0k3NWJWQVA3OG8xOEtBT0F4clNCS05aTzZ1RW9Eb05OWW9jR25XZmRKajJIZ2t5WWxIQU82bEZ4MU5ZQ0JxU3J4U21PQQpTY3k3K0cyckFhMWFaVktpL1VWcEdtVXZxVTgyTHNZUXJ1SFFHcjlCTnNycEpxRXloa1BLai9OMjVITHc1R3NuZVNBbUErdHRlOEJrCjRYWXpPN0xpS0JUR3NNUGxtVW8wQmxyMnhhT1lXaUxlbXpoaTZuMzAzWlprQmhQY0pVVmNkZ3lzdGtRSm55SGNnWXhFcnY4WVFoLzEKR3FmQlF0bzk3QmJPNDFJdC8vVVVNOU1oZzFDR2lTUlJJZjZuUDJHZU9sVTZZYkJLRlUvY3UzUUNZcmtzbnRCZE9zR0dRNldQSmRHNgphRHFZRkI5TDhoN3M4Z3YyZ1NpbUR3T296ekNxd1B1MjdXQ1BEWjQ5L0FlTElGdVRBTDFsNENWQnZVS2x6RVAxQURrWm5RTnNrYVRDClB4c3V3ZEVwa0IxSTJ3YnRlZ01tanRQZWhxZU96c2R6a0M4aEt6WDhkQkZGdWdMSjFxREJUaHR0QkRiQWl6S1dod2Y2Z05ucERWTFcKZU12TFA3aExaeEs2ay9BdkRtRllMNTV3bHNrazVTWGREV0tqOXNpZE5ZUk9yNVo1NmFzZlhSaXMyYmV6NWFmWW43M0NrNk1XenZFdgo4WFVlWk9pWVJHOFFZRU9SUVg3QlJEckNzc3E3bDY2YWFPU2hYbm4zTTJ6L2pxR0VoaS9vY3I3alRIVHBIWjBTd05PRTl3RDdLVWlCCktDYit3dURQUGcxeE9FVUwzMmVQOGZzWSt3bm5yejY4VTV5dFNlZ0grTFVVaFpXRmlUTCtocGk1OU1PeVZTcHV1Um9WQTMzQkNWZXYKd3E5UytmSnhTQU0yNXdzazZoZjRwL2NPb3c5Zk9QdUo0TDlYWHdUaGQwRnVORUQybWZFMHlGR25seSs0bzA2U0xOWTdVU2E0K1JmQwo1cE40R0hLb2o0MVQ5S2txeVA4ZjYvc2ZHK3ZiL2xmS2tBQ1RxZUQ0c0xpWjhjOGNEVllyK09adGZqcnY0QXVoWVc2KytOblV4ditaCkh3ejRBL1VmQnY2RC8wWmlEemdSZlNCQ0lmQkhDSDVibXhnYzZOMEgzUGxRQTd2TDBKODluQW8vMDlQUGRqTSsvT2NoRHIvcTFtdnQKU3VFaC9rQzlPd1R2Smg0Y1lEVFlFTHdOSGpuaFFlY1FqSEJvd0I2eTRIL2RmeHZPNEQvczRjV0FQV0QwQU9CLzNiRUJvMGNFM3ZvUAorT01KZlBnRlgvMzdBY2NlNmc4Zlg5akRESXk4MnpRRVlnOWVISC80b3o1Z0QydjBJZW9MRVRFd2t3RDRnTWRDNEl1SFFBVCtPelVFCjRQK3REYmd2R01FSUhQNkJVKzlqR0FFL0FoaFRBNDZBcnRIL0U3NVFNQWJlb2wveDRvR0hBUG9Yd0lxZ0R3QW5BRUE5aVZHL0lCN28KZ1UwTjM0WTJuSjh2QWdrS1VhQVpnYUdqMmMwTTRRZUg4Nkg3emxBQ3ZBZkhoZm5Da1ZnNEdrQWZNSUlnd0ljWWhvZURERmxFTk9LSQpnZEhFaU5HMGlJaHBFVUcwaUZDMGlQQnBFWUVFaUhDMGlOR2t3R2hTNEdKU0VJZ1VCRU1LZ2lNRlF3Q1dGQmhOaWhnOTNiWTBIOUg4CkFjakFYLzlMYWxtSDdHU3BqM0M2MUNlRkNZTVhxQ2xiaDRxVEJvL3BhVk9mRkNZT1FESlRCeDhWSm04ZHlvbE85bkFZVXgrQnZEeGsKejZmdFEzTjhQTTBQUC85Nzduend2NTBPUDVzRkpUMUFvbWJieVh5WXJjU0dMNVBqL1BDditXeFluZjluU0wxMDVBa1pEdDdkYkRjUApnWENBNWk4dHNzYnlFZUE0aW84SW5HWWtQQVlKRytYb2lzY1FZZkVZeFVwNGpNOUw0QytjL2czOFFPQVVMeEVFeFV0RVFFUlNJZ2hKCkN2NmxlQWw4WUhnSlBvbFJ2NEJvNmNIOXR3c1d3V2daZ3RFeWVGUk1FRXJONExTZXdRV0tCa2VhQnYwR0VZVFdNd1N0WndpeG5pR1EKbmlFWVBVTndlb1lJMEVUZ0VRVC9KOFFMVFpuK2lMSHlwVGh0SkdGbzRqd1JrNW82RWl3MGVlcVR3dlFwRVVNRVlFUk1qZ1QvdzRRcwpFS0I1S2tEUVBCWEFJSEVESEhFREdDSnVBS040S29EeGVTb0F3YUxmd0hkeEJBZHhWU0JBY1ZVZ0tDSnJJQVRKQ3Y2bHVBcDhZTGdxClFKRVIvb0loYVNEdzN5OW1BVWJ2QkJpOVE4UkVKQ0VvdlVQUWVvY1E2QjBDNlIzNEc0WWt0T1lKMEpvbklOWThBYVI1QW96bUNYQ2EKSnhDa3ljQWpDZkZQQ0JxYU5QMFJad1ZOY2VKSTBJaVlVTkNrSjQ4RUxFQXdvcVpFQUVyVUVBa1lVWk1qd3Y5dFVhdmxLRnNXV0xiSQo0dlFDLzlyNk9sN01XNGZ4enhwWXRvdmorRi96aC9GbXN6Mk5UL01kZVBLd09NeVBwKzFoL25CY2J2OE52d0UvWVY0SE52SUxhZmcvCndrbmVyZz09DQoJXV0+DQo8L2k6cGdmPg0KPC9zdmc+DQo=);
+ -webkit-background-size: cover;
+ -moz-background-size: cover;
+ background-size: cover;
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ overflow: hidden;
+ vertical-align: middle;
+ width: 1.3rem;
+ height: 1.3rem;
+}
+#download-btn {
+ display: none;
+}
+/* Content */
+#content {
+ width: 100%;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 20px;
+}
+/* Code */
+#content section.code {
+ display: none;
+ background: #FFF;
+ border: 1px solid #E0E0E0;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 15px;
+ font-size: 12px;
+ -moz-border-radius: 1px;
+ -webkit-border-radius: 1px;
+ border-radius: 1px;
+ font-weight: 400;
+}
+article.component {
+ padding: 0 0 10px;
+}
+#content section.code h3 {
+ margin: 0;
+ font-size: 12px;
+ color: #000;
+ font-weight: 400;
+}
+#content header h2 {
+ font-weight: 300;
+ margin: 10px 0 25px;
+ font-size: 20px;
+ position: relative;
+ display: inline-block;
+ padding-right: 10px;
+}
+body.light #content header h2 {
+ background: #F4F4F4;
+}
+body.dark #content header h2 {
+ background: #4A4D4E;
+}
+#content header{
+ position: relative;
+}
+#content header:before {
+ content: '';
+ width: 100%;
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 23px;
+}
+body.light #content header:before {
+ border-bottom: 1px solid #E0E0E0;
+}
+body.dark #content header:before {
+ border-bottom: 1px solid #58595A;
+}
+#content pre {
+ padding: 0;
+ margin: 2px 0 10px;
+}
+.showcode {
+ margin: 10px 0;
+}
+.showcode a, section.examples a {
+ color: #288edf;
+ text-decoration: none;
+}
+.showcode a:hover, section.examples a:hover {
+ text-decoration: underline;
+}
+section.examples ul {
+ margin: 0 0 20px;
+ padding: 0 0 0 20px;
+}
+section.examples h4 {
+ margin-bottom: 5px;
+}
+section.examples li {
+ color: #58595A;
+}
+/* Side Nav */
+#sideNav {
+ background: #4A4D4E;
+ position: absolute;
+ width: 100%;
+ z-index: 1;
+ height: 100%;
+ left: 0;
+}
+#sideNav ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+#sideNav li a {
+ color: #F0F1F1;
+ display: block;
+ height: 46px;
+ font-size: 16px;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 12px 0 0 20px;
+ text-decoration: none;
+}
+#sideNav nav.site, #sideNav .combo {
+ border-bottom: 1px solid #58595A;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 10px;
+ display: block;
+}
+#pageNav li {
+ border-bottom: 1px solid #58595A;
+}
+
+select.docNav {
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ background: #595B5B;
+ background-image: none;
+ box-shadow: 0 0 0 1px #303233;
+ border: none;
+ border-top: 2px solid #666767;
+ color: #FFF;
+ text-shadow: 0 -1px 0 #000;
+ overflow: hidden;
+ font-size: 14px;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 20px;
+ -webkit-appearance: none;
+ -moz-appearance: button;
+}
+@media screen and (min-width: 650px) {
+ #site.open {
+ transform: translate3d(0, 0, 0);
+ -webkit-transform: translate3d(0, 0, 0);
+ }
+ #main-header nav {
+ display: inline-block;
+ position: absolute;
+ right: 0;
+ top: 40px;
+ }
+ #main-header ul {
+ list-style: none;
+ }
+ #main-header nav li {
+ display: inline-block;
+ margin: 0 18px;
+ }
+ #main-header nav li#download-btn {
+ display: none;
+ }
+ #main-header nav li a {
+ text-decoration: none;
+ font-size: 20px;
+ color: #7F7F7F;
+ }
+ #main-header nav li.selected a {
+ color: #373435;
+ }
+ #slide-menu-button{
+ display: none;
+ }
+ #main-header hgroup {
+ text-align: left;
+ position: absolute;
+ display: inline-block;
+ top: 24px;
+ }
+ #main-header hgroup h1 {
+ font-size: 60px;
+ }
+ #main-header hgroup p {
+ font-size: 15px;
+ }
+ #main-header {
+ color: #373435;
+ background: #fff;
+ height: 148px;
+ }
+ #content {
+ padding-left: 240px;
+ }
+ /* Side Nav */
+ #sideNav {
+ background: transparent;
+ width: 220px;
+ z-index: 20;
+ left: 10px;
+ top: 150px;
+ height: auto;
+ }
+ #sideNav nav.site {
+ display: none;
+ }
+ #sideNav .combo {
+ border-bottom: none;
+ padding: 36px 0;
+ }
+ #sideNav li a {
+ padding: 12px 0 0 10px;
+ }
+ body.light #sideNav li a {
+ color: #797B7B;
+ }
+ body.light #pageNav li {
+ border-bottom: 1px solid #E0E0E0;
+ }
+ select.docNav {
+ background: #595B5B;
+ box-shadow: 0 0 0 1px #303233;
+ border: none;
+ border-top: 2px solid #666767;
+ color: #FFF;
+ text-shadow: 0 -1px 0 #000;
+ padding: 3px 20px 4px 8px;
+ -webkit-appearance: none;
+ }
+ body.light select.docNav {
+ box-shadow: 0 0 0 1px #949696;
+ background: #DDE1E1;
+ border-top: 1px solid #FFF;
+ color: #454545;
+ text-shadow: 0 -1px 0 #FFF;
+ width: 192px;
+ }
+}
+@media screen and (min-width: 880px) {
+ #content {
+ padding-left: 300px;
+ }
+ #sideNav li a {
+ display: block;
+ height: 60px;
+ padding: 22px 0 0 10px;
+ text-decoration: none;
+ }
+ #content header h2 {
+ font-size: 28px;
+ }
+ #content header:before {
+ top: 30px;
+ }
+ section.code div {
+ display: inline-block;
+ width: 48%;
+ vertical-align: top;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+ section.code div:first-child {
+ padding-right: 5px;
+ }
+ section.code div:last-child {
+ padding-left: 5px;
+ }
+ .max-width {
+ max-width: 1180px;
+ position: relative;
+ margin: 0 auto;
+ }
+ header#main-header .max-width {
+ top: -10px;
+ }
+ #main-header nav li a {
+ font-size: 22px;
+ }
+ #main-header nav {
+ display: inline-block;
+ }
+
+ #main-header nav li {
+ margin: 0 25px;
+ }
+ #main-header nav li:last-child {
+ margin-right: 0;
+ }
+}
+@media screen and (min-width: 940px) {
+ #main-header nav li#download-btn {
+ display: inline-block;
+ }
+ #main-header nav li a#download-btn{
+ position:relative;
+ top: -15px;
+ display:inline-block;
+ box-sizing:border-box;
+ -moz-box-sizing:border-box;
+ background-clip:padding-box;
+ font:inherit;
+ background:transparent;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ overflow:hidden;
+ font-size:16px;
+ line-height:3rem;
+ letter-spacing:1px;
+ color:#454545;
+ text-shadow:0 1px #fff;
+ vertical-align:top;
+ background-color:#e5e9e8;
+ box-shadow:inset 0 1px #fff;
+ border:1px solid #a5a8a8;
+ border-radius:6px;
+ margin:0;
+ padding:0 1.25rem;
+ }
+ #main-header nav li a#download-btn, #main-header nav li a#download-btn:hover {
+ border:1px solid #143250;
+ background-color:#288edf;
+ box-shadow:inset 0 1px rgba(255,255,255,0.36);
+ color:#fff;
+ font-weight:500;
+ text-shadow:0 -1px rgba(0,0,0,0.36);
+ }
+ #main-header nav li a#download-btn:hover {
+ background-color:#2f9cf3;
+ }
+ #main-header nav li a#download-btn:active, #main-header nav li a#download-btn.is-active {
+ background-color:#0380e8;
+ box-shadow:inset 0 1px rgba(0,0,0,0.12);
+ }
+ #main-header nav li a#download-btn:disabled, #main-header nav li a#download-btn.is-disabled {
+ opacity:.3;
+ cursor:default;
+ pointer-events:none;
+ }
+}
+
+
+
diff --git a/docs/css/prism.css b/docs/css/prism.css
new file mode 100644
index 0000000..b508b61
--- /dev/null
+++ b/docs/css/prism.css
@@ -0,0 +1,168 @@
+/**
+ * prism.js Twilight theme
+ * Based (more or less) on the Twilight theme originally of Textmate fame.
+ * @author Remy Bach
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+ color: white;
+ direction: ltr;
+ font-family: source-code-pro, Consolas, Monaco, 'Andale Mono', monospace;
+ text-align: left;
+ text-shadow: 0 -.1em .2em black;
+ white-space: pre;
+ word-spacing: normal;
+
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+}
+
+pre[class*="language-"],
+:not(pre) > code[class*="language-"] {
+ background:#181818;
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+ margin: .5em 0;
+ overflow: auto;
+}
+pre[class*="language-"]::selection { /* Safari */
+ background:hsl(200, 4%, 16%); /* #282A2B */
+}
+pre[class*="language-"]::selection { /* Firefox */
+ background:hsl(200, 4%, 16%); /* #282A2B */
+}
+
+/* Inline code */
+:not(pre) > code[class*="language-"] {
+ border-radius: .3em;
+ border: .13em solid hsl(0,0%,33%); /* #545454 */
+ box-shadow: 1px 1px .3em -.1em black inset;
+ padding: .15em .2em .05em;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+ color: hsl(0, 0%, 47%); /* #777777 */
+}
+
+.token.punctuation {
+ opacity: .7;
+}
+
+.namespace {
+ opacity: .7;
+}
+
+.token.tag,
+.token.boolean,
+.token.number {
+ color: hsl(14, 58%, 55%); /* #CF6A4C */
+}
+
+.token.keyword,
+.token.property,
+.token.selector {
+ color:hsl(53, 89%, 79%); /* #F9EE98 */
+}
+.token.attr-name,
+.token.attr-value,
+.token.string,
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+ color:hsl(76, 21%, 52%); /* #8F9D6A */
+}
+
+.token.atrule {
+ color:hsl(218, 22%, 55%); /* #7587A6 */
+}
+
+.token.regex,
+.token.important {
+ color: hsl(42, 75%, 65%); /* #E9C062 */
+}
+
+.token.important {
+ font-weight: bold;
+}
+
+.token.entity {
+ cursor: help;
+}
+pre[data-line] {
+ padding: 1em 0 1em 3em;
+ position: relative;
+}
+
+/* Markup */
+.language-markup .token.tag,
+.language-markup .token.attr-name,
+.language-markup .token.punctuation {
+ color: hsl(33, 33%, 52%); /* #AC885B */
+}
+
+/* Text Selection colour */
+::selection {
+ background: hsla(0,0%,93%,0.15); /* #EDEDED */
+}
+::-moz-selection {
+ background: hsla(0,0%,93%,0.15); /* #EDEDED */
+}
+
+/* Make the tokens sit above the line highlight so the colours don't look faded. */
+.token {
+ position:relative;
+ z-index:1;
+}
+.line-highlight {
+ background: -moz-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */
+ background: -o-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */
+ background: -webkit-linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */
+ background: hsla(0, 0%, 33%, 0.25); /* #545454 */
+ background: linear-gradient(left, hsla(0, 0%, 33%,.1) 70%, hsla(0, 0%, 33%,0)); /* #545454 */
+ border-bottom:1px dashed hsl(0, 0%, 33%); /* #545454 */
+ border-top:1px dashed hsl(0, 0%, 33%); /* #545454 */
+ left: 0;
+ line-height: inherit;
+ margin-top: 0.75em; /* Same as .prism’s padding-top */
+ padding: inherit 0;
+ pointer-events: none;
+ position: absolute;
+ right: 0;
+ white-space: pre;
+ z-index:0;
+}
+.line-highlight:before,
+.line-highlight[data-end]:after {
+ background-color: hsl(215, 15%, 59%); /* #8794A6 */
+ border-radius: 999px;
+ box-shadow: 0 1px white;
+ color: hsl(24, 20%, 95%); /* #F5F2F0 */
+ content: attr(data-start);
+ font: bold 65%/1.5 sans-serif;
+ left: .6em;
+ min-width: 1em;
+ padding: 0 .5em;
+ position: absolute;
+ text-align: center;
+ text-shadow: none;
+ top: .4em;
+ vertical-align: .3em;
+}
+.line-highlight[data-end]:after {
+ bottom: .4em;
+ content: attr(data-end);
+ top: auto;
+}
\ No newline at end of file
diff --git a/docs/css/topcoat-desktop-light.css b/docs/css/topcoat-desktop-light.css
new file mode 100644
index 0000000..1e221af
--- /dev/null
+++ b/docs/css/topcoat-desktop-light.css
@@ -0,0 +1,2883 @@
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.button-bar {
+ display: table;
+ table-layout: fixed;
+ white-space: no-wrap;
+ margin: 0;
+ padding: 0;
+}
+
+.button-bar__item {
+ display: table-cell;
+ width: auto;
+ border-radius: 0;
+}
+
+.button_bar__item > input {
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ border: 0;
+ opacity: 0.001;
+ z-index: 1;
+ vertical-align: top;
+ outline: none;
+}
+
+.button-bar__button {
+ border-radius: inherit;
+}
+
+.button-bar__item:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.button,
+.topcoat-button,
+.topcoat-button--quiet,
+.topcoat-button--large,
+.topcoat-button--large--quiet,
+.topcoat-button--cta,
+.topcoat-button--large--cta,
+.topcoat-button-bar__button,
+.topcoat-button-bar__button--large {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ text-decoration: none;
+}
+
+.button--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.button--disabled,
+.topcoat-button:disabled,
+.topcoat-button--quiet:disabled,
+.topcoat-button--large:disabled,
+.topcoat-button--large--quiet:disabled,
+.topcoat-button--cta:disabled,
+.topcoat-button--large--cta:disabled,
+.topcoat-button-bar__button:disabled,
+.topcoat-button-bar__button--large:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+.topcoat-button,
+.topcoat-button--quiet,
+.topcoat-button--large,
+.topcoat-button--large--quiet,
+.topcoat-button--cta,
+.topcoat-button--large--cta,
+.topcoat-button-bar__button,
+.topcoat-button-bar__button--large {
+ padding: 0 1.25rem;
+ font-size: 16px;
+ line-height: 3rem;
+ letter-spacing: 1px;
+ color: #454545;
+ text-shadow: 0 1px #fff;
+ vertical-align: top;
+ background-color: #e5e9e8;
+ box-shadow: inset 0 1px #fff;
+ border: 1px solid #a5a8a8;
+ border-radius: 6px;
+}
+
+.topcoat-button:hover,
+.topcoat-button--quiet:hover,
+.topcoat-button--large:hover,
+.topcoat-button--large--quiet:hover,
+.topcoat-button-bar__button:hover,
+.topcoat-button-bar__button--large:hover {
+ background-color: #edf1f1;
+}
+
+.topcoat-button:active,
+.topcoat-button--large:active,
+.topcoat-button-bar__button:active,
+.topcoat-button-bar__button--large:active,
+:checked + .topcoat-button-bar__button {
+ background-color: #d3d7d7;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+.topcoat-button:focus,
+.topcoat-button--quiet:focus,
+.topcoat-button--large:focus,
+.topcoat-button--large--quiet:focus,
+.topcoat-button--cta:focus,
+.topcoat-button--large--cta:focus,
+.topcoat-button-bar__button:focus,
+.topcoat-button-bar__button--large:focus {
+ border: 1px solid #0940fd;
+ box-shadow: 0 0 0 2px #6fb5f1;
+ outline: 0;
+}
+
+.topcoat-button--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.topcoat-button--quiet:hover,
+.topcoat-button--large--quiet:hover {
+ text-shadow: 0 1px #fff;
+ border: 1px solid #a5a8a8;
+ box-shadow: inset 0 1px #fff;
+}
+
+.topcoat-button--quiet:active,
+.topcoat-button--large--quiet:active {
+ color: #454545;
+ text-shadow: 0 1px #fff;
+ background-color: #d3d7d7;
+ border: 1px solid #a5a8a8;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+.topcoat-button--large,
+.topcoat-button--large--quiet,
+.topcoat-button-bar__button--large {
+ font-size: 1.3rem;
+ font-weight: 400;
+ line-height: 4.375rem;
+ padding: 0 1.25rem;
+}
+
+.topcoat-button--large--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.topcoat-button--cta,
+.topcoat-button--large--cta {
+ border: 1px solid #143250;
+ background-color: #288edf;
+ box-shadow: inset 0 1px rgba(255,255,255,0.36);
+ color: #fff;
+ font-weight: 500;
+ text-shadow: 0 -1px rgba(0,0,0,0.36);
+}
+
+.topcoat-button--cta:hover,
+.topcoat-button--large--cta:hover {
+ background-color: #509bef;
+}
+
+.topcoat-button--cta:active,
+.topcoat-button--large--cta:active {
+ background-color: #0380e8;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+.topcoat-button--large--cta {
+ font-size: 1.3rem;
+ font-weight: 400;
+ line-height: 4.375rem;
+ padding: 0 1.25rem;
+}
+
+.button-bar,
+.topcoat-button-bar {
+ display: table;
+ table-layout: fixed;
+ white-space: no-wrap;
+ margin: 0;
+ padding: 0;
+}
+
+.button-bar__item,
+.topcoat-button-bar__item {
+ display: table-cell;
+ width: auto;
+ border-radius: 0;
+}
+
+.button_bar__item > input,
+.topcoat-button-bar__item > input {
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ border: 0;
+ opacity: 0.001;
+ z-index: 1;
+ vertical-align: top;
+ outline: none;
+}
+
+.button-bar__button {
+ border-radius: inherit;
+}
+
+.button-bar__item:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/* topdoc
+ name: Button Bar
+ description: Component of grouped buttons
+ modifiers:
+ :disabled: Disabled state
+ markup:
+
+ examples:
+ mobile button bar: http://codepen.io/Topcoat/pen/kdKyg
+ tags:
+ - desktop
+ - light
+ - dark
+ - mobile
+ - button
+ - group
+ - bar
+*/
+
+.topcoat-button-bar > .topcoat-button-bar__item:first-child {
+ border-top-left-radius: 6px;
+ border-bottom-left-radius: 6px;
+}
+
+.topcoat-button-bar > .topcoat-button-bar__item:last-child {
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+}
+
+.topcoat-button-bar__item:first-child > .topcoat-button-bar__button,
+.topcoat-button-bar__item:first-child > .topcoat-button-bar__button--large {
+ border-right: none;
+}
+
+.topcoat-button-bar__item:last-child > .topcoat-button-bar__button,
+.topcoat-button-bar__item:last-child > .topcoat-button-bar__button--large {
+ border-left: none;
+}
+
+.topcoat-button-bar__button {
+ border-radius: inherit;
+}
+
+.topcoat-button-bar__button:focus,
+.topcoat-button-bar__button--large:focus {
+ z-index: 1;
+}
+
+/* topdoc
+ name: Large Button Bar
+ description: A button bar, only larger
+ modifiers:
+ :disabled: Disabled state
+ markup:
+
+ tags:
+ - desktop
+ - light
+ - dark
+ - mobile
+ - button
+ - group
+ - bar
+ - large
+*/
+
+.topcoat-button-bar__button--large {
+ border-radius: inherit;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.button {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ text-decoration: none;
+}
+
+.button--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.button--disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.button,
+.topcoat-button,
+.topcoat-button--quiet,
+.topcoat-button--large,
+.topcoat-button--large--quiet,
+.topcoat-button--cta,
+.topcoat-button--large--cta {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ text-decoration: none;
+}
+
+.button--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.button--disabled,
+.topcoat-button:disabled,
+.topcoat-button--quiet:disabled,
+.topcoat-button--large:disabled,
+.topcoat-button--large--quiet:disabled,
+.topcoat-button--cta:disabled,
+.topcoat-button--large--cta:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/* topdoc
+ name: Button
+ description: A simple button
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+ Button
+ Button
+ examples:
+ mobile button: http://codepen.io/Topcoat/pen/DpKtf
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+*/
+
+.topcoat-button,
+.topcoat-button--quiet,
+.topcoat-button--large,
+.topcoat-button--large--quiet,
+.topcoat-button--cta,
+.topcoat-button--large--cta {
+ padding: 0 1.25rem;
+ font-size: 16px;
+ line-height: 3rem;
+ letter-spacing: 1px;
+ color: #454545;
+ text-shadow: 0 1px #fff;
+ vertical-align: top;
+ background-color: #e5e9e8;
+ box-shadow: inset 0 1px #fff;
+ border: 1px solid #a5a8a8;
+ border-radius: 6px;
+}
+
+.topcoat-button:hover,
+.topcoat-button--quiet:hover,
+.topcoat-button--large:hover,
+.topcoat-button--large--quiet:hover {
+ background-color: #edf1f1;
+}
+
+.topcoat-button:active,
+.topcoat-button--large:active {
+ background-color: #d3d7d7;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+.topcoat-button:focus,
+.topcoat-button--quiet:focus,
+.topcoat-button--large:focus,
+.topcoat-button--large--quiet:focus,
+.topcoat-button--cta:focus,
+.topcoat-button--large--cta:focus {
+ border: 1px solid #0940fd;
+ box-shadow: 0 0 0 2px #6fb5f1;
+ outline: 0;
+}
+
+/* topdoc
+ name: Quiet Button
+ description: A simple, yet quiet button
+ modifiers:
+ :active: Quiet button active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+ Button
+ Button
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - quiet
+*/
+
+.topcoat-button--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.topcoat-button--quiet:hover,
+.topcoat-button--large--quiet:hover {
+ text-shadow: 0 1px #fff;
+ border: 1px solid #a5a8a8;
+ box-shadow: inset 0 1px #fff;
+}
+
+.topcoat-button--quiet:active,
+.topcoat-button--large--quiet:active {
+ color: #454545;
+ text-shadow: 0 1px #fff;
+ background-color: #d3d7d7;
+ border: 1px solid #a5a8a8;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+/* topdoc
+ name: Large Button
+ description: A big ol button
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+ Button
+ Button
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - large
+*/
+
+.topcoat-button--large,
+.topcoat-button--large--quiet {
+ font-size: 1.3rem;
+ font-weight: 400;
+ line-height: 4.375rem;
+ padding: 0 1.25rem;
+}
+
+/* topdoc
+ name: Large Quiet Button
+ description: A large, yet quiet button
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+ Button
+ Button
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - large
+ - quiet
+*/
+
+.topcoat-button--large--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+/* topdoc
+ name: Call To Action Button
+ description: A CALL TO ARMS, er, ACTION!
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+ Button
+ Button
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - call to action
+*/
+
+.topcoat-button--cta,
+.topcoat-button--large--cta {
+ border: 1px solid #143250;
+ background-color: #288edf;
+ box-shadow: inset 0 1px rgba(255,255,255,0.36);
+ color: #fff;
+ font-weight: 500;
+ text-shadow: 0 -1px rgba(0,0,0,0.36);
+}
+
+.topcoat-button--cta:hover,
+.topcoat-button--large--cta:hover {
+ background-color: #509bef;
+}
+
+.topcoat-button--cta:active,
+.topcoat-button--large--cta:active {
+ background-color: #0380e8;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+/* topdoc
+ name: Large Call To Action Button
+ description: Like call to action, but bigger
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+ Button
+ Button
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - large
+ - call to action
+*/
+
+.topcoat-button--large--cta {
+ font-size: 1.3rem;
+ font-weight: 400;
+ line-height: 4.375rem;
+ padding: 0 1.25rem;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+input[type="checkbox"] {
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ border: 0;
+ opacity: 0.001;
+ z-index: 1;
+ vertical-align: top;
+ outline: none;
+}
+
+.checkbox {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.checkbox__label {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.checkbox--disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+.checkbox:before,
+.checkbox:after {
+ content: '';
+ position: absolute;
+}
+
+.checkbox:before {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+input[type="checkbox"] {
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ border: 0;
+ opacity: 0.001;
+ z-index: 1;
+ vertical-align: top;
+ outline: none;
+}
+
+.checkbox,
+.topcoat-checkbox__checkmark {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.checkbox__label,
+.topcoat-checkbox {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.checkbox--disabled,
+input[type="checkbox"]:disabled + .topcoat-checkbox__checkmark {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+.checkbox:before,
+.checkbox:after,
+.topcoat-checkbox__checkmark:before,
+.topcoat-checkbox__checkmark:after {
+ content: '';
+ position: absolute;
+}
+
+.checkbox:before,
+.topcoat-checkbox__checkmark:before {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+}
+
+/* topdoc
+ name: Checkbox
+ description: Default skin for Topcoat checkbox
+ modifiers:
+ :focus: Focus state
+ :disabled: Disabled state
+ markup:
+
+
+
+ Default
+
+
+
+
+
+
+ Disabled
+
+ examples:
+ mobile checkbox: http://codepen.io/Topcoat/pen/piHcs
+ tags:
+ - desktop
+ - light
+ - mobile
+ - checkbox
+*/
+
+.topcoat-checkbox__checkmark {
+ height: 2rem;
+}
+
+input[type="checkbox"] {
+ height: 2rem;
+ width: 2rem;
+ margin-top: 0;
+ margin-right: -2rem;
+ margin-bottom: -2rem;
+ margin-left: 0;
+}
+
+input[type="checkbox"]:checked + .topcoat-checkbox__checkmark:after {
+ opacity: 1;
+}
+
+.topcoat-checkbox {
+ line-height: 2rem;
+}
+
+.topcoat-checkbox__checkmark:before {
+ width: 2rem;
+ height: 2rem;
+ background: #e5e9e8;
+ border: 1px solid #a5a8a8;
+ border-radius: 3px;
+ box-shadow: inset 0 1px #fff;
+}
+
+.topcoat-checkbox__checkmark {
+ width: 2rem;
+ height: 2rem;
+}
+
+.topcoat-checkbox__checkmark:after {
+ top: 1px;
+ left: 2px;
+ opacity: 0;
+ width: 28px;
+ height: 11px;
+ background: transparent;
+ border: 7px solid #666;
+ border-width: 7px;
+ border-top: none;
+ border-right: none;
+ border-radius: 2px;
+ -webkit-transform: rotate(-50deg);
+ -ms-transform: rotate(-50deg);
+ transform: rotate(-50deg);
+}
+
+input[type="checkbox"]:focus + .topcoat-checkbox__checkmark:before {
+ border: 1px solid #0940fd;
+ box-shadow: 0 0 0 2px #6fb5f1;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.button,
+.topcoat-icon-button,
+.topcoat-icon-button--quiet,
+.topcoat-icon-button--large,
+.topcoat-icon-button--large--quiet {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ text-decoration: none;
+}
+
+.button--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.button--disabled,
+.topcoat-icon-button:disabled,
+.topcoat-icon-button--quiet:disabled,
+.topcoat-icon-button--large:disabled,
+.topcoat-icon-button--large--quiet:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/* topdoc
+ name: Icon Button
+ description: Like button, but it has an icon.
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+
+
+
+
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - icon
+*/
+
+.topcoat-icon-button,
+.topcoat-icon-button--quiet,
+.topcoat-icon-button--large,
+.topcoat-icon-button--large--quiet {
+ padding: 0 0.75rem;
+ line-height: 3rem;
+ letter-spacing: 1px;
+ color: #454545;
+ text-shadow: 0 1px #fff;
+ vertical-align: baseline;
+ background-color: #e5e9e8;
+ box-shadow: inset 0 1px #fff;
+ border: 1px solid #a5a8a8;
+ border-radius: 6px;
+}
+
+.topcoat-icon-button:hover,
+.topcoat-icon-button--quiet:hover,
+.topcoat-icon-button--large:hover,
+.topcoat-icon-button--large--quiet:hover {
+ background-color: #edf1f1;
+}
+
+.topcoat-icon-button:active {
+ background-color: #d3d7d7;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+.topcoat-icon-button:focus,
+.topcoat-icon-button--quiet:focus,
+.topcoat-icon-button--quiet:hover:focus,
+.topcoat-icon-button--large:focus,
+.topcoat-icon-button--large--quiet:focus,
+.topcoat-icon-button--large--quiet:hover:focus {
+ border: 1px solid #0940fd;
+ box-shadow: 0 0 0 2px #6fb5f1;
+ outline: 0;
+}
+
+/* topdoc
+ name: Quiet Icon Button
+ description: Like quiet button, but it has an icon.
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+
+
+
+
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - icon
+ - quiet
+*/
+
+.topcoat-icon-button--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.topcoat-icon-button--quiet:hover,
+.topcoat-icon-button--large--quiet:hover {
+ text-shadow: 0 1px #fff;
+ border: 1px solid #a5a8a8;
+ box-shadow: inset 0 1px #fff;
+}
+
+.topcoat-icon-button--quiet:active,
+.topcoat-icon-button--large--quiet:active {
+ color: #454545;
+ text-shadow: 0 1px #fff;
+ background-color: #d3d7d7;
+ border: 1px solid #a5a8a8;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+/* topdoc
+ name: Large Icon Button
+ description: Like large button, but it has an icon.
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ :focus: Focused
+ markup:
+
+
+
+
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - icon
+ - large
+*/
+
+.topcoat-icon-button--large,
+.topcoat-icon-button--large--quiet {
+ width: 4.375rem;
+ height: 4.375rem;
+ line-height: 4.375rem;
+}
+
+.topcoat-icon-button--large:active {
+ background-color: #d3d7d7;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+}
+
+/* topdoc
+ name: Large Quiet Icon Button
+ description: Like large button, but it has an icon and this one is quiet.
+ modifiers:
+ :active: Active state
+ :disabled: Disabled state
+ :hover: Hover state
+ markup:
+
+
+
+
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - button
+ - icon
+ - large
+ - quiet
+*/
+
+.topcoat-icon-button--large--quiet {
+ background: transparent;
+ border: 1px solid transparent;
+ box-shadow: none;
+}
+
+.topcoat-icon,
+.topcoat-icon--large {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ overflow: hidden;
+ width: 1.62rem;
+ height: 1.62rem;
+ vertical-align: middle;
+ top: -1px;
+}
+
+.topcoat-icon--large {
+ width: 2.499999998125rem;
+ height: 2.499999998125rem;
+ top: -2px;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.input {
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ vertical-align: top;
+ outline: none;
+}
+
+.input:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.list {
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.list__header {
+ margin: 0;
+}
+
+.list__container {
+ padding: 0;
+ margin: 0;
+ list-style-type: none;
+}
+
+.list__item {
+ margin: 0;
+ padding: 0;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.list,
+.topcoat-list {
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.list__header,
+.topcoat-list__header {
+ margin: 0;
+}
+
+.list__container,
+.topcoat-list__container {
+ padding: 0;
+ margin: 0;
+ list-style-type: none;
+}
+
+.list__item,
+.topcoat-list__item {
+ margin: 0;
+ padding: 0;
+}
+
+/* topdoc
+ name: List
+ description: Topcoat default list skin
+ markup:
+
+
+
+
+ Item
+
+
+ Item
+
+
+ Item
+
+
+
+ tags:
+ - mobile
+ - list
+*/
+
+.topcoat-list {
+ border-top: 1px solid #bcbfbf;
+ border-bottom: 1px solid #eff1f1;
+ background-color: #dfe2e2;
+}
+
+.topcoat-list__header {
+ padding: 4px 20px;
+ font-size: 0.9em;
+ font-weight: 400;
+ background-color: #cccfcf;
+ color: #656565;
+ text-shadow: 0 1px 0 rgba(255,255,255,0.5);
+ border-top: 1px solid rgba(255,255,255,0.5);
+ border-bottom: 1px solid rgba(255,255,255,0.23);
+}
+
+.topcoat-list__container {
+ border-top: 1px solid #bcbfbf;
+ color: #454545;
+}
+
+.topcoat-list__item {
+ padding: 1.25rem;
+ border-top: 1px solid #eff1f1;
+ border-bottom: 1px solid #bcbfbf;
+}
+
+.topcoat-list__item:first-child {
+ border-top: 1px solid rgba(0,0,0,0.05);
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.navigation-bar {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ white-space: nowrap;
+ overflow: hidden;
+ word-spacing: 0;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.navigation-bar__item {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+}
+
+.navigation-bar__title {
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.navigation-bar,
+.topcoat-navigation-bar {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ white-space: nowrap;
+ overflow: hidden;
+ word-spacing: 0;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.navigation-bar__item,
+.topcoat-navigation-bar__item {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+}
+
+.navigation-bar__title,
+.topcoat-navigation-bar__title {
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+/* topdoc
+ name: Navigation Bar
+ description: A place where navigation goes to drink
+ markup:
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - navigation
+ - bar
+*/
+
+.topcoat-navigation-bar {
+ height: 4.375rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ background: #e5e9e8;
+ color: #000;
+ box-shadow: inset 0 -1px #b9bcbc, 0 1px #d4d6d6;
+}
+
+.topcoat-navigation-bar__item {
+ margin: 0;
+ line-height: 4.375rem;
+ vertical-align: top;
+}
+
+.topcoat-navigation-bar__title {
+ font-size: 1.3rem;
+ font-weight: 400;
+ color: #000;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+input[type="radio"] {
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ border: 0;
+ opacity: 0.001;
+ z-index: 1;
+ vertical-align: top;
+ outline: none;
+}
+
+.radio-button {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.radio-button__label {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.radio-button:before,
+.radio-button:after {
+ content: '';
+ position: absolute;
+ border-radius: 100%;
+}
+
+.radio-button:after {
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.radio-button:before {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+}
+
+.radio-button--disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+input[type="radio"] {
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ border: 0;
+ opacity: 0.001;
+ z-index: 1;
+ vertical-align: top;
+ outline: none;
+}
+
+.radio-button,
+.topcoat-radio-button__checkmark {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.radio-button__label,
+.topcoat-radio-button {
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.radio-button:before,
+.radio-button:after,
+.topcoat-radio-button__checkmark:before,
+.topcoat-radio-button__checkmark:after {
+ content: '';
+ position: absolute;
+ border-radius: 100%;
+}
+
+.radio-button:after,
+.topcoat-radio-button__checkmark:after {
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.radio-button:before,
+.topcoat-radio-button__checkmark:before {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+}
+
+.radio-button--disabled,
+input[type="radio"]:disabled + .topcoat-radio-button__checkmark {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/* topdoc
+ name: Radio Button
+ description: A button that can play music, but usually just plays ads.
+ modifiers:
+ markup:
+
+
+
+
+
+
+
+
+
+ Left label
+
+
+
+
+
+
+
+
+
+ Right label
+
+
+
+
+
+
+
+ Disabled
+
+ examples:
+ Mobile Radio Button: http://codepen.io/Topcoat/pen/HDcJj
+ tags:
+ - desktop
+ - light
+ - mobile
+ - Radio
+*/
+
+input[type="radio"] {
+ height: 1.875rem;
+ width: 1.875rem;
+ margin-top: 0;
+ margin-right: -1.875rem;
+ margin-bottom: -1.875rem;
+ margin-left: 0;
+}
+
+input[type="radio"]:checked + .topcoat-radio-button__checkmark:after {
+ opacity: 1;
+}
+
+.topcoat-radio-button {
+ color: #454545;
+ line-height: 1.875rem;
+}
+
+.topcoat-radio-button__checkmark:before {
+ width: 1.875rem;
+ height: 1.875rem;
+ background: #e5e9e8;
+ border: 1px solid #a5a8a8;
+ box-shadow: inset 0 1px #fff;
+}
+
+.topcoat-radio-button__checkmark {
+ position: relative;
+ width: 1.875rem;
+ height: 1.875rem;
+}
+
+.topcoat-radio-button__checkmark:after {
+ opacity: 0;
+ width: 0.875rem;
+ height: 0.875rem;
+ background: #666;
+ border: 1px solid rgba(0,0,0,0.1);
+ box-shadow: 0 1px rgba(255,255,255,0.5);
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ top: 7px;
+ left: 7px;
+}
+
+input[type="radio"]:focus + .topcoat-radio-button__checkmark:before {
+ border: 1px solid #0940fd;
+ box-shadow: 0 0 0 2px #6fb5f1;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.search-input {
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ vertical-align: top;
+ outline: none;
+ -webkit-appearance: none;
+}
+
+input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none;
+}
+
+.search-input:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.search-input,
+.topcoat-search-input,
+.topcoat-search-input--large {
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ vertical-align: top;
+ outline: none;
+ -webkit-appearance: none;
+}
+
+input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none;
+}
+
+.search-input:disabled,
+.topcoat-search-input:disabled,
+.topcoat-search-input--large:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/* topdoc
+ name: Search Input
+ description: A text input designed for searching.
+ modifiers:
+ :disabled: Disabled state
+ markup:
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - text
+ - input
+ - search
+ - form
+*/
+
+.topcoat-search-input,
+.topcoat-search-input--large {
+ line-height: 3rem;
+ font-size: 16px;
+ border: 1px solid #a5a8a8;
+ background-color: #d3d7d7;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+ color: #454545;
+ padding: 0 0 0 2rem;
+ border-radius: 30px;
+ background-image: url("../img/search.svg");
+ background-position: 1em center;
+ background-repeat: no-repeat;
+ background-size: 16px;
+}
+
+.topcoat-search-input:focus,
+.topcoat-search-input--large:focus {
+ background-image: url("../img/search_dark.svg");
+ background-color: #edf1f1;
+ color: #000;
+ border: 1px solid #0940fd;
+ box-shadow: 0 0 0 2px #6fb5f1;
+}
+
+.topcoat-search-input::-webkit-search-cancel-button,
+.topcoat-search-input::-webkit-search-decoration,
+.topcoat-search-input--large::-webkit-search-cancel-button,
+.topcoat-search-input--large::-webkit-search-decoration {
+ margin-right: 5px;
+}
+
+.topcoat-search-input:focus::-webkit-input-placeholder,
+.topcoat-search-input:focus::-webkit-input-placeholder {
+ color: #c6c8c8;
+}
+
+.topcoat-search-input:disabled::-webkit-input-placeholder {
+ color: #000;
+}
+
+.topcoat-search-input:disabled::-moz-placeholder {
+ color: #000;
+}
+
+.topcoat-search-input:disabled:-ms-input-placeholder {
+ color: #000;
+}
+
+/* topdoc
+ name: Large Search Input
+ description: A large text input designed for searching.
+ modifiers:
+ :disabled: Disabled state
+ markup:
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - text
+ - input
+ - search
+ - form
+ - large
+*/
+
+.topcoat-search-input--large {
+ line-height: 4.375rem;
+ font-size: 1.3rem;
+ font-weight: 200;
+ padding: 0 0 0 2.9rem;
+ border-radius: 40px;
+ background-position: 1.2em center;
+ background-size: 1.3rem;
+}
+
+.topcoat-search-input--large:disabled {
+ color: #000;
+}
+
+.topcoat-search-input--large:disabled::-webkit-input-placeholder {
+ color: #000;
+}
+
+.topcoat-search-input--large:disabled::-moz-placeholder {
+ color: #000;
+}
+
+.topcoat-search-input--large:disabled:-ms-input-placeholder {
+ color: #000;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.input,
+.topcoat-text-input,
+.topcoat-text-input--large {
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ vertical-align: top;
+ outline: none;
+}
+
+.input:disabled,
+.topcoat-text-input:disabled,
+.topcoat-text-input--large:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/* topdoc
+ name: Text input
+ description: Topdoc text input
+ markup:
+
+
+
+
+ tags:
+ - desktop
+ - mobile
+ - text
+ - input
+*/
+
+.topcoat-text-input,
+.topcoat-text-input--large {
+ line-height: 3rem;
+ font-size: 16px;
+ letter-spacing: 1px;
+ padding: 0 1.25rem;
+ border: 1px solid #a5a8a8;
+ border-radius: 6px;
+ background-color: #d3d7d7;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+ color: #454545;
+ vertical-align: top;
+}
+
+.topcoat-text-input:focus,
+.topcoat-text-input--large:focus {
+ background-color: #edf1f1;
+ color: #000;
+ border: 1px solid #0940fd;
+ box-shadow: 0 0 0 2px #6fb5f1;
+}
+
+.topcoat-text-input:disabled::-webkit-input-placeholder {
+ color: #000;
+}
+
+.topcoat-text-input:disabled::-moz-placeholder {
+ color: #000;
+}
+
+.topcoat-text-input:disabled:-ms-input-placeholder {
+ color: #000;
+}
+
+/* topdoc
+ name: Large Text Input
+ description: A bigger input, still for text.
+ modifiers:
+ :disabled: Disabled state
+ markup:
+
+
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - form
+ - input
+ - large
+*/
+
+.topcoat-text-input--large {
+ line-height: 4.375rem;
+ font-size: 1.3rem;
+}
+
+.topcoat-text-input--large:disabled {
+ color: #000;
+}
+
+.topcoat-text-input--large:disabled::-webkit-input-placeholder {
+ color: #000;
+}
+
+.topcoat-text-input--large:disabled::-moz-placeholder {
+ color: #000;
+}
+
+.topcoat-text-input--large:disabled:-ms-input-placeholder {
+ color: #000;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.textarea {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ vertical-align: top;
+ resize: none;
+ outline: none;
+}
+
+.textarea:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+/**
+*
+* Copyright 2012 Adobe Systems Inc.;
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+.textarea,
+.topcoat-textarea,
+.topcoat-textarea--large {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ vertical-align: top;
+ resize: none;
+ outline: none;
+}
+
+.textarea:disabled,
+.topcoat-textarea:disabled,
+.topcoat-textarea--large:disabled {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/* topdoc
+ name: Textarea
+ description: A whole area, just for text.
+ modifiers:
+ :disabled: Disabled state
+ markup:
+
+
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - form
+ - input
+ - textarea
+*/
+
+.topcoat-textarea,
+.topcoat-textarea--large {
+ padding: 2rem;
+ font-size: 2.5rem;
+ font-weight: 200;
+ border-radius: 6px;
+ line-height: 3rem;
+ border: 1px solid #a5a8a8;
+ background-color: #d3d7d7;
+ box-shadow: inset 0 1px rgba(0,0,0,0.12);
+ color: #454545;
+ letter-spacing: 1px;
+}
+
+.topcoat-textarea:focus,
+.topcoat-textarea--large:focus {
+ background-color: #edf1f1;
+ color: #000;
+ border: 1px solid #0940fd;
+ box-shadow: 0 0 0 2px #6fb5f1;
+}
+
+.topcoat-textarea:disabled::-webkit-input-placeholder {
+ color: #000;
+}
+
+.topcoat-textarea:disabled::-moz-placeholder {
+ color: #000;
+}
+
+.topcoat-textarea:disabled:-ms-input-placeholder {
+ color: #000;
+}
+
+/* topdoc
+ name: Large Textarea
+ description: A whole area, just for text; now available in large.
+ modifiers:
+ :disabled: Disabled state
+ markup:
+
+
+
+
+ tags:
+ - desktop
+ - light
+ - mobile
+ - form
+ - input
+ - textarea
+*/
+
+.topcoat-textarea--large {
+ font-size: 3rem;
+ line-height: 4.375rem;
+}
+
+.topcoat-textarea--large:disabled {
+ color: #000;
+}
+
+.topcoat-textarea--large:disabled::-webkit-input-placeholder {
+ color: #000;
+}
+
+.topcoat-textarea--large:disabled::-moz-placeholder {
+ color: #000;
+}
+
+.topcoat-textarea--large:disabled:-ms-input-placeholder {
+ color: #000;
+}
+
+@font-face {
+ font-family: "Source Sans";
+ src: url("../font/SourceSansPro-Regular.otf");
+}
+
+@font-face {
+ font-family: "Source Sans";
+ src: url("../font/SourceSansPro-Light.otf");
+ font-weight: 200;
+}
+
+@font-face {
+ font-family: "Source Sans";
+ src: url("../font/SourceSansPro-Semibold.otf");
+ font-weight: 600;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #dfe2e2;
+ color: #000;
+ font: 16px "Source Sans", helvetica, arial, sans-serif;
+ font-weight: 200;
+ text-rendering: optimizeLegibility;
+}
+
+:focus {
+ outline-color: transparent;
+ outline-style: none;
+}
+
+.topcoat-icon--menu-stack {
+ background: url("../img/hamburger_dark.svg") no-repeat;
+ background-size: cover;
+}
+
+.quarter {
+ width: 25%;
+}
+
+.half {
+ width: 50%;
+}
+
+.three-quarters {
+ width: 75%;
+}
+
+.third {
+ width: 33.333%;
+}
+
+.two-thirds {
+ width: 66.666%;
+}
+
+.full {
+ width: 100%;
+}
+
+.left {
+ text-align: left;
+}
+
+.center {
+ text-align: center;
+}
+
+.right {
+ text-align: right;
+}
+
+.reset-ui {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background-clip: padding-box;
+ position: relative;
+ display: inline-block;
+ vertical-align: top;
+ padding: 0;
+ margin: 0;
+ font: inherit;
+ color: inherit;
+ background: transparent;
+ border: none;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+/* Call To Action */
+
+/* Icons */
+
+/* Navigation Bar */
+
+/* Text Input */
+
+/* Search Input */
+
+/* List */
+
+/* Checkbox */
+
+/* Overlay */
+
+/* Progress bar */
+
+/* Checkbox */
+
+/* Radio Button */
+
+/* Icon Button */
+
+/* Navigation bar */
+
+/* List */
+
+/* Search Input */
+
+/* Textarea */
+
+/* Checkbox */
+
+/* Radio */
+
+/* Search Input */
+
+/* Call To Action */
+
+/* Icons */
+
+/* Navigation Bar */
+
+/* Text Input */
+
+/* List */
+
+/*Overlay*/
+
+/* Progress bar */
+
+/* Checkbox */
+
+/* Range input */
+
+/* Containers */
+
+/* Icon Button */
+
+/* Navigation bar */
+
+/* List */
+
+/* Search Input */
+
+/* Text Area */
+
+/* Checkbox */
+
+/* Radio */
+
+/* Range input */
+
+/* Search Input */
+
+/* Text Input */
+
+/* Radio input */
+
+/* Overlay */
+
+/* Textarea */
+
+/* Progress bar container */
+
+/* Progress bar progress */
+
+/* Search input */
\ No newline at end of file
diff --git a/docs/fonts/sourcecodepro-regular-webfont.eot b/docs/fonts/sourcecodepro-regular-webfont.eot
new file mode 100644
index 0000000..9e9e4de
Binary files /dev/null and b/docs/fonts/sourcecodepro-regular-webfont.eot differ
diff --git a/docs/fonts/sourcecodepro-regular-webfont.svg b/docs/fonts/sourcecodepro-regular-webfont.svg
new file mode 100644
index 0000000..f4a1739
--- /dev/null
+++ b/docs/fonts/sourcecodepro-regular-webfont.svg
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/fonts/sourcecodepro-regular-webfont.ttf b/docs/fonts/sourcecodepro-regular-webfont.ttf
new file mode 100644
index 0000000..6eb48e7
Binary files /dev/null and b/docs/fonts/sourcecodepro-regular-webfont.ttf differ
diff --git a/docs/fonts/sourcecodepro-regular-webfont.woff b/docs/fonts/sourcecodepro-regular-webfont.woff
new file mode 100644
index 0000000..2383f47
Binary files /dev/null and b/docs/fonts/sourcecodepro-regular-webfont.woff differ
diff --git a/docs/fonts/sourcesanspro-light-webfont.eot b/docs/fonts/sourcesanspro-light-webfont.eot
new file mode 100644
index 0000000..bda2005
Binary files /dev/null and b/docs/fonts/sourcesanspro-light-webfont.eot differ
diff --git a/docs/fonts/sourcesanspro-light-webfont.svg b/docs/fonts/sourcesanspro-light-webfont.svg
new file mode 100644
index 0000000..e031390
--- /dev/null
+++ b/docs/fonts/sourcesanspro-light-webfont.svg
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/fonts/sourcesanspro-light-webfont.ttf b/docs/fonts/sourcesanspro-light-webfont.ttf
new file mode 100644
index 0000000..0959ece
Binary files /dev/null and b/docs/fonts/sourcesanspro-light-webfont.ttf differ
diff --git a/docs/fonts/sourcesanspro-light-webfont.woff b/docs/fonts/sourcesanspro-light-webfont.woff
new file mode 100644
index 0000000..522d5ab
Binary files /dev/null and b/docs/fonts/sourcesanspro-light-webfont.woff differ
diff --git a/docs/fonts/sourcesanspro-regular-webfont.eot b/docs/fonts/sourcesanspro-regular-webfont.eot
new file mode 100644
index 0000000..2b75abb
Binary files /dev/null and b/docs/fonts/sourcesanspro-regular-webfont.eot differ
diff --git a/docs/fonts/sourcesanspro-regular-webfont.svg b/docs/fonts/sourcesanspro-regular-webfont.svg
new file mode 100644
index 0000000..581a849
--- /dev/null
+++ b/docs/fonts/sourcesanspro-regular-webfont.svg
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/fonts/sourcesanspro-regular-webfont.ttf b/docs/fonts/sourcesanspro-regular-webfont.ttf
new file mode 100644
index 0000000..e166286
Binary files /dev/null and b/docs/fonts/sourcesanspro-regular-webfont.ttf differ
diff --git a/docs/fonts/sourcesanspro-regular-webfont.woff b/docs/fonts/sourcesanspro-regular-webfont.woff
new file mode 100644
index 0000000..315c98a
Binary files /dev/null and b/docs/fonts/sourcesanspro-regular-webfont.woff differ
diff --git a/docs/fonts/sourcesanspro-semibold-webfont.eot b/docs/fonts/sourcesanspro-semibold-webfont.eot
new file mode 100644
index 0000000..ddf5d11
Binary files /dev/null and b/docs/fonts/sourcesanspro-semibold-webfont.eot differ
diff --git a/docs/fonts/sourcesanspro-semibold-webfont.svg b/docs/fonts/sourcesanspro-semibold-webfont.svg
new file mode 100644
index 0000000..317e536
--- /dev/null
+++ b/docs/fonts/sourcesanspro-semibold-webfont.svg
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/fonts/sourcesanspro-semibold-webfont.ttf b/docs/fonts/sourcesanspro-semibold-webfont.ttf
new file mode 100644
index 0000000..6d97e7b
Binary files /dev/null and b/docs/fonts/sourcesanspro-semibold-webfont.ttf differ
diff --git a/docs/fonts/sourcesanspro-semibold-webfont.woff b/docs/fonts/sourcesanspro-semibold-webfont.woff
new file mode 100644
index 0000000..d844315
Binary files /dev/null and b/docs/fonts/sourcesanspro-semibold-webfont.woff differ
diff --git a/docs/fonts/stylesheet.css b/docs/fonts/stylesheet.css
new file mode 100644
index 0000000..2d66502
--- /dev/null
+++ b/docs/fonts/stylesheet.css
@@ -0,0 +1,57 @@
+
+@font-face {
+ font-family: 'source-sans-pro';
+ src: url('sourcesanspro-light-webfont.eot');
+ src: url('sourcesanspro-light-webfont.eot?#iefix') format('embedded-opentype'),
+ url('sourcesanspro-light-webfont.woff') format('woff'),
+ url('sourcesanspro-light-webfont.ttf') format('truetype'),
+ url('sourcesanspro-light-webfont.svg#source_sans_prolight') format('svg');
+ font-weight: 300;
+ font-style: normal;
+
+}
+
+
+
+
+@font-face {
+ font-family: 'source-sans-pro';
+ src: url('sourcesanspro-regular-webfont.eot');
+ src: url('sourcesanspro-regular-webfont.eot?#iefix') format('embedded-opentype'),
+ url('sourcesanspro-regular-webfont.woff') format('woff'),
+ url('sourcesanspro-regular-webfont.ttf') format('truetype'),
+ url('sourcesanspro-regular-webfont.svg#source_sans_proregular') format('svg');
+ font-weight: 400;
+ font-style: normal;
+
+}
+
+
+
+
+@font-face {
+ font-family: 'source-sans-pro';
+ src: url('sourcesanspro-semibold-webfont.eot');
+ src: url('sourcesanspro-semibold-webfont.eot?#iefix') format('embedded-opentype'),
+ url('sourcesanspro-semibold-webfont.woff') format('woff'),
+ url('sourcesanspro-semibold-webfont.ttf') format('truetype'),
+ url('sourcesanspro-semibold-webfont.svg#source_sans_prosemibold') format('svg');
+ font-weight: 600;
+ font-style: normal;
+
+}
+
+
+
+
+@font-face {
+ font-family: 'source-code-pro';
+ src: url('sourcecodepro-regular-webfont.eot');
+ src: url('sourcecodepro-regular-webfont.eot?#iefix') format('embedded-opentype'),
+ url('sourcecodepro-regular-webfont.woff') format('woff'),
+ url('sourcecodepro-regular-webfont.ttf') format('truetype'),
+ url('sourcecodepro-regular-webfont.svg#source_code_proregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+
+}
\ No newline at end of file
diff --git a/docs/img/search.svg b/docs/img/search.svg
new file mode 100644
index 0000000..d18a4fa
--- /dev/null
+++ b/docs/img/search.svg
@@ -0,0 +1,11 @@
+
+
+ Slice 1
+ Created with Sketch (http://www.bohemiancoding.com/sketch)
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/img/search_dark.svg b/docs/img/search_dark.svg
new file mode 100644
index 0000000..cbfae91
--- /dev/null
+++ b/docs/img/search_dark.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+]>
+
+
+
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..f68187f
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,2393 @@
+
+
+
+
+
+ RedRaphaël API Reference
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RedRaphaël
+ API Reference
+
+
+
+
+
+*
+ Creates a copy of existing animation object with given delay.
+*
+
+
Parameters *
+
+
delay
+number
+number of ms to pass between animation start and actual animation
+
+
*
+
+
Returns: object new altered Animation object
+
var anim = Raphael.animation({cx: 10, cy: 20}, 2e3);
+ circle1.animate(anim); // run the given animation immediately
+ circle2.animate(anim.delay(500)); // run the given animation after 500 ms
+
+
+*
+ Creates a copy of existing animation object with given repetition.
+*
+
+
Parameters *
+
+
repeat
+number
+number iterations of animation. For infinite animation pass Infinity
+
+
*
+
+
Returns: object new altered Animation object
+
+
+*
+ Creates and starts animation for given element.
+*
+
+
Parameters *
+
+
params
+object
+final attributes for the element, see also Element.attr
+ ms
+number
+number of milliseconds for animation to run
+ easing
+optional
+string
+easing type. Accept one of Raphael.easing_formulas or CSS format: cubic‐bezier(XX, XX, XX, XX)
+ callback
+optional
+function
+callback function. Will be called at the end of animation.
+
+
or
+
+
+
*
+
+
Returns: object original element
+
+*
+ Acts similar to Element.animate , but ensure that given animation runs in sync with another given element.
+*
+
+
Parameters *
+
+
el
+object
+element to sync with
+ anim
+object
+animation to sync with
+ params
+optional
+object
+final attributes for the element, see also Element.attr
+ ms
+optional
+number
+number of milliseconds for animation to run
+ easing
+optional
+string
+easing type. Accept on of Raphael.easing_formulas or CSS format: cubic‐bezier(XX, XX, XX, XX)
+ callback
+optional
+function
+callback function. Will be called at the end of animation.
+
+
or
+
+
element
+object
+element to sync with
+ anim
+object
+animation to sync with
+ animation
+optional
+object
+animation object, see Raphael.animation
+
+
*
+
+
Returns: object original element
+
+*
+ Adds event handler for click for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+
+
Returns: object clone of a given element
+
*
+
+
+*
+ Adds or retrieves given value asociated with given key.
+*
+ See also Element.removeData
+
+
Parameters key
+string
+key to store data
+ value
+optional
+any
+value to store
+
+
Returns: object Element
+
or, if value is not specified:
+
+
Returns: any value
+
Usage for (var i = 0, i < 5, i++) {
+ paper.circle(10 + 15 * i, 10, 10)
+ .attr({fill: "#000"})
+ .data("i", i)
+ .click(function () {
+ alert(this.data("i"));
+ });
+ }
+
+
+*
+ Adds event handler for double click for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Adds event handlers for drag of the element.
+
+
Parameters onmove
+function
+handler for moving
+ onstart
+function
+handler for drag start
+ onend
+function
+handler for drag end
+ mcontext
+optional
+object
+context for moving handler
+ scontext
+optional
+object
+context for drag start handler
+ econtext
+optional
+object
+context for drag end handler
+
+
Additionaly following drag
events will be triggered: drag.start.<id>
on start,
+ drag.end.<id>
on end and drag.move.<id>
on every move. When element will be dragged over another element
+ drag.over.<id>
will be fired as well.
+
+
Start event and start handler will be called in specified context or in context of the element with following parameters:
+
+
x number x position of the mouse
+y number y position of the mouse
+event object DOM event object
+
+
Move event and move handler will be called in specified context or in context of the element with following parameters:
+
+
dx number shift by x from the start point
+dy number shift by y from the start point
+x number x position of the mouse
+y number y position of the mouse
+event object DOM event object
+
+
End event and end handler will be called in specified context or in context of the element with following parameters:
+
+
event object DOM event object
+
+
Returns: object Element
+
+*
+ Return bounding box for a given element
+*
+
+
Parameters *
+
+
isWithoutTransform
+boolean
+flag, true
if you want to have bounding box before transformations. Default is false
.
+
+
Returns: object Bounding box object:
+
{x: number top left corner x
+y: number top left corner y
+x2: number bottom right corner x
+y2: number bottom right corner y
+width: number width
+height: number height
+ }
+
+*
+ Retrieves the element data
+
+
Returns: object data
+
+*
+ Return set of elements that create glow-like effect around given element. See Paper.set .
+
+
Note: Glow is not connected to the element. If you change element attributes it won’t adjust itself.
+*
+
+
Parameters *
+
+
glow
+optional
+object
+parameters object with all properties optional:
+
+
{width number size of the glow, default is 10
+fill boolean will it be filled, default is false
+opacity number opacity, default is 0.5
+offsetx number horizontal offset, default is 0
+offsety number vertical offset, default is 0
+color string glow colour, default is black
+ }
+
Returns: object Paper.set of elements that represents glow
+
+*
+ Adds event handlers for hover for the element.
+
+
Parameters f_in
+function
+handler for hover in
+ f_out
+function
+handler for hover out
+ icontext
+optional
+object
+context for hover in handler
+ ocontext
+optional
+object
+context for hover out handler
+
+
Returns: object Element
+
+*
+ Determine if given point is inside this element’s shape
+*
+
+
Parameters *
+
+
x
+number
+x coordinate of the point
+ y
+number
+y coordinate of the point
+
+
Returns: boolean true
if point inside the shape
+
+object *
+ Keeps Matrix object, which represents element transformation
+
+
+*
+ Adds event handler for mousedown for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Adds event handler for mousemove for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Adds event handler for mouseout for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Adds event handler for mouseover for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Adds event handler for mouseup for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Shortcut for assigning event handler for drag.over.<id>
event, where id is id of the element (see Element.id ).
+
+
Parameters f
+function
+handler for event, first argument would be the element you are dragging over
+
+
+*
+ Stops animation of the element with ability to resume it later on.
+*
+
+
Parameters *
+
+
anim
+optional
+object
+animation object
+
+
*
+
+
Returns: object original element
+
+*
+ Removes value associated with an element by given key.
+ If key is not provided, removes all the data of the element.
+
+
Parameters key
+optional
+string
+key
+
+
Returns: object Element
+
+*
+ Resumes animation if it was paused with Element.pause method.
+*
+
+
Parameters *
+
+
anim
+optional
+object
+animation object
+
+
*
+
+
Returns: object original element
+
+*
+ Sets the status of animation of the element in milliseconds. Similar to Element.status method.
+*
+
+
Parameters *
+
+
anim
+object
+animation object
+ value
+number
+number of milliseconds from the beginning of the animation
+
+
*
+
+
Returns: object original element if value
is specified
+
Note, that during animation following events are triggered:
+
+
On each animation frame event anim.frame.<id>
, on start anim.start.<id>
and on end anim.finish.<id>
.
+
+
+*
+ Gets or sets the status of animation of the element.
+*
+
+
Parameters *
+
+
anim
+optional
+object
+animation object
+ value
+optional
+number
+0 – 1. If specified, method works like a setter and sets the status of a given animation to the value. This will cause animation to jump to the given position.
+
+
*
+
+
Returns: number status
+
or
+
+
Returns: array status if anim
is not specified. Array of objects in format:
+
{anim: object animation object
+status: number status
+ }
+
or
+
+
Returns: object original element if value
is specified
+
+*
+ Stops animation of the element.
+*
+
+
Parameters *
+
+
anim
+optional
+object
+animation object
+
+
*
+
+
Returns: object original element
+
+*
+ Adds event handler for touchcancel for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Adds event handler for touchend for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Adds event handler for touchmove for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Adds event handler for touchstart for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for click for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for double click for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes all drag event handlers from given element.
+
+
+*
+ Removes event handlers for hover for the element.
+
+
Parameters f_in
+function
+handler for hover in
+ f_out
+function
+handler for hover out
+
+
Returns: object Element
+
+*
+ Removes event handler for mousedown for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for mousemove for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for mouseout for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for mouseover for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for mouseup for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for touchcancel for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for touchend for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for touchmove for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+*
+ Removes event handler for touchstart for the element.
+
+
Parameters handler
+function
+handler for the event
+
+
Returns: object Element
+
+
+*
+ Adds given matrix to existing one.
+
+
Parameters a
+number
+
+ b
+number
+
+ c
+number
+
+ d
+number
+
+ e
+number
+
+ f
+number
+
+
+
r
+
+
+*
+ Returns copy of the matrix
+
+
Returns: object Matrix
+
+*
+ Returns inverted version of the matrix
+
+
Returns: object Matrix
+
+*
+ Rotates the matrix
+
+
Parameters a
+number
+
+ x
+number
+
+ y
+number
+
+
+
+*
+ Scales the matrix
+
+
Parameters x
+number
+
+ y
+optional
+number
+
+ cx
+optional
+number
+
+ cy
+optional
+number
+
+
+
+*
+ Splits matrix into primitive transformations
+
+
Returns: object in format:
+
dx number translation by x
+dy number translation by y
+scalex number scale by x
+scaley number scale by y
+shear number shear
+rotate number rotation in deg
+isSimple boolean could it be represented via simple transformations
+
+
+*
+ Return transform string that represents given matrix
+
+
Returns: string transform string
+
+*
+ Translate the matrix
+
+
Parameters x
+number
+
+ y
+number
+
+
+
+*
+ Return x coordinate for given point after transformation described by the matrix. See also Matrix.y
+
+
Parameters x
+number
+
+ y
+number
+
+
+
Returns: number x
+
+*
+ Return y coordinate for given point after transformation described by the matrix. See also Matrix.x
+
+
Parameters x
+number
+
+ y
+number
+
+
+
Returns: number y
+
+
+*
+ Imports elements in JSON array in format {type: type, <attributes>}
+*
+
+
Parameters *
+
+
+
Returns: object resulting set of imported elements
+
Usage paper.add([
+ {
+ type: "circle",
+ cx: 10,
+ cy: 10,
+ r: 5
+ },
+ {
+ type: "rect",
+ x: 10,
+ y: 10,
+ width: 10,
+ height: 10,
+ fill: "#fc0"
+ }
+ ]);
+
+
+*
+ Points to the bottom element on the paper
+
+
+
+*
+ Draws a circle.
+*
+
+
Parameters *
+
+
x
+number
+x coordinate of the centre
+ y
+number
+y coordinate of the centre
+ r
+number
+radius
+
+
Returns: object Raphaël element object with type “circle”
+
*
+
+
Usage var c = paper.circle(50, 50, 40);
+
+
+object *
+ If you have a set of attributes that you would like to represent
+ as a function of some number you can do it easily with custom attributes:
+
+
Usage paper.customAttributes.hue = function (num) {
+ num = num % 1;
+ return {fill: "hsb(" + num + ", 0.75, 1)"};
+ };
+ // Custom attribute “hue” will change fill
+ // to be given hue with fixed saturation and brightness.
+ // Now you can use it like this:
+ var c = paper.circle(10, 10, 10).attr({hue: .45});
+ // or even like this:
+ c.animate({hue: 1}, 1e3);
+
+ // You could also create custom attribute
+ // with multiple parameters:
+ paper.customAttributes.hsb = function (h, s, b) {
+ return {fill: "hsb(" + [h, s, b].join(",") + ")"};
+ };
+ c.attr({hsb: "0.5 .8 1"});
+ c.animate({hsb: [1, 0, 0.5]}, 1e3);
+
+
+*
+ Draws an ellipse.
+*
+
+
Parameters *
+
+
x
+number
+x coordinate of the centre
+ y
+number
+y coordinate of the centre
+ rx
+number
+horizontal radius
+ ry
+number
+vertical radius
+
+
Returns: object Raphaël element object with type “ellipse”
+
*
+
+
Usage var c = paper.ellipse(50, 50, 40, 20);
+
+
+*
+ Executes given function for each element on the paper
+
+
If callback function returns false
it will stop loop running.
+*
+
+
Parameters *
+
+
callback
+function
+function to run
+ thisArg
+object
+context object for the callback
+
+
Returns: object Paper object
+
Usage paper.forEach(function (el) {
+ el.attr({ stroke: "blue" });
+ });
+
+
Paper.getElementByPoint⚓ ➭
+*
+ Returns you topmost element under given point.
+*
+
+
Returns: object Raphaël element object
+
Parameters *
+
+
x
+number
+x coordinate from the top left corner of the window
+ y
+number
+y coordinate from the top left corner of the window
+
+
Usage paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
+
+
Paper.getElementsByBBox⚓ ➭
+*
+ Returns set of elements that have an intersecting bounding box
+*
+
+
Parameters *
+
+
bbox
+object
+bbox to check with
+
+
Returns: object Set
+
Paper.getElementsByPoint⚓ ➭
+*
+ Returns set of elements that have common point inside
+*
+
+
Parameters *
+
+
x
+number
+x coordinate of the point
+ y
+number
+y coordinate of the point
+
+
Returns: object Set
+
+*
+ Finds font object in the registered fonts by given parameters. You could specify only one word from the font name, like “Myriad” for “Myriad Pro”.
+*
+
+
Parameters *
+
+
family
+string
+font family name or any word from it
+ weight
+optional
+string
+font weight
+ style
+optional
+string
+font style
+ stretch
+optional
+string
+font stretch
+
+
Returns: object the font object
+
Usage paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30);
+
+
+*
+ Creates a group
+*
+
+
Parameters *
+
+
id
+number
+id of the group
+
+
Returns: object Raphaël element object with type “group”
+
*
+
+
Usage
+
+*
+ Hides a paper
+*
+
+
Usage
+
+*
+ Embeds an image into the surface.
+*
+
+
Parameters *
+
+
src
+string
+URI of the source image
+ x
+number
+x coordinate position
+ y
+number
+y coordinate position
+ width
+number
+width of the image
+ height
+number
+height of the image
+
+
Returns: object Raphaël element object with type “image”
+
*
+
+
Usage var c = paper.image("apple.png", 10, 10, 80, 80);
+
+
+*
+ Creates a path element by given path data string.
+
+
Parameters pathString
+optional
+string
+path string in SVG format.
+
+
Path string consists of one-letter commands, followed by comma seprarated arguments in numercal form. Example:
+
+
+
Here we can see two commands: “M”, with arguments (10, 20)
and “L” with arguments (30, 40)
. Upper case letter mean command is absolute, lower case—relative.
+
+
+
Here is short list of commands available, for more details see SVG path string format .
+
Command Name Parameters
+ M moveto (x y)+
+ Z closepath (none)
+ L lineto (x y)+
+ H horizontal lineto x+
+ V vertical lineto y+
+ C curveto (x1 y1 x2 y2 x y)+
+ S smooth curveto (x2 y2 x y)+
+ Q quadratic Bézier curveto (x1 y1 x y)+
+ T smooth quadratic Bézier curveto (x y)+
+ A elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
+ R Catmull-Rom curveto *x1 y1 (x y)+
+
“Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier.
+ Note: there is a special case when path consist of just three commands: “M10,10R…z”. In this case path will smoothly connects to its beginning.
+
+
Usage var c = paper.path("M10 10L90 90");
+ // draw a diagonal line:
+ // move to 10,10, line to 90,90
+
+
For example of path strings, check out these icons: http://raphaeljs.com/icons/
+
+
+*
+ Creates path that represent given text written using given font at given position with given size.
+ Result of the method is path element that contains whole text as a separate path.
+*
+
+
Parameters *
+
+
x
+number
+x position of the text
+ y
+number
+y position of the text
+ string
+string
+text to print
+ font
+object
+font object, see Paper.getFont
+ size
+optional
+number
+size of the font, default is 16
+ origin
+optional
+string
+could be "baseline"
or "middle"
, default is "middle"
+ letter_spacing
+optional
+number
+number in range -1..1
, default is 0
+
+
Returns: object resulting path element, which consist of all letters
+
Usage var txt = r.print(10, 50, "print", r.getFont("Museo"), 30).attr({fill: "#fff"});
+
+
+*
+ Points to the Raphael object/function
+
+
+
+
Draws a rectangle.
+*
+
+
Parameters *
+
+
x
+number
+x coordinate of the top left corner
+ y
+number
+y coordinate of the top left corner
+ width
+number
+width
+ height
+number
+height
+ r
+optional
+number
+radius for rounded corners, default is 0
+
+
Returns: object Raphaël element object with type “rect”
+
*
+
+
Usage // regular rectangle
+ var c = paper.rect(10, 10, 50, 50);
+ // rectangle with rounded corners
+ var c = paper.rect(40, 40, 50, 50, 10);
+
+
+*
+ There is an inconvenient rendering bug in Safari (WebKit):
+ sometimes the rendering should be forced.
+ This method should help with dealing with this bug.
+
+
+*
+ Creates array-like object to keep and operate several elements at once.
+ Warning: it doesn’t create any elements for itself in the page, it just groups existing elements.
+ Sets act as pseudo elements — all methods available to an element can be used on a set.
+
+
Returns: object array-like object that represents set of elements
+
*
+
+
Usage var st = paper.set();
+ st.push(
+ paper.circle(10, 10, 5),
+ paper.circle(30, 10, 5)
+ );
+ st.attr({fill: "red"}); // changes the fill of both circles
+
+
+*
+ See Paper.setStart . This method finishes catching and returns resulting set.
+*
+
+
Returns: object set
+
+*
+ If you need to change dimensions of the canvas call this method
+*
+
+
Parameters *
+
+
width
+number
+new width of the canvas
+ height
+number
+new height of the canvas
+
+
+*
+ Creates Paper.set . All elements that will be created after calling this method and before calling
+ Paper.setFinish will be added to the set.
+*
+
+
Usage paper.setStart();
+ paper.circle(10, 10, 5),
+ paper.circle(30, 10, 5)
+ var st = paper.setFinish();
+ st.attr({fill: "red"}); // changes the fill of both circles
+
+
+*
+ Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by
+ specifying new boundaries.
+*
+
+
Parameters *
+
+
x
+number
+new x position, default is 0
+ y
+number
+new y position, default is 0
+ w
+number
+new width of the canvas
+ h
+number
+new height of the canvas
+ fit
+boolean
+true
if you want graphics to fit into new boundary box
+
+
+*
+ Shows a hidden paper
+*
+
+
Usage
+
+*
+ Draws a text string. If you need line breaks, put “\n” in the string.
+*
+
+
Parameters *
+
+
x
+number
+x coordinate position
+ y
+number
+y coordinate position
+ text
+string
+The text string to draw
+
+
Returns: object Raphaël element object with type “text”
+
*
+
+
Usage var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!");
+
+
+*
+ Points to the topmost element on the paper
+
+
+*
+ Creates a canvas object on which to draw.
+ You must do this first, as all future calls to drawing methods
+ from this instance will be bound to this canvas.
+
+
Parameters *
+
+
container
+HTMLElement string
+DOM element or its ID which is going to be a parent for drawing surface
+ width
+number
+
+ height
+number
+
+ callback
+optional
+function
+callback function which is going to be executed in the context of newly created paper
+
+
or
+
+
x
+number
+
+ y
+number
+
+ width
+number
+
+ height
+number
+
+ callback
+optional
+function
+callback function which is going to be executed in the context of newly created paper
+
+
or
+
+
all
+array
+(first 3 or 4 elements in the array are equal to [containerID, width, height] or [x, y, width, height]. The rest are element descriptions in format {type: type, <attributes>}). See Paper.add .
+ callback
+optional
+function
+callback function which is going to be executed in the context of newly created paper
+
+
or
+
+
onReadyCallback
+function
+function that is going to be called on DOM ready event. You can also subscribe to this event via Eve’s “DOMLoad” event. In this case method returns undefined
.
+
+
Returns: object Paper
+
Usage // Each of the following examples create a canvas
+ // that is 320px wide by 200px high.
+ // Canvas is created at the viewport’s 10,50 coordinate.
+ var paper = Raphael(10, 50, 320, 200);
+ // Canvas is created at the top left corner of the #notepad element
+ // (or its top right corner in dir="rtl" elements)
+ var paper = Raphael(document.getElementById("notepad"), 320, 200);
+ // Same as above
+ var paper = Raphael("notepad", 320, 200);
+ // Image dump
+ var set = Raphael(["notepad", 320, 200, {
+ type: "rect",
+ x: 10,
+ y: 10,
+ width: 25,
+ height: 25,
+ stroke: "#f00"
+ }, {
+ type: "text",
+ x: 30,
+ y: 40,
+ text: "Dump"
+ }]);
+
+
+*
+ Returns angle between two or three points
+
+
Parameters x1
+number
+x coord of first point
+ y1
+number
+y coord of first point
+ x2
+number
+x coord of second point
+ y2
+number
+y coord of second point
+ x3
+optional
+number
+x coord of third point
+ y3
+optional
+number
+y coord of third point
+
+
Returns: number angle in degrees.
+
+*
+ Creates an animation object that can be passed to the Element.animate or Element.animateWith methods.
+ See also Animation.delay and Animation.repeat methods.
+*
+
+
Parameters *
+
+
params
+object
+final attributes for the element, see also Element.attr
+ ms
+number
+number of milliseconds for animation to run
+ easing
+optional
+string
+easing type. Accept one of Raphael.easing_formulas or CSS format: cubic‐bezier(XX, XX, XX, XX)
+ callback
+optional
+function
+callback function. Will be called at the end of animation.
+
+
*
+
+
Returns: object Animation
+
+*
+ Utility method
+*
+ Return bounding box of a given cubic bezier curve
+
+
Parameters p1x
+number
+x of the first point of the curve
+ p1y
+number
+y of the first point of the curve
+ c1x
+number
+x of the first anchor of the curve
+ c1y
+number
+y of the first anchor of the curve
+ c2x
+number
+x of the second anchor of the curve
+ c2y
+number
+y of the second anchor of the curve
+ p2x
+number
+x of the second point of the curve
+ p2y
+number
+y of the second point of the curve
+
+
or
+
+
bez
+array
+array of six points for bezier curve
+
+
Returns: object point information in format:
+
{ min: {x: number x coordinate of the left point
+y: number y coordinate of the top point
+ } max: {x: number x coordinate of the right point
+y: number y coordinate of the bottom point
+ } }
+
+
+*
+ Returns a recursively cloned version of an object.
+
+
+*
+ Parses the color string and returns object with all values for the given color.
+
+
Parameters clr
+string
+color string in one of the supported formats (see Raphael.getRGB )
+
+
Returns: object Combined RGB & HSB object in format:
+
{r number red,
+g number green,
+b number blue,
+hex string color in HTML/CSS format: #••••••,
+error boolean true
if string can’t be parsed,
+h number hue,
+s number saturation,
+v number value (brightness),
+l number lightness
+ }
+
+*
+ Returns RFC4122, version 4 ID
+
+
Raphael.customAttributes⚓ ➭
+object *
+ If you have a set of attributes that you would like to represent
+ as a function of some number across all papers you can do it
+ easily with custom attributes:
+
+
Usage Raphael.customAttributes.hue = function (num) {
+ num = num % 1;
+ return {fill: "hsb(" + num + ", 0.75, 1)"};
+ };
+ // Custom attribute “hue” will change fill
+ // to be given hue with fixed saturation and brightness.
+ // Now you can use it like this:
+ var c = paper.circle(10, 10, 10).attr({hue: .45});
+ // or even like this:
+ c.animate({hue: 1}, 1e3);
+
+ // You could also create custom attribute
+ // with multiple parameters:
+ Raphael.customAttributes.hsb = function (h, s, b) {
+ return {fill: "hsb(" + [h, s, b].join(",") + ")"};
+ };
+ c.attr({hsb: "0.5 .8 1"});
+ c.animate({hsb: [1, 0, 0.5]}, 1e3);
+
+
+*
+ Allows a unified definition of composite shapes and other behaviours using
+ simple directives.
+*
+
+
Parameters *
+
+
definition
+object
+the shape definition
+
+
+*
+ Transform angle to degrees
+
+
Parameters deg
+number
+angle in radians
+
+
Returns: number angle in degrees.
+
+*
+ Object that contains easing formulas for animation. You could extend it with your own. By default it has following list of easing:
+
+
+ “linear”
+ “<” or “easeIn” or “ease-in”
+ “>” or “easeOut” or “ease-out”
+ “<>” or “easeInOut” or “ease-in-out”
+ “backIn” or “back-in”
+ “backOut” or “back-out”
+ “elastic”
+ “bounce”
+
+
See also Easing demo .
+
+object *
+ You can add your own method to elements. This is usefull when you want to hack default functionality or
+ want to wrap some common transformation or attributes in one method. In difference to canvas methods,
+ you can redefine element method at any time. Expending element methods wouldn’t affect set.
+
+
Usage Raphael.el.red = function () {
+ this.attr({fill: "#f00"});
+ };
+ // then use it
+ paper.circle(100, 100, 20).red();
+
+
Raphael.findDotsAtSegment⚓ ➭
+*
+ Utility method
+*
+ Find dot coordinates on the given cubic bezier curve at the given t.
+
+
Parameters p1x
+number
+x of the first point of the curve
+ p1y
+number
+y of the first point of the curve
+ c1x
+number
+x of the first anchor of the curve
+ c1y
+number
+y of the first anchor of the curve
+ c2x
+number
+x of the second anchor of the curve
+ c2y
+number
+y of the second anchor of the curve
+ p2x
+number
+x of the second point of the curve
+ p2y
+number
+y of the second point of the curve
+ t
+number
+position on the curve (0..1)
+
+
Returns: object point information in format:
+
{x: number x coordinate of the point
+y: number y coordinate of the point
+ m: {x: number x coordinate of the left anchor
+y: number y coordinate of the left anchor
+ } n: {x: number x coordinate of the right anchor
+y: number y coordinate of the right anchor
+ } start: {x: number x coordinate of the start of the curve
+y: number y coordinate of the start of the curve
+ } end: {x: number x coordinate of the end of the curve
+y: number y coordinate of the end of the curve
+ } alpha: number angle of the curve derivative at the point
+ }
+
+object *
+ You can add your own method to the canvas. For example if you want to draw a pie chart,
+ you can create your own pie chart function and ship it as a Raphaël plugin. To do this
+ you need to extend the Raphael.fn
object. You should modify the fn
object before a
+ Raphaël instance is created, otherwise it will take no effect. Please note that the
+ ability for namespaced plugins was removed in Raphael 2.0. It is up to the plugin to
+ ensure any namespacing ensures proper context.
+
+
Usage Raphael.fn.arrow = function (x1, y1, x2, y2, size) {
+ return this.path( ... );
+ };
+ // or create namespace
+ Raphael.fn.mystuff = {
+ arrow: function () {…},
+ star: function () {…},
+ // etc…
+ };
+ var paper = Raphael(10, 10, 630, 480);
+ // then use it
+ paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"});
+ paper.mystuff.arrow();
+ paper.mystuff.star();
+
+
+*
+ Simple format function. Replaces construction of type “{<number>}
” to the corresponding argument.
+*
+
+
Parameters *
+
+
token
+string
+string to format
+ …
+string
+rest of arguments will be treated as parameters for replacement
+
+
Returns: string formated string
+
Usage var x = 10,
+ y = 20,
+ width = 40,
+ height = 50;
+ // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
+ paper.path(Raphael.format("M{0},{1}h{2}v{3}h{4}z", x, y, width, height, -width));
+
+
+*
+ A little bit more advanced format function than Raphael.format . Replaces construction of type “{<name>}
” to the corresponding argument.
+*
+
+
Parameters *
+
+
token
+string
+string to format
+ json
+object
+object which properties will be used as a replacement
+
+
Returns: string formated string
+
Usage // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
+ paper.path(Raphael.fullfill("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
+ x: 10,
+ y: 20,
+ dim: {
+ width: 40,
+ height: 50,
+ "negative width": -40
+ }
+ }));
+
+
+*
+ On each call returns next colour in the spectrum. To reset it back to red call Raphael.getColor.reset
+
+
Parameters value
+optional
+number
+brightness, default is 0.75
+
+
Returns: string hex representation of the colour.
+
+ Raphael.getPointAtLength⚓ ➭
+*
+ Return coordinates of the point located at the given length on the given path.
+*
+
+
Parameters *
+
+
path
+string
+SVG path string
+ length
+number
+
+
+
*
+
+
Returns: object representation of the point:
+
{x: number x coordinate
+y: number y coordinate
+alpha: number angle of derivative
+ }
+
+*
+ Parses colour string as RGB object
+
+
Parameters colour
+string
+colour string in one of formats:
+
+
+ Colour name (“red
”, “green
”, “cornflowerblue
”, etc)
+ #••• — shortened HTML colour: (“#000
”, “#fc0
”, etc)
+ #•••••• — full length HTML colour: (“#000000
”, “#bd2300
”)
+ rgb(•••, •••, •••) — red, green and blue channels’ values: (“rgb(200, 100, 0)
”)
+ rgb(•••%, •••%, •••%) — same as above, but in %: (“rgb(100%, 175%, 0%)
”)
+ hsb(•••, •••, •••) — hue, saturation and brightness values: (“hsb(0.5, 0.25, 1)
”)
+ hsb(•••%, •••%, •••%) — same as above, but in %
+ hsl(•••, •••, •••) — same as hsb
+ hsl(•••%, •••%, •••%) — same as hsb
+
+
Returns: object RGB object in format:
+
{r number red,
+g number green,
+b number blue
+hex string color in HTML/CSS format: #••••••,
+error boolean true if string can’t be parsed
+ }
+
+*
+ Return subpath of a given path from given length to given length.
+*
+
+
Parameters *
+
+
path
+string
+SVG path string
+ from
+number
+position of the start of the segment
+ to
+number
+position of the end of the segment
+
+
*
+
+
Returns: string pathstring for the segment
+
+*
+ Returns length of the given path in pixels.
+*
+
+
Parameters *
+
+
path
+string
+SVG path string.
+
+
*
+
+
Returns: number length.
+
+*
+ Converts HSB values to hex representation of the colour.
+
+
Parameters h
+number
+hue
+ s
+number
+saturation
+ b
+number
+value or brightness
+
+
Returns: string hex representation of the colour.
+
+*
+ Converts HSB values to RGB object.
+
+
Parameters h
+number
+hue
+ s
+number
+saturation
+ v
+number
+value or brightness
+
+
Returns: object RGB object in format:
+
{r number red,
+g number green,
+b number blue,
+hex string color in HTML/CSS format: #••••••
+ }
+
+*
+ Converts HSL values to hex representation of the colour.
+
+
Parameters h
+number
+hue
+ s
+number
+saturation
+ l
+number
+luminosity
+
+
Returns: string hex representation of the colour.
+
+*
+ Converts HSL values to RGB object.
+
+
Parameters h
+number
+hue
+ s
+number
+saturation
+ l
+number
+luminosity
+
+
Returns: object RGB object in format:
+
{r number red,
+g number green,
+b number blue,
+hex string color in HTML/CSS format: #••••••
+ }
+
+*
+ Handfull replacement for typeof
operator.
+
+
Parameters o
+…
+any object or primitive
+ type
+string
+name of the type, i.e. “string”, “function”, “number”, etc.
+
+
Returns: boolean is given value is of given type
+
Raphael.isBBoxIntersect⚓ ➭
+*
+ Utility method
+*
+ Returns true
if two bounding boxes intersect
+
+
Parameters bbox1
+string
+first bounding box
+ bbox2
+string
+second bounding box
+
+
Returns: boolean true
if they intersect
+
Raphael.isPointInsideBBox⚓ ➭
+*
+ Utility method
+*
+ Returns true
if given point is inside bounding boxes.
+
+
Parameters bbox
+string
+bounding box
+ x
+string
+x coordinate of the point
+ y
+string
+y coordinate of the point
+
+
Returns: boolean true
if point inside
+
Raphael.isPointInsidePath⚓ ➭
+*
+ Utility method
+*
+ Returns true
if given point is inside a given closed path.
+
+
Parameters path
+string
+path string
+ x
+number
+x of the point
+ y
+number
+y of the point
+
+
Returns: boolean true, if point is inside the path
+
+*
+ Transform the path string with given matrix.
+
+
Parameters path
+string
+path string
+ matrix
+object
+see Matrix
+
+
Returns: string transformed path string
+
+*
+ Utility method
+*
+ Returns matrix based on given parameters.
+
+
Parameters a
+number
+
+ b
+number
+
+ c
+number
+
+ d
+number
+
+ e
+number
+
+ f
+number
+
+
+
Returns: object Matrix
+
+*
+ If you want to leave no trace of Raphaël (Well, Raphaël creates only one global variable Raphael
, but anyway.) You can use ninja
method.
+ Beware, that in this case plugins could stop working, because they are depending on global variable existance.
+*
+
+
Returns: object Raphael object
+
Usage (function (local_raphael) {
+ var paper = local_raphael(10, 10, 320, 200);
+ …
+ })(Raphael.ninja());
+
+
Raphael.parsePathString⚓ ➭
+*
+ Utility method
+*
+ Parses given path string into an array of arrays of path segments.
+
+
Parameters pathString
+string array
+path string or array of segments (in the last case it will be returned straight away)
+
+
Returns: array array of segments.
+
+*
+ Utility method
+*
+ Parses given path string into an array of transformations.
+
+
Parameters TString
+string array
+transform string or array of transformations (in the last case it will be returned straight away)
+
+
Returns: array array of transformations.
+
+*
+ Utility method
+*
+ Converts path to a new path where all segments are cubic bezier curves.
+
+
Parameters pathString
+string array
+path string or array of segments
+
+
Returns: array array of segments.
+
+*
+ Utility method
+*
+ Return bounding box of a given path
+
+
Parameters path
+string
+path string
+
+
Returns: object bounding box
+
{x: number x coordinate of the left top point of the box
+y: number y coordinate of the left top point of the box
+x2: number x coordinate of the right bottom point of the box
+y2: number y coordinate of the right bottom point of the box
+width: number width of the box
+height: number height of the box
+cx: number x coordinate of the center of the box
+cy: number y coordinate of the center of the box
+ }
+
Raphael.pathIntersection⚓ ➭
+*
+ Utility method
+*
+ Finds intersections of two paths
+
+
Parameters path1
+string
+path string
+ path2
+string
+path string
+
+
Returns: array dots of intersection
+
[ {x: number x coordinate of the point
+y: number y coordinate of the point
+t1: number t value for segment of path1
+t2: number t value for segment of path2
+segment1: number order number for segment of path1
+segment2: number order number for segment of path2
+bez1: array eight coordinates representing beziér curve for the segment of path1
+bez2: array eight coordinates representing beziér curve for the segment of path2
+ } ]
+
+*
+ Utility method
+*
+ Converts path to relative form
+
+
Parameters pathString
+string array
+path string or array of segments
+
+
Returns: array array of segments.
+
+*
+ Returns the first truthy argument.
+
+
+*
+ Transform angle to radians
+
+
Parameters deg
+number
+angle in degrees
+
+
Returns: number angle in radians.
+
+*
+ Adds given font to the registered set of fonts for Raphaël. Should be used as an internal call from within Cufón’s font file.
+ Returns original parameter, so it could be used with chaining.
+
+
More about Cufón and how to convert your font form TTF, OTF, etc to JavaScript file.
+
*
+
+
Parameters *
+
+
font
+object
+the font to register
+
+
Returns: object the font you passed in
+
Usage Cufon.registerFont(Raphael.registerFont({…}));
+
+
+*
+ Converts RGB values to hex representation of the colour.
+
+
Parameters r
+number
+red
+ g
+number
+green
+ b
+number
+blue
+
+
Returns: string hex representation of the colour.
+
+*
+ Converts RGB values to HSB object.
+
+
Parameters r
+number
+red
+ g
+number
+green
+ b
+number
+blue
+
+
Returns: object HSB object in format:
+
{h number hue
+s number saturation
+b number brightness
+ }
+
+*
+ Converts RGB values to HSL object.
+
+
Parameters r
+number
+red
+ g
+number
+green
+ b
+number
+blue
+
+
Returns: object HSL object in format:
+
{h number hue
+s number saturation
+l number luminosity
+ }
+
+*
+ Used when you need to draw in <iframe>
. Switched window to the iframe one.
+
+
Parameters newwin
+window
+new window object
+
+
+*
+ Snaps given value to given grid.
+
+
Parameters values
+array number
+given array of values or step of the grid
+ value
+number
+value to adjust
+ tolerance
+optional
+number
+tolerance for snapping. Default is 10
.
+
+
Returns: number adjusted value.
+
+object *
+ You can add your own method to elements and sets. It is wise to add a set method for each element method
+ you added, so you will be able to call the same method on sets too.
+*
+ See also Raphael.el .
+
+
Usage Raphael.el.red = function () {
+ this.attr({fill: "#f00"});
+ };
+ Raphael.st.red = function () {
+ this.forEach(function (el) {
+ el.red();
+ });
+ };
+ // then use it
+ paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red();
+
+
+boolean *
+ true
if browser supports SVG.
+
+
+*
+ Utility method
+*
+ Returns matrix of transformations applied to a given path
+
+
Parameters path
+string
+path string
+ transform
+string array
+transformation string
+
+
Returns: object Matrix
+
+*
+ Utility method
+*
+ Returns path transformed by a given transformation
+
+
Parameters path
+string
+path string
+ transform
+string array
+transformation string
+
+
Returns: string path
+
+string *
+ Can be “SVG”, “VML” or empty, depending on browser support.
+
+
+boolean *
+ true
if browser supports VML.
+
+
+
+*
+ Removeds all elements from the set
+
+
+*
+ Removes given element from the set
+*
+
+
Parameters *
+
+
element
+object
+element to remove
+
+
Returns: boolean true
if object was found & removed from the set
+
+*
+ Executes given function for each element in the set.
+
+
If function returns false
it will stop loop running.
+*
+
+
Parameters *
+
+
callback
+function
+function to run
+ thisArg
+object
+context object for the callback
+
+
Returns: object Set object
+
+*
+ Removes last element and returns it.
+
+
Returns: object element
+
+*
+ Adds each argument to the current set.
+
+
Returns: object original element
+
+*
+ Removes given element from the set
+*
+
+
Parameters *
+
+
index
+number
+position of the deletion
+ count
+number
+number of element to remove
+ insertion…
+optional
+object
+elements to insert
+
+
Returns: object set elements that were deleted
+
+ Fires event with given name
, given scope and other parameters.
+
+
Arguments name
+string
+name of the event , dot (.
) or slash (/
) separated
+ scope
+object
+context for the event handlers
+ varargs
+...
+the rest of arguments will be sent to event handlers
+
+
Returns: object array of returned values from the listeners
+
+*
+ Returns function that will fire given event with optional arguments.
+ Arguments that will be passed to the result function will be also
+ concated to the list of final arguments.
+
+
el.onclick = eve.f("click", 1, 2);
+ eve.on("click", function (a, b, c) {
+ console.log(a, b, c); // 1, 2, [event object]
+ });
+
+
Arguments event
+string
+event name
+ varargs
+…
+and any other arguments
+
+
Returns: function possible event handler function
+
+ Internal method which gives you array of all event handlers that will be triggered by the given name
.
+
+
Arguments name
+string
+name of the event, dot (.
) or slash (/
) separated
+
+
Returns: array array of event handlers
+
+*
+ Could be used inside event handler to figure out actual name of the event.
+*
+
+
Arguments *
+
+
subname
+optional
+string
+subname of the event
+
+
*
+
+
Returns: string name of the event, if subname
is not specified
+
or
+
+
Returns: boolean true
, if current event’s name contains subname
+
+*
+ Could be used inside event handler to figure out actual name of the event.
+*
+*
+
+
Returns: array names of the event
+
+*
+ Removes given function from the list of event listeners assigned to given name.
+ If no arguments specified all the events will be cleared.
+*
+
+
Arguments *
+
+
name
+string
+name of the event, dot (.
) or slash (/
) separated, with optional wildcards
+ f
+function
+event handler function
+
+
+*
+ Binds given event handler with a given name. You can use wildcards “*
” for the names:
+
+
eve.on("*.under.*", f);
+ eve("mouse.under.floor"); // triggers f
+
+
Use eve to trigger the listener.
+*
+
+
Arguments *
+
+
name
+string
+name of the event, dot (.
) or slash (/
) separated, with optional wildcards
+ f
+function
+event handler function
+
+
*
+
+
Returns: function returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
+
Example: eve.on("mouse", eatIt)(2);
+ eve.on("mouse", scream);
+ eve.on("mouse", catchIt)(1);
+
+
This will ensure that catchIt()
function will be called before eatIt()
.
+
+
If you want to put your handler before non-indexed handlers, specify a negative value.
+ Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
+
+
+*
+ Binds given event handler with a given name to only run once then unbind itself.
+
+
eve.once("login", f);
+ eve("login"); // triggers f
+ eve("login"); // no listeners
+
+
Use eve to trigger the listener.
+*
+
+
Arguments *
+
+
name
+string
+name of the event, dot (.
) or slash (/
) separated, with optional wildcards
+ f
+function
+event handler function
+
+
*
+
+
Returns: function same return function as eve.on
+
+*
+ Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
+
+
+
+string *
+ Current version of the library.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/js/prism.js b/docs/js/prism.js
new file mode 100644
index 0000000..8f1a555
--- /dev/null
+++ b/docs/js/prism.js
@@ -0,0 +1,9 @@
+/**
+ * Prism: Lightweight, robust, elegant syntax highlighting
+ * MIT license http://www.opensource.org/licenses/mit-license.php/
+ * @author Lea Verou http://lea.verou.me
+ */(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&").replace(/e.length)break e;if(p instanceof i)continue;a.lastIndex=0;var d=a.exec(p);if(d){l&&(c=d[1].length);var v=d.index-1+c,d=d[0].slice(c),m=d.length,g=v+m,y=p.slice(0,v+1),b=p.slice(g+1),w=[h,1];y&&w.push(y);var E=new i(u,f?t.tokenize(d,f):d);w.push(E);b&&w.push(b);Array.prototype.splice.apply(s,w)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+""+s.tag+">"};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();;
+Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}}, number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|(&){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};
+;
+Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|throw|catch|finally|null|break|continue)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig,inside:{tag:{pattern:/(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});
+;
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6815a97
--- /dev/null
+++ b/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "redraphael",
+ "filename": "raphael",
+ "version": "1.0.0",
+ "rversion": "2.1.0",
+ "description": "RedRaphael",
+ "main": "index.js",
+ "scripts": {
+ "test": "init"
+ },
+ "repository": "",
+ "author": "FusionCharts",
+ "license": "MIT",
+ "devDependencies": {
+ "grunt-contrib-concat": "~0.3.0",
+ "grunt-contrib-uglify": "~0.2.2",
+ "grunt-contrib-jasmine": "~0.5.2"
+ }
+}
diff --git a/package/raphael-min.js b/package/raphael-min.js
new file mode 100644
index 0000000..dc832d4
--- /dev/null
+++ b/package/raphael-min.js
@@ -0,0 +1,15 @@
+/**!
+ * RedRaphael 1.0.0 - JavaScript Vector Library
+ * Copyright (c) 2012-2013 FusionCharts Technologies
+ *
+ * Raphael 2.1.0
+ * Copyright (c) 2008-2012 Dmitry Baranovskiy
+ * Copyright © 2008-2012 Sencha Labs
+ *
+ * Licensed under the MIT license.
+ */
+!function(a){var b,c,d="0.4.2",e="hasOwnProperty",f=/[\.\/]/,g="*",h=function(){},i=function(a,b){return a-b},j={n:{}},k=function(a,d){a=String(a);var e,f=c,g=Array.prototype.slice.call(arguments,2),h=k.listeners(a),j=0,l=[],m={},n=[],o=b;b=a,c=0;for(var p=0,q=h.length;q>p;p++)"zIndex"in h[p]&&(l.push(h[p].zIndex),h[p].zIndex<0&&(m[h[p].zIndex]=h[p]));for(l.sort(i);l[j]<0;)if(e=m[l[j++]],n.push(e.apply(d,g)),c)return c=f,n;for(p=0;q>p;p++)if(e=h[p],"zIndex"in e)if(e.zIndex==l[j]){if(n.push(e.apply(d,g)),c)break;do if(j++,e=m[l[j]],e&&n.push(e.apply(d,g)),c)break;while(e)}else m[e.zIndex]=e;else if(n.push(e.apply(d,g)),c)break;return c=f,b=o,n.length?n:null};k._events=j,k.listeners=function(a){var b,c,d,e,h,i,k,l,m=a.split(f),n=j,o=[n],p=[];for(e=0,h=m.length;h>e;e++){for(l=[],i=0,k=o.length;k>i;i++)for(n=o[i].n,c=[n[m[e]],n[g]],d=2;d--;)b=c[d],b&&(l.push(b),p=p.concat(b.f||[]));o=l}return p},k.on=function(a,b){if(a=String(a),"function"!=typeof b)return function(){};for(var c=a.split(f),d=j,e=0,g=c.length;g>e;e++)d=d.n,d=d.hasOwnProperty(c[e])&&d[c[e]]||(d[c[e]]={n:{}});for(d.f=d.f||[],e=0,g=d.f.length;g>e;e++)if(d.f[e]==b)return h;return d.f.push(b),function(a){+a==+a&&(b.zIndex=+a)}},k.f=function(a){var b=[].slice.call(arguments,1);return function(){k.apply(null,[a,null].concat(b).concat([].slice.call(arguments,0)))}},k.stop=function(){c=1},k.nt=function(a){return a?new RegExp("(?:\\.|\\/|^)"+a+"(?:\\.|\\/|$)").test(b):b},k.nts=function(){return b.split(f)},k.off=k.unbind=function(a,b){if(!a)return k._events=j={n:{}},void 0;var c,d,h,i,l,m,n,o=a.split(f),p=[j];for(i=0,l=o.length;l>i;i++)for(m=0;mi;i++)for(c=p[i];c.n;){if(b){if(c.f){for(m=0,n=c.f.length;n>m;m++)if(c.f[m]==b){c.f.splice(m,1);break}!c.f.length&&delete c.f}for(d in c.n)if(c.n[e](d)&&c.n[d].f){var q=c.n[d].f;for(m=0,n=q.length;n>m;m++)if(q[m]==b){q.splice(m,1);break}!q.length&&delete c.n[d].f}}else{delete c.f;for(d in c.n)c.n[e](d)&&c.n[d].f&&delete c.n[d].f}c=c.n}},k.once=function(a,b){var c=function(){return k.unbind(a,c),b.apply(this,arguments)};return k.on(a,c)},k.version=d,k.toString=function(){return"You are running Eve "+d},"undefined"!=typeof module&&module.exports?module.exports=k:"undefined"!=typeof define?define("eve",[],function(){return k}):a.eve=k}(this),function(a,b){"function"==typeof define&&define.amd?define(["eve"],function(c){return b(a,c)}):b(a,a.eve)}(this,function(a,b){function c(d){var e,f;return c._url&&(c._url=(c._g&&c._g.win||a).location.href.replace(/#.*?$/,"")),c.is(d,"function")?s?d():b.on("raphael.DOMload",d):c.is(d,B)?c._engine.create[x](c,d.splice(0,3+c.is(d[0],z))).add(d):(e=Array.prototype.slice.call(arguments,0),c.is(e[e.length-1],"function")?(f=e.pop(),s?f.call(c._engine.create[x](c,e)):b.on("raphael.DOMload",function(){f.call(c._engine.create[x](c,e))})):c._engine.create[x](c,arguments))}function d(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function e(){return this.hex}function f(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}function g(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function h(a,b,c,d,e,f,h,i,j){null==j&&(j=1),j=j>1?1:0>j?0:j;for(var k=j/2,l=12,m=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],n=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],o=0,p=0;l>p;p++){var q=k*m[p]+k,r=g(q,a,c,e,h),s=g(q,b,d,f,i),t=r*r+s*s;o+=n[p]*eb(t)}return k*o}function i(a,b,c,d,e,f,g,i,j){if(!(0>j||h(a,b,c,d,e,f,g,i)o;)m/=2,n+=(j>k?1:-1)*m,k=h(a,b,c,d,e,f,g,i,n);return n}}function j(a,b,c,d,e,f,g,h){if(!($(a,c)<_(e,g)||_(a,c)>$(e,g)||$(b,d)<_(f,h)||_(b,d)>$(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(k){var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(!(n<+_(a,c).toFixed(2)||n>+$(a,c).toFixed(2)||n<+_(e,g).toFixed(2)||n>+$(e,g).toFixed(2)||o<+_(b,d).toFixed(2)||o>+$(b,d).toFixed(2)||o<+_(f,h).toFixed(2)||o>+$(f,h).toFixed(2)))return{x:l,y:m}}}}function k(a,b,d){var e=c.bezierBBox(a),f=c.bezierBBox(b);if(!c.isBBoxIntersect(e,f))return d?0:[];for(var g=h.apply(0,a),i=h.apply(0,b),k=$(~~(g/5),1),l=$(~~(i/5),1),m=[],n=[],o={},p=d?0:[],q=0;k+1>q;q++){var r=c.findDotsAtSegment.apply(c,a.concat(q/k));m.push({x:r.x,y:r.y,t:q/k})}for(q=0;l+1>q;q++)r=c.findDotsAtSegment.apply(c,b.concat(q/l)),n.push({x:r.x,y:r.y,t:q/l});for(q=0;k>q;q++)for(var s=0;l>s;s++){var t=m[q],u=m[q+1],v=n[s],w=n[s+1],x=ab(u.x-t.x)<.001?"y":"x",y=ab(w.x-v.x)<.001?"y":"x",z=j(t.x,t.y,u.x,u.y,v.x,v.y,w.x,w.y);if(z){if(o[z.x.toFixed(4)]==z.y.toFixed(4))continue;o[z.x.toFixed(4)]=z.y.toFixed(4);var A=t.t+ab((z[x]-t[x])/(u[x]-t[x]))*(u.t-t.t),B=v.t+ab((z[y]-v[y])/(w[y]-v[y]))*(w.t-v.t);A>=0&&1.001>=A&&B>=0&&1.001>=B&&(d?p++:p.push({x:z.x,y:z.y,t1:_(A,1),t2:_(B,1)}))}}return p}function l(a,b,d){a=c._path2curve(a),b=c._path2curve(b);for(var e,f,g,h,i,j,l,m,n,o,p=d?0:[],q=0,r=a.length;r>q;q++){var s=a[q];if("M"==s[0])e=i=s[1],f=j=s[2];else{"C"==s[0]?(n=[e,f].concat(s.slice(1)),e=n[6],f=n[7]):(n=[e,f,e,f,i,j,i,j],e=i,f=j);for(var t=0,u=b.length;u>t;t++){var v=b[t];if("M"==v[0])g=l=v[1],h=m=v[2];else{"C"==v[0]?(o=[g,h].concat(v.slice(1)),g=o[6],h=o[7]):(o=[g,h,g,h,l,m,l,m],g=l,h=m);var w=k(n,o,d);if(d)p+=w;else{for(var x=0,y=w.length;y>x;x++)w[x].segment1=q,w[x].segment2=t,w[x].bez1=n,w[x].bez2=o;p=p.concat(w)}}}}}return p}function m(a,b,c,d,e,f){null!=a?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function n(){return this.x+v+this.y+v+this.width+" × "+this.height}function o(a,b,c,d,e,f){function g(a){return((l*a+k)*a+j)*a}function h(a,b){var c=i(a,b);return((o*c+n)*c+m)*c}function i(a,b){var c,d,e,f,h,i;for(e=a,i=0;8>i;i++){if(f=g(e)-a,ab(f)e)return c;if(e>d)return d;for(;d>c;){if(f=g(e),ab(f-a)f?c=e:d=e,e=(d-c)/2+c}return e}var j=3*b,k=3*(d-b)-j,l=1-j-k,m=3*c,n=3*(e-c)-m,o=1-m-n;return h(a,1/(200*f))}function p(a,b){var c=[],d={};if(this.ms=b,this.times=1,a){for(var e in a)a[w](e)&&(d[X(e)]=a[e],c.push(X(e)));c.sort(Ab)}this.anim=d,this.top=c[c.length-1],this.percents=c}function q(a,d,e,f,g,h){e=X(e);var i,j,k,l,n,p,q=a.ms,r={},s={},t={};if(f)for(v=0,x=Ec.length;x>v;v++){var u=Ec[v];if(u.el.id==d.id&&u.anim==a){u.percent!=e?(Ec.splice(v,1),k=1):j=u,d.attr(u.totalOrigin);break}}else f=+s;for(var v=0,x=a.percents.length;x>v;v++){if(a.percents[v]==e||a.percents[v]>f*a.top){e=a.percents[v],n=a.percents[v-1]||0,q=q/a.top*(e-n),l=a.percents[v+1],i=a.anim[e];break}f&&d.attr(a.anim[a.percents[v]])}if(i){if(j)j.initstatus=f,j.start=new Date-j.ms*f;else{for(var A in i)if(i[w](A)&&(yb[w](A)||d.ca[A]))switch(r[A]=d.attr(A),null==r[A]&&(r[A]=xb[A]),s[A]=i[A],yb[A]){case z:t[A]=(s[A]-r[A])/q;break;case"colour":r[A]=c.getRGB(r[A]);var B=c.getRGB(s[A]);t[A]={r:(B.r-r[A].r)/q,g:(B.g-r[A].g)/q,b:(B.b-r[A].b)/q};break;case"path":var C=cc(r[A],s[A]),D=C[1];for(r[A]=C[0],t[A]=[],v=0,x=r[A].length;x>v;v++){t[A][v]=[0];for(var F=1,G=r[A][v].length;G>F;F++)t[A][v][F]=(D[v][F]-r[A][v][F])/q}break;case"transform":var H=d._,I=hc(H[A],s[A]);if(I)for(r[A]=I.from,s[A]=I.to,t[A]=[],t[A].real=!0,v=0,x=r[A].length;x>v;v++)for(t[A][v]=[r[A][v][0]],F=1,G=r[A][v].length;G>F;F++)t[A][v][F]=(s[A][v][F]-r[A][v][F])/q;else{var J=d.matrix||new m,K={_:{transform:H.transform},getBBox:function(){return d.getBBox(1)}};r[A]=[J.a,J.b,J.c,J.d,J.e,J.f],fc(K,s[A]),s[A]=K._.transform,t[A]=[(K.matrix.a-J.a)/q,(K.matrix.b-J.b)/q,(K.matrix.c-J.c)/q,(K.matrix.d-J.d)/q,(K.matrix.e-J.e)/q,(K.matrix.f-J.f)/q]}break;case"csv":var L=W(i[A])[E](mb),M=W(r[A])[E](mb);if("clip-rect"==A)for(r[A]=M,t[A]=[],v=M.length;v--;)t[A][v]=(L[v]-r[A][v])/q;s[A]=L;break;default:for(L=[][y](i[A]),M=[][y](r[A]),t[A]=[],v=d.ca[A].length;v--;)t[A][v]=((L[v]||0)-(M[v]||0))/q}var N=i.easing,O=c.easing_formulas[N];if(!O)if(O=W(N).match(pb),O&&5==O.length){var P=O;O=function(a){return o(a,+P[1],+P[2],+P[3],+P[4],q)}}else O=Cb;if(p=i.start||a.start||+new Date,u={anim:a,percent:e,timestamp:p,start:p+(a.del||0),status:0,initstatus:f||0,stop:!1,ms:q,easing:O,from:r,diff:t,to:s,el:d,callback:i.callback,prev:n,next:l,repeat:h||a.times,origin:d.attr(),totalOrigin:g},Ec.push(u),f&&!j&&!k&&(u.stop=!0,u.start=new Date-q*f,1==Ec.length))return Gc();k&&(u.start=new Date-u.ms*f),1==Ec.length&&Fc(Gc)}b("raphael.anim.start."+d.id,d,a)}}function r(a){for(var b=0;be;e++)for(i=a[e],f=1,h=i.length;h>f;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d;return a},Hb=(c.pick=function(){for(var a,b=0,c=arguments.length;c>b;b+=1)if(a=arguments[b],a||a===!1||0===a)return a;return t},c._lastArgIfGroup=function(a,b){var d=a.length-1,e=a[d];return e&&e.constructor===c.el.constructor&&"group"===e.type?(b&&K.call(a,d,1),e):void 0}),Ib=c.merge=function(a,b,c,d,e){var f,g,h,i,j;if(e?(d.push(a),e.push(b)):(d=[a],e=[b]),b instanceof Array)for(f=0;f ',Lb=Mb.firstChild,Lb.style.behavior="url(#default#VML)",!Lb||typeof Lb.adj!=C)return c.type=u;Mb=null}c.svg=!((c.vml="VML"==c.type)||(c.canvas="CANVAS"==c.type)),c._Paper=R,c._id=0,c._oid=0,c.angle=function(a,b,d,e,f,g){if(null==f){var h=a-d,i=b-e;return h||i?(180+Z.atan2(-i,-h)*ib+360)%360:0}return c.angle(a,b,f,g)-c.angle(d,e,f,g)},c.rad=function(a){return a%360*hb},c.deg=function(a){return a*ib%360},c.snapTo=function(a,b,c){var d,e;if(Jb(c,D)||(c=10),Jb(a,B)){for(e=a.length;e--;)if(ab(a[e]-b)<=c)return a[e]}else{if(a=+a,d=b%a,c>d)return b-d;if(d>a-c)return b-d+a}return b},c.setWindow=function(a){b("raphael.setWindow",c,L.win,a),O=L.win=a,N=L.doc=L.win.document,c._engine.initWin&&c._engine.initWin(L.win)};var Nb=function(a){if(c.vml){var b,d=/^\s+|\s+$/g;try{var e=new ActiveXObject("htmlfile");e.write(""),e.close(),b=e.body}catch(f){b=createPopup().document.body}var g=b.createTextRange();Nb=Tb(function(a){try{b.style.color=W(a).replace(d,u);var c=g.queryCommandValue("ForeColor");return c=(255&c)<<16|65280&c|(16711680&c)>>>16,"#"+("000000"+c.toString(16)).slice(-6)}catch(e){return F}})}else{var h=L.doc.createElement("i");h.title="Raphaël Colour Picker",h.style.display=F,L.doc.body.appendChild(h),Nb=Tb(function(a){return h.style.color=a,L.doc.defaultView.getComputedStyle(h,u).getPropertyValue("color")})}return Nb(a)},Ob=function(){return"hsb("+[this.h,this.s,this.b]+")"},Pb=function(){return"hsl("+[this.h,this.s,this.l]+")"},Qb=function(){return this.hex},Rb=function(a,b,d){if(null==b&&Jb(a,C)&&"r"in a&&"g"in a&&"b"in a&&(d=a.b,b=a.g,a=a.r),null==b&&Jb(a,A)){var e=c.getRGB(a);a=e.r,b=e.g,d=e.b}return(a>1||b>1||d>1)&&(a/=255,b/=255,d/=255),[a,b,d]},Sb=function(a,b,d,e){var f={r:a*=255,g:b*=255,b:d*=255,hex:c.rgb(a,b,d),toString:Qb};return Jb(e,"finite")&&(f.opacity=e),f};c.color=function(a){var b;return c.is(a,C)&&"h"in a&&"s"in a&&"b"in a?(b=c.hsb2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.hex=b.hex):c.is(a,C)&&"h"in a&&"s"in a&&"l"in a?(b=c.hsl2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.hex=b.hex):(c.is(a,"string")&&(a=c.getRGB(a)),c.is(a,C)&&"r"in a&&"g"in a&&"b"in a?(b=c.rgb2hsl(a),a.h=b.h,a.s=b.s,a.l=b.l,b=c.rgb2hsb(a),a.v=b.b):(a={hex:F},a.r=a.g=a.b=a.h=a.s=a.v=a.l=-1)),a.toString=Qb,a},c.hsb2rgb=function(a,b,c,d){this.is(a,C)&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,a=a.h,d=a.o),a*=360;var e,f,g,h,i;return a=a%360/60,i=c*b,h=i*(1-ab(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a],Sb(e,f,g,d)},c.hsl2rgb=function(a,b,c,d){this.is(a,C)&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h),(a>1||b>1||c>1)&&(a/=360,b/=100,c/=100),a*=360;var e,f,g,h,i;return a=a%360/60,i=2*b*(.5>c?c:1-c),h=i*(1-ab(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a],Sb(e,f,g,d)},c.rgb2hsb=function(a,b,c){c=Rb(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;return f=$(a,b,c),g=f-_(a,b,c),d=0==g?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=60*((d+360)%6)/360,e=0==g?0:g/f,{h:d,s:e,b:f,toString:Ob}},c.rgb2hsl=function(a,b,c){c=Rb(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;return g=$(a,b,c),h=_(a,b,c),i=g-h,d=0==i?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=60*((d+360)%6)/360,f=(g+h)/2,e=0==i?0:.5>f?i/(2*f):i/(2-2*f),{h:d,s:e,l:f,toString:Pb}},c._path2string=function(){return this.join(",").replace(rb,"$1")};var Tb=c._cacher=function(a,b,c){function e(){var f=J.call(arguments,0),g=f.join("␀"),h=e.cache=e.cache||{},i=e.count=e.count||[];return h[w](g)?(d(i,g),c?c(h[g]):h[g]):(i.length>=1e3&&delete h[i.shift()],i.push(g),h[g]=a[x](b,f),c?c(h[g]):h[g])}return e};c._preload=function(a,b){var c=N.createElement("img");c.style.cssText="position:absolute;left:-9999em;top:-9999em",c.onload=function(){b.call(this),this.onload=null,N.body.removeChild(this)},c.onerror=function(){N.body.removeChild(this)},N.body.appendChild(c),c.src=a},c.getRGB=Tb(function(a){var b,d,f,g,h,i,j;return a&&Jb(a,"object")&&"opacity"in a&&(b=a.opacity),!a||(a=W(a)).indexOf("-")+1?{r:-1,g:-1,b:-1,hex:F,error:1,toString:e}:a==F?{r:-1,g:-1,b:-1,hex:F,toString:e}:(!(wb[w](a.toLowerCase().substring(0,2))||"#"===a.charAt())&&(a=Nb(a)),(j=a.match(ob))?(j[2]&&(g=Y(j[2].substring(5),16),f=Y(j[2].substring(3,5),16),d=Y(j[2].substring(1,3),16)),j[3]&&(g=Y((h=j[3].charAt(3))+h,16),f=Y((h=j[3].charAt(2))+h,16),d=Y((h=j[3].charAt(1))+h,16)),j[4]&&(i=j[4][E](qb),d=X(i[0]),"%"==i[0].slice(-1)&&(d*=2.55),f=X(i[1]),"%"==i[1].slice(-1)&&(f*=2.55),g=X(i[2]),"%"==i[2].slice(-1)&&(g*=2.55),"rgba"==j[1].toLowerCase().slice(0,4)&&(b=X(i[3])),i[3]&&"%"==i[3].slice(-1)&&(b/=100)),j[5]?(i=j[5][E](qb),d=X(i[0]),"%"==i[0].slice(-1)&&(d*=2.55),f=X(i[1]),"%"==i[1].slice(-1)&&(f*=2.55),g=X(i[2]),"%"==i[2].slice(-1)&&(g*=2.55),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(d/=360),"hsba"==j[1].toLowerCase().slice(0,4)&&(b=X(i[3])),i[3]&&"%"==i[3].slice(-1)&&(b/=100),c.hsb2rgb(d,f,g,b)):j[6]?(i=j[6][E](qb),d=X(i[0]),"%"==i[0].slice(-1)&&(d*=2.55),f=X(i[1]),"%"==i[1].slice(-1)&&(f*=2.55),g=X(i[2]),"%"==i[2].slice(-1)&&(g*=2.55),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(d/=360),"hsla"==j[1].toLowerCase().slice(0,4)&&(b=X(i[3])),i[3]&&"%"==i[3].slice(-1)&&(b/=100),c.hsl2rgb(d,f,g,b)):(j={r:d,g:f,b:g,toString:e},j.hex="#"+(16777216|g|f<<8|d<<16).toString(16).slice(1),c.is(b,"finite")&&(j.opacity=b),j)):{r:-1,g:-1,b:-1,hex:F,error:1,toString:e})},c),c.tintshade=Tb(function(a,b){var d,f=c.getRGB(a),g=255;return 0>b&&(b*=-1,g=0),b>1&&(b=1),d=0===b?f:{r:g-(g-f.r)*b,g:g-(g-f.g)*b,b:g-(g-f.b)*b,toString:e},d.hex=c.rgb(d.r,d.g,d.b),f.error&&(d.error=f.error),"opacity"in f?(d.rgba="rgba("+[d.r,d.g,d.b,f.opacity].join(",")+")",d.opacity=f.opacity):d.rgba="rgb("+[d.r,d.g,d.b].join(",")+")",d},c),c.hsb=Tb(function(a,b,d){return c.hsb2rgb(a,b,d).hex}),c.hsl=Tb(function(a,b,d){return c.hsl2rgb(a,b,d).hex}),c.rgb=Tb(function(a,b,c){return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),c.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);return b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b})),c.hex},c.getColor.reset=function(){delete this.start},c.parsePathString=function(a){if(!a)return null;var b=Ub(a);if(b.arr)return Wb(b.arr);var d={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},e=[];return c.is(a,B)&&c.is(a[0],B)&&(e=Wb(a)),e.length||W(a).replace(sb,function(a,b,c){var f=[],g=b.toLowerCase();if(c.replace(ub,function(a,b){b&&f.push(+b)}),"m"==g&&f.length>2&&(e.push([b][y](f.splice(0,2))),g="l",b="m"==b?"l":"L"),"r"==g)e.push([b][y](f));else for(;f.length>=d[g]&&(e.push([b][y](f.splice(0,d[g]))),d[g]););}),e.toString=c._path2string,b.arr=Wb(e),e},c.parseTransformString=Tb(function(a){if(!a)return null;var b=[];return c.is(a,B)&&c.is(a[0],B)&&(b=Wb(a)),b.length||W(a).replace(tb,function(a,c,d){var e=[];jb.call(c),d.replace(ub,function(a,b){b&&e.push(+b)}),b.push([c][y](e))}),b.toString=c._path2string,b});var Ub=function(a){var b=Ub.ps=Ub.ps||{};return b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[w](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])}),b[a]};c.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=bb(j,3),l=bb(j,2),m=i*i,n=m*i,o=k*a+3*l*i*c+3*j*i*i*e+n*g,p=k*b+3*l*i*d+3*j*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,w=j*e+i*g,x=j*f+i*h,y=90-180*Z.atan2(q-s,r-t)/gb;return(q>s||t>r)&&(y+=180),{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:w,y:x},alpha:y}},c.bezierBBox=function(a,b,d,e,f,g,h,i){c.is(a,"array")||(a=[a,b,d,e,f,g,h,i]);var j=bc.apply(null,a);return{x:j.min.x,y:j.min.y,x2:j.max.x,y2:j.max.y,width:j.max.x-j.min.x,height:j.max.y-j.min.y}},c.isPointInsideBBox=function(a,b,c){return b>=a.x&&b<=a.x2&&c>=a.y&&c<=a.y2},c.isBBoxIntersect=function(a,b){var d=c.isPointInsideBBox;return d(b,a.x,a.y)||d(b,a.x2,a.y)||d(b,a.x,a.y2)||d(b,a.x2,a.y2)||d(a,b.x,b.y)||d(a,b.x2,b.y)||d(a,b.x,b.y2)||d(a,b.x2,b.y2)||(a.xb.x||b.xa.x)&&(a.yb.y||b.ya.y)},c.pathIntersection=function(a,b){return l(a,b)},c.pathIntersectionNumber=function(a,b){return l(a,b,1)},c.isPointInsidePath=function(a,b,d){var e=c.pathBBox(a);return c.isPointInsideBBox(e,b,d)&&(1==l(a,[["M",b,d],["H",e.x2+10]],1)%2||1==l(a,[["M",b,d],["V",e.y2+10]],1)%2)},c._removedFactory=function(a){return function(){b("raphael.log",null,"Raphaël: you are calling to method “"+a+"” of removed object",a)}};var Vb=c.pathBBox=function(a){var b=Ub(a);if(b.bbox)return b.bbox;if(!a)return{x:0,y:0,width:0,height:0,x2:0,y2:0};a=cc(a);for(var c,d=0,e=0,f=[],g=[],h=0,i=a.length;i>h;h++)if(c=a[h],"M"==c[0])d=c[1],e=c[2],f.push(d),g.push(e);else{var j=bc(d,e,c[1],c[2],c[3],c[4],c[5],c[6]);f=f[y](j.min.x,j.max.x),g=g[y](j.min.y,j.max.y),d=c[5],e=c[6]}var k=_[x](0,f),l=_[x](0,g),m=$[x](0,f),n=$[x](0,g),o={x:k,y:l,x2:m,y2:n,width:m-k,height:n-l};return b.bbox=Kb(o),o},Wb=function(a){var b=Kb(a);return b.toString=c._path2string,b},Xb=c._pathToRelative=function(a){var b=Ub(a);if(b.rel)return Wb(b.rel);c.is(a,B)&&c.is(a&&a[0],B)||(a=c.parsePathString(a));var d=[],e=0,f=0,g=0,h=0,i=0;"M"==a[0][0]&&(e=a[0][1],f=a[0][2],g=e,h=f,i++,d.push(["M",e,f]));for(var j=i,k=a.length;k>j;j++){var l=d[j]=[],m=a[j];if(m[0]!=jb.call(m[0]))switch(l[0]=jb.call(m[0]),l[0]){case"a":l[1]=m[1],l[2]=m[2],l[3]=m[3],l[4]=m[4],l[5]=m[5],l[6]=+(m[6]-e).toFixed(3),l[7]=+(m[7]-f).toFixed(3);break;case"v":l[1]=+(m[1]-f).toFixed(3);break;case"m":g=m[1],h=m[2];default:for(var n=1,o=m.length;o>n;n++)l[n]=+(m[n]-(n%2?e:f)).toFixed(3)}else{l=d[j]=[],"m"==m[0]&&(g=m[1]+e,h=m[2]+f);for(var p=0,q=m.length;q>p;p++)d[j][p]=m[p]}var r=d[j].length;switch(d[j][0]){case"z":e=g,f=h;break;case"h":e+=+d[j][r-1];break;case"v":f+=+d[j][r-1];break;default:e+=+d[j][r-2],f+=+d[j][r-1]}}return d.toString=c._path2string,b.rel=Wb(d),d},Yb=c._pathToAbsolute=function(a){var b,d=Ub(a);if(d.abs)return Wb(d.abs);if(c.is(a,B)&&c.is(a&&a[0],B)||(a=c.parsePathString(a)),!a||!a.length)return b=["M",0,0],b.toString=c._path2string,b;var e=0,g=0,h=0,i=0,j=0;b=[],"M"==a[0][0]&&(e=+a[0][1],g=+a[0][2],h=e,i=g,j++,b[0]=["M",e,g]);for(var k,l,m=3==a.length&&"M"==a[0][0]&&"R"==a[1][0].toUpperCase()&&"Z"==a[2][0].toUpperCase(),n=j,o=a.length;o>n;n++){if(b.push(k=[]),l=a[n],l[0]!=kb.call(l[0]))switch(k[0]=kb.call(l[0]),k[0]){case"A":k[1]=l[1],k[2]=l[2],k[3]=l[3],k[4]=l[4],k[5]=l[5],k[6]=+(l[6]+e),k[7]=+(l[7]+g);break;case"V":k[1]=+l[1]+g;break;case"H":k[1]=+l[1]+e;break;case"R":for(var p=[e,g][y](l.slice(1)),q=2,r=p.length;r>q;q++)p[q]=+p[q]+e,p[++q]=+p[q]+g;b.pop(),b=b[y](f(p,m));break;case"M":h=+l[1]+e,i=+l[2]+g;default:for(q=1,r=l.length;r>q;q++)k[q]=+l[q]+(q%2?e:g)}else if("R"==l[0])p=[e,g][y](l.slice(1)),b.pop(),b=b[y](f(p,m)),k=["R"][y](l.slice(-2));else for(var s=0,t=l.length;t>s;s++)k[s]=l[s];switch(k[0]){case"Z":e=h,g=i;break;case"H":e=k[1];break;case"V":g=k[1];break;case"M":h=k[k.length-2],i=k[k.length-1];default:e=k[k.length-2],g=k[k.length-1]}}return b.toString=c._path2string,d.abs=Wb(b),b},Zb=function(a,b,c,d){return[a,b,c,d,c,d]},$b=function(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]},_b=function(a,b,c,d,e,f,g,h,i,j){var k,l=120*gb/180,m=hb*(+e||0),n=[],o=Tb(function(a,b,c){var d=a*cb(c)-b*db(c),e=a*db(c)+b*cb(c);return{x:d,y:e}});if(j)x=j[0],z=j[1],v=j[2],w=j[3];else{k=o(a,b,-m),a=k.x,b=k.y,k=o(h,i,-m),h=k.x,i=k.y;var p=(cb(hb*e),db(hb*e),(a-h)/2),q=(b-i)/2,r=p*p/(c*c)+q*q/(d*d);r>1&&(r=eb(r),c=r*c,d=r*d);var s=c*c,t=d*d,u=(f==g?-1:1)*eb(ab((s*t-s*q*q-t*p*p)/(s*q*q+t*p*p))),v=u*c*q/d+(a+h)/2,w=u*-d*p/c+(b+i)/2,x=Z.asin(((b-w)/d).toFixed(9)),z=Z.asin(((i-w)/d).toFixed(9));x=v>a?gb-x:x,z=v>h?gb-z:z,0>x&&(x=2*gb+x),0>z&&(z=2*gb+z),g&&x>z&&(x-=2*gb),!g&&z>x&&(z-=2*gb)}var A=z-x;if(ab(A)>l){var B=z,C=h,D=i;z=x+l*(g&&z>x?1:-1),h=v+c*cb(z),i=w+d*db(z),n=_b(h,i,c,d,e,0,g,C,D,[z,B,v,w])}A=z-x;var F=cb(x),G=db(x),H=cb(z),I=db(z),J=Z.tan(A/4),K=4/3*c*J,L=4/3*d*J,M=[a,b],N=[a+K*G,b-L*F],O=[h+K*I,i-L*H],P=[h,i];if(N[0]=2*M[0]-N[0],N[1]=2*M[1]-N[1],j)return[N,O,P][y](n);n=[N,O,P][y](n).join()[E](",");for(var Q=[],R=0,S=n.length;S>R;R++)Q[R]=R%2?o(n[R-1],n[R],m).y:o(n[R],n[R+1],m).x;return Q},ac=function(a,b,c,d,e,f,g,h,i){var j=1-i;return{x:bb(j,3)*a+3*bb(j,2)*i*c+3*j*i*i*e+bb(i,3)*g,y:bb(j,3)*b+3*bb(j,2)*i*d+3*j*i*i*f+bb(i,3)*h}},bc=Tb(function(a,b,c,d,e,f,g,h){var i,j=e-2*c+a-(g-2*e+c),k=2*(c-a)-2*(e-c),l=a-c,m=(-k+eb(k*k-4*j*l))/2/j,n=(-k-eb(k*k-4*j*l))/2/j,o=[b,h],p=[a,g];return ab(m)>"1e12"&&(m=.5),ab(n)>"1e12"&&(n=.5),m>0&&1>m&&(i=ac(a,b,c,d,e,f,g,h,m),p.push(i.x),o.push(i.y)),n>0&&1>n&&(i=ac(a,b,c,d,e,f,g,h,n),p.push(i.x),o.push(i.y)),j=f-2*d+b-(h-2*f+d),k=2*(d-b)-2*(f-d),l=b-d,m=(-k+eb(k*k-4*j*l))/2/j,n=(-k-eb(k*k-4*j*l))/2/j,ab(m)>"1e12"&&(m=.5),ab(n)>"1e12"&&(n=.5),m>0&&1>m&&(i=ac(a,b,c,d,e,f,g,h,m),p.push(i.x),o.push(i.y)),n>0&&1>n&&(i=ac(a,b,c,d,e,f,g,h,n),p.push(i.x),o.push(i.y)),{min:{x:_[x](0,p),y:_[x](0,o)},max:{x:$[x](0,p),y:$[x](0,o)}}}),cc=c._path2curve=Tb(function(a,b){var c=!b&&Ub(a);if(!b&&c.curve)return Wb(c.curve);for(var d=Yb(a),e=b&&Yb(b),f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},h=(function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];switch(!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null),a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][y](_b[x](0,[b.x,b.y][y](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=["C",c,d][y](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=["C"][y]($b(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][y]($b(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][y](Zb(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][y](Zb(b.x,b.y,a[1],b.y));break;case"V":a=["C"][y](Zb(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][y](Zb(b.x,b.y,b.X,b.Y))}return a}),i=function(a,b){if(a[b].length>7){a[b].shift();for(var c=a[b];c.length;)a.splice(b++,0,["C"][y](c.splice(0,6)));a.splice(b,1),l=$(d.length,e&&e.length||0)}},j=function(a,b,c,f,g){a&&b&&"M"==a[g][0]&&"M"!=b[g][0]&&(b.splice(g,0,["M",f.x,f.y]),c.bx=0,c.by=0,c.x=a[g][1],c.y=a[g][2],l=$(d.length,e&&e.length||0))},k=0,l=$(d.length,e&&e.length||0);l>k;k++){d[k]=h(d[k],f),i(d,k),e&&(e[k]=h(e[k],g)),e&&i(e,k),j(d,e,f,g,k),j(e,d,g,f,k);var m=d[k],n=e&&e[k],o=m.length,p=e&&n.length;f.x=m[o-2],f.y=m[o-1],f.bx=X(m[o-4])||f.x,f.by=X(m[o-3])||f.y,g.bx=e&&(X(n[p-4])||g.x),g.by=e&&(X(n[p-3])||g.y),g.x=e&&n[p-2],g.y=e&&n[p-1]}return e||(c.curve=Wb(d)),e?[d,e]:d},null,Wb),dc=(c._parseDots=Tb(function(a){for(var b=[],d=0,e=a.length;e>d;d++){var f={},g=a[d].match(/^([^:]*):?([\d\.]*)/);if(f.color=c.getRGB(g[1]),f.color.error)return null;f.opacity=f.color.opacity,f.color=f.color.hex,g[2]&&(f.offset=g[2]+"%"),b.push(f)}for(d=1,e=b.length-1;e>d;d++)if(!b[d].offset){for(var h=X(b[d-1].offset||0),i=0,j=d+1;e>j;j++)if(b[j].offset){i=b[j].offset;break}i||(i=100,j=e),i=X(i);for(var k=(i-h)/(j-d+1);j>d;d++)h+=k,b[d].offset=h+"%"}return b}),c._tear=function(a,b){a==b.top&&(b.top=a.prev),a==b.bottom&&(b.bottom=a.next),a.next&&(a.next.prev=a.prev),a.prev&&(a.prev.next=a.next)}),ec=(c._tofront=function(a,b){return b.top===a?!1:(dc(a,b),a.next=null,a.prev=b.top,b.top.next=a,b.top=a,!0)},c._toback=function(a,b){return b.bottom===a?!1:(dc(a,b),a.next=b.bottom,a.prev=null,b.bottom.prev=a,b.bottom=a,!0)},c._insertafter=function(a,b,c,d){dc(a,c),a.parent=d,b===d.top&&(d.top=a),b.next&&(b.next.prev=a),a.next=b.next,a.prev=b,b.next=a},c._insertbefore=function(a,b,c,d){dc(a,c),a.parent=d,b===d.bottom&&(d.bottom=a),b.prev&&(b.prev.next=a),a.prev=b.prev,b.prev=a,a.next=b},c.toMatrix=function(a,b){var c=Vb(a),d={_:{transform:u},getBBox:function(){return c}};return fc(d,b),d.matrix}),fc=(c.transformPath=function(a,b){return Gb(a,ec(a,b))},c._extractTransform=function(a,b){if(null==b)return a._.transform;
+b=W(b).replace(/\.{3}|\u2026/g,a._.transform||u);var d=c.parseTransformString(b),e=0,f=0,g=0,h=1,i=1,j=a._,k=new m;if(j.transform=d||[],d)for(var l=0,n=d.length;n>l;l++){var o,p,q,r,s,t=d[l],v=t.length,w=W(t[0]).toLowerCase(),x=t[0]!=w,y=x?k.invert():0;"t"==w&&3==v?x?(o=y.x(0,0),p=y.y(0,0),q=y.x(t[1],t[2]),r=y.y(t[1],t[2]),k.translate(q-o,r-p)):k.translate(t[1],t[2]):"r"==w?2==v?(s=s||a.getBBox(1),k.rotate(t[1],s.x+s.width/2,s.y+s.height/2),e+=t[1]):4==v&&(x?(q=y.x(t[2],t[3]),r=y.y(t[2],t[3]),k.rotate(t[1],q,r)):k.rotate(t[1],t[2],t[3]),e+=t[1]):"s"==w?2==v||3==v?(s=s||a.getBBox(1),k.scale(t[1],t[v-1],s.x+s.width/2,s.y+s.height/2),h*=t[1],i*=t[v-1]):5==v&&(x?(q=y.x(t[3],t[4]),r=y.y(t[3],t[4]),k.scale(t[1],t[2],q,r)):k.scale(t[1],t[2],t[3],t[4]),h*=t[1],i*=t[2]):"m"==w&&7==v&&k.add(t[1],t[2],t[3],t[4],t[5],t[6]),j.dirtyT=1,a.matrix=k}a.matrix=k,j.sx=h,j.sy=i,j.deg=e,j.dx=f=k.e,j.dy=g=k.f,1==h&&1==i&&!e&&j.bbox?(j.bbox.x+=+f,j.bbox.y+=+g):j.dirtyT=1}),gc=function(a){var b=a[0];switch(b.toLowerCase()){case"t":return[b,0,0];case"m":return[b,1,0,0,1,0,0];case"r":return 4==a.length?[b,0,a[2],a[3]]:[b,0];case"s":return 5==a.length?[b,1,1,a[3],a[4]]:3==a.length?[b,1,1]:[b,1]}},hc=c._equaliseTransform=function(a,b){b=W(b).replace(/\.{3}|\u2026/g,a),a=c.parseTransformString(a)||[],b=c.parseTransformString(b)||[];for(var d,e,f,g,h=$(a.length,b.length),i=[],j=[],k=0;h>k;k++){if(f=a[k]||gc(b[k]),g=b[k]||gc(f),f[0]!=g[0]||"r"==f[0].toLowerCase()&&(f[2]!=g[2]||f[3]!=g[3])||"s"==f[0].toLowerCase()&&(f[3]!=g[3]||f[4]!=g[4]))return;for(i[k]=[],j[k]=[],d=0,e=$(f.length,g.length);e>d;d++)d in f&&(i[k][d]=f[d]),d in g&&(j[k][d]=g[d])}return{from:i,to:j}};c._getContainer=function(a,b,d,e){var f;return f=null!=e||c.is(a,C)?a:L.doc.getElementById(a),null!=f?f.tagName?null==b?{container:f,width:f.style.pixelWidth||f.offsetWidth,height:f.style.pixelHeight||f.offsetHeight}:{container:f,width:b,height:d}:{container:1,x:a,y:b,width:d,height:e}:void 0},c.pathToRelative=Xb,c._engine={},c.path2curve=cc,c.matrix=function(a,b,c,d,e,f){return new m(a,b,c,d,e,f)},function(a){function b(a){return a[0]*a[0]+a[1]*a[1]}function d(a){var c=eb(b(a));a[0]&&(a[0]/=c),a[1]&&(a[1]/=c)}a.add=function(a,b,c,d,e,f){var g,h,i,j,k=[[],[],[]],l=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],n=[[a,c,e],[b,d,f],[0,0,1]];for(a&&a instanceof m&&(n=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]),g=0;3>g;g++)for(h=0;3>h;h++){for(j=0,i=0;3>i;i++)j+=l[g][i]*n[i][h];k[g][h]=j}this.a=k[0][0],this.b=k[1][0],this.c=k[0][1],this.d=k[1][1],this.e=k[0][2],this.f=k[1][2]},a.invert=function(){var a=this,b=a.a*a.d-a.b*a.c;return new m(a.d/b,-a.b/b,-a.c/b,a.a/b,(a.c*a.f-a.d*a.e)/b,(a.b*a.e-a.a*a.f)/b)},a.clone=function(){return new m(this.a,this.b,this.c,this.d,this.e,this.f)},a.translate=function(a,b){this.add(1,0,0,1,a,b)},a.scale=function(a,b,c,d){null==b&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d)},a.rotate=function(a,b,d){a=c.rad(a),b=b||0,d=d||0;var e=+cb(a).toFixed(9),f=+db(a).toFixed(9);this.add(e,f,-f,e,b,d),this.add(1,0,0,1,-b,-d)},a.x=function(a,b){return a*this.a+b*this.c+this.e},a.y=function(a,b){return a*this.b+b*this.d+this.f},a.get=function(a){return+this[W.fromCharCode(97+a)].toFixed(4)},a.toString=function(){return c.svg?"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")":[this.get(0),this.get(2),this.get(1),this.get(3),0,0].join()},a.toMatrixString=function(){return"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")"},a.toFilter=function(){return"progid:DXImageTransform.Microsoft.Matrix(M11="+this.get(0)+", M12="+this.get(2)+", M21="+this.get(1)+", M22="+this.get(3)+", Dx="+this.get(4)+", Dy="+this.get(5)+", sizingmethod='auto expand')"},a.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},a.split=function(){var a={};a.dx=this.e,a.dy=this.f;var e=[[this.a,this.c],[this.b,this.d]];a.scalex=eb(b(e[0])),d(e[0]),a.shear=e[0][0]*e[1][0]+e[0][1]*e[1][1],e[1]=[e[1][0]-e[0][0]*a.shear,e[1][1]-e[0][1]*a.shear],a.scaley=eb(b(e[1])),d(e[1]),a.shear/=a.scaley;var f=-e[0][1],g=e[1][1];return 0>g?(a.rotate=c.deg(Z.acos(g)),0>f&&(a.rotate=360-a.rotate)):a.rotate=c.deg(Z.asin(f)),a.isSimple=!(+a.shear.toFixed(9)||a.scalex.toFixed(9)!=a.scaley.toFixed(9)&&a.rotate),a.isSuperSimple=!+a.shear.toFixed(9)&&a.scalex.toFixed(9)==a.scaley.toFixed(9)&&!a.rotate,a.noRotation=!+a.shear.toFixed(9)&&!a.rotate,a},a.toTransformString=function(a){var b=a||this[E]();return b.isSimple?(b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4),(b.dx||b.dy?"t"+[b.dx,b.dy]:u)+(1!=b.scalex||1!=b.scaley?"s"+[b.scalex,b.scaley,0,0]:u)+(b.rotate?"r"+[b.rotate,0,0]:u)):"m"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]}}(m.prototype);var ic=navigator.userAgent.match(/Version\/(.*?)\s/)||navigator.userAgent.match(/Chrome\/(\d+)/);S.safari="Apple Computer, Inc."==navigator.vendor&&(ic&&ic[1]<4||"iP"==navigator.platform.slice(0,2))||"Google Inc."==navigator.vendor&&ic&&ic[1]<8?function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:"none"});return setTimeout(function(){a.remove()}),!0}:Bb;for(var jc=function(){this.returnValue=!1},kc=function(){return this.originalEvent.preventDefault()},lc=function(){this.cancelBubble=!0},mc=function(){return this.originalEvent.stopPropagation()},nc=c.addEvent=function(){return L.doc.addEventListener?function(a,b,c,d){var e=P&&V[b]?V[b]:b,f=function(e){var f=L.doc.documentElement.scrollTop||L.doc.body.scrollTop,g=L.doc.documentElement.scrollLeft||L.doc.body.scrollLeft;if(P&&V[w](b))for(var h=0,i=e.targetTouches&&e.targetTouches.length;i>h;h++)if(e.targetTouches[h].target==a){var j=e;e=e.targetTouches[h],e.originalEvent=j,e.preventDefault=kc,e.stopPropagation=mc;break}return c.call(d,e,e.clientX+g,e.clientY+f)};return a.addEventListener(e,f,!1),function(){return a.removeEventListener(e,f,!1),!0}}:L.doc.attachEvent?function(a,b,c,d){var e=function(a){a=a||L.win.event;var b=L.doc.documentElement.scrollTop||L.doc.body.scrollTop,e=L.doc.documentElement.scrollLeft||L.doc.body.scrollLeft,f=a.clientX+e,g=a.clientY+b;return a.preventDefault=a.preventDefault||jc,a.stopPropagation=a.stopPropagation||lc,c.call(d,a,f,g)};a.attachEvent("on"+b,e);var f=function(){return a.detachEvent("on"+b,e),!0};return f}:void 0}(),oc=[],pc=function(a){for(var c,d=a.clientX,e=a.clientY,f=L.doc.documentElement.scrollTop||L.doc.body.scrollTop,g=L.doc.documentElement.scrollLeft||L.doc.body.scrollLeft,h=oc.length;h--;){if(c=oc[h],P){for(var i,j=a.touches.length;j--;)if(i=a.touches[j],i.identifier==c.el._drag.id){d=i.clientX,e=i.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}else a.preventDefault();var k,l=c.el.node,m=l.nextSibling,n=l.parentNode,o=l.style.display;L.win.opera&&n.removeChild(l),l.style.display="none",k=c.el.paper.getElementByPoint(d,e),l.style.display=o,L.win.opera&&(m?n.insertBefore(l,m):n.appendChild(l)),k&&b("raphael.drag.over."+c.el.id,c.el,k),d+=g,e+=f,b("raphael.drag.move."+c.el.id,c.move_scope||c.el,d-c.el._drag.x,e-c.el._drag.y,d,e,a)}},qc=function(a){c.unmousemove(pc).unmouseup(qc);for(var d,e=oc.length;e--;)d=oc[e],d.el._drag={},b("raphael.drag.end."+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,a);oc=[]},rc=c.el={},sc=U.length;sc--;)!function(a){c[a]=rc[a]=function(b,d){return c.is(b,"function")&&(this.events=this.events||[],this.events.push({name:a,f:b,unbind:nc(this.shape||this.node||L.doc,a,b,d||this)})),this},c["un"+a]=rc["un"+a]=function(b){for(var c=this.events||[],d=c.length;d--;)if(c[d].name==a&&c[d].f==b)return c[d].unbind(),c.splice(d,1),!c.length&&delete this.events,this;return this}}(U[sc]);rc.data=function(a,d){var e=zb[this.id]=zb[this.id]||{};if(1==arguments.length){if(c.is(a,C)){for(var f in a)a[w](f)&&this.data(f,a[f]);return this}return b("raphael.data.get."+this.id,this,e[a],a),e[a]}return e[a]=d,b("raphael.data.set."+this.id,this,d,a),this},rc.removeData=function(a){return null==a?zb[this.id]={}:zb[this.id]&&delete zb[this.id][a],this},rc.getData=function(){return Kb(zb[this.id]||{})};var tc=[],uc=function(){this.untrack=nc(L.doc,"mouseup",vc,this)},vc=function(){return this.untrack(),this.untrack=null,this.fn&&this.fn.apply(this.scope||this.el,arguments)};rc.mouseup=function(a,b,d){return d?(tc.push(d={el:this,fn:a,scope:b}),d.unbind=nc(this.shape||this.node||L.doc,"mousedown",uc,d),this):c.mouseup.apply(this,arguments)},rc.unmouseup=function(a){for(var b,d=tc.length;d--;)tc[d].el===this&&tc[d].fn===a&&(b=tc[d],b.unbind(),b.untrack&&b.untrack(),tc.splice(d,1));return b?this:c.unmouseup.apply(this,arguments)},rc.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},rc.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var wc=[];rc.drag=function(a,d,e,f,g,h){function i(i){(i.originalEvent||i).preventDefault();var j=L.doc.documentElement.scrollTop||L.doc.body.scrollTop,k=L.doc.documentElement.scrollLeft||L.doc.body.scrollLeft;this._drag.x=i.clientX+k,this._drag.y=i.clientY+j,this._drag.id=i.identifier,!oc.length&&c.mousemove(pc).mouseup(qc),oc.push({el:this,move_scope:f,start_scope:g,end_scope:h}),d&&b.on("raphael.drag.start."+this.id,d),a&&b.on("raphael.drag.move."+this.id,a),e&&b.on("raphael.drag.end."+this.id,e),b("raphael.drag.start."+this.id,g||f||this,i.clientX+k,i.clientY+j,i)}return this._drag={},wc.push({el:this,start:i}),this.mousedown(i),this},rc.onDragOver=function(a){a?b.on("raphael.drag.over."+this.id,a):b.unbind("raphael.drag.over."+this.id)},rc.undrag=function(){for(var a=wc.length;a--;)wc[a].el==this&&(this.unmousedown(wc[a].start),wc.splice(a,1),b.unbind("raphael.drag.*."+this.id));!wc.length&&c.unmousemove(pc).unmouseup(qc)},rc.follow=function(a,b,d){return a.removed||a.constructor!==c.el.constructor?this:(a.followers.push({el:this,stalk:d={before:"insertBefore",after:"insertAfter"}[d],cb:b}),d&&this[d](a),this)},rc.unfollow=function(a){if(a.removed||a.constructor!==c.el.constructor)return this;for(var b=0,d=a.followers.length;d>b;b++)if(a.followers[b].el===this){a.followers.splice(b,1);break}return this},S.hide=function(){var a=this;return a.canvas.style.visibility="hidden",a},S.show=function(){var a=this;return a.canvas.style.visibility=u,a},S.group=function(){var a,b=this,d=arguments,e=Hb(d,!0);return a=c._engine.group(b,d[0],e),b.__set__&&b.__set__.push(a),a},S.circle=function(){var a,b=this,d=arguments,e=Hb(d,!0);return a=c._engine.circle(b,d[0]||0,d[1]||0,d[2]||0,e),b.__set__&&b.__set__.push(a),a},S.rect=function(){var a,b=this,d=arguments,e=Hb(d,!0);return a=c._engine.rect(b,d[0]||0,d[1]||0,d[2]||0,d[3]||0,d[4]||0,e),b.__set__&&b.__set__.push(a),a},S.ellipse=function(){var a,b=this,d=arguments,e=Hb(d,!0);return a=c._engine.ellipse(this,d[0]||0,d[1]||0,d[2]||0,d[3]||0,e),b.__set__&&b.__set__.push(a),a},S.path=function(){var a,b,d=this,e=arguments,f=Hb(e,!0);return a=e[0],a&&!c.is(a,A)&&!c.is(a[0],B)&&(a+=u),b=c._engine.path(c.format[x](c,arguments),d,f),d.__set__&&d.__set__.push(b),b},S.image=function(){var a,b=this,d=arguments,e=Hb(d,!0);return a=c._engine.image(b,d[0]||"about:blank",d[1]||0,d[2]||0,d[3]||0,d[4]||0,e),b.__set__&&b.__set__.push(a),a},S.text=function(){var a,b=this,d=arguments,e=Hb(d,!0);return a=c._engine.text(b,d[0]||0,d[1]||0,W(d[2]||u),e),b.__set__&&b.__set__.push(a),a},S.set=function(a){!c.is(a,"array")&&(a=K.call(arguments,0,arguments.length));var b=new Ic(a);return this.__set__&&this.__set__.push(b),b},S.setStart=function(a){this.__set__=a||this.set()},S.setFinish=function(){var a=this.__set__;return delete this.__set__,a},S.setSize=function(a,b){return c._engine.setSize.call(this,a,b)},S.setViewBox=function(a,b,d,e,f){return c._engine.setViewBox.call(this,a,b,d,e,f)},S.top=S.bottom=null,S.raphael=c;var xc=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,g=e.clientLeft||d.clientLeft||0,h=b.top+(L.win.pageYOffset||e.scrollTop||d.scrollTop)-f,i=b.left+(L.win.pageXOffset||e.scrollLeft||d.scrollLeft)-g;return{y:h,x:i}};S.getElementByPoint=function(a,b){var c=this,d=c.canvas,e=L.doc.elementFromPoint(a,b);if(L.win.opera&&"svg"==e.tagName){var f=xc(d),g=d.createSVGRect();g.x=a-f.x,g.y=b-f.y,g.width=g.height=1;var h=d.getIntersectionList(g,null);h.length&&(e=h[h.length-1])}if(!e)return null;for(;e.parentNode&&e!=d.parentNode&&!e.raphael;)e=e.parentNode;return e==c.canvas.parentNode&&(e=d),e=e&&e.raphael?c.getById(e.raphaelid):null},S.getElementsByBBox=function(a){var b=this.set();return this.forEach(function(d){c.isBBoxIntersect(d.getBBox(),a)&&b.push(d)}),b},S.getById=function(a){for(var b=this.bottom;b;){if(b.id==a)return b;b=b.next}return null},S.forEach=function(a,b){for(var c=this.bottom;c;){if(a.call(b,c)===!1)return this;c=c.next}return this},S.getElementsByPoint=function(a,b){var c=this.set();return this.forEach(function(d){d.isPointInside(a,b)&&c.push(d)}),c},rc.isPointInside=function(a,b){var d,e=this.realPath=this.realPath||Fb[this.type](this);return c.isPointInsidePath((d=this.attr("transform"))&&d.length&&c.transformPath(e,d)||e,a,b)},rc.getBBox=function(a){if(this.removed)return{};var b=this._;return a?((b.dirty||!b.bboxwt)&&(this.realPath=Fb[this.type](this),b.bboxwt=Vb(this.realPath),b.bboxwt.toString=n,b.dirty=0),b.bboxwt):((b.dirty||b.dirtyT||!b.bbox)&&((b.dirty||!this.realPath)&&(b.bboxwt=0,this.realPath=Fb[this.type](this)),b.bbox=Vb(Gb(this.realPath,this.matrix)),b.bbox.toString=n,b.dirty=b.dirtyT=0),b.bbox)},rc.clone=function(){if(this.removed)return null;var a=this,b=a.paper[a.type]().attr(a.attr());return a.__set__&&a.__set__.push(b),b},rc.glow=function(a){if("text"==this.type)return null;a=a||{};var b={width:(a.width||10)+(+this.attr("stroke-width")||1),fill:a.fill||!1,opacity:a.opacity||.5,offsetx:a.offsetx||0,offsety:a.offsety||0,color:a.color||"#000"},c=b.width/2,d=this.paper,e=d.set(),f=this.realPath||Fb[this.type](this);f=this.matrix?Gb(f,this.matrix):f;for(var g=1;c+1>g;g++)e.push(d.path(f).attr({stroke:b.color,fill:b.fill?b.color:"none","stroke-linejoin":"round","stroke-linecap":"round","stroke-width":+(b.width/c*g).toFixed(3),opacity:+(b.opacity/c).toFixed(3)}));return e.insertBefore(this).translate(b.offsetx,b.offsety)};var yc=function(a,b,d,e,f,g,j,k,l){return null==l?h(a,b,d,e,f,g,j,k):c.findDotsAtSegment(a,b,d,e,f,g,j,k,i(a,b,d,e,f,g,j,k,l))},zc=function(a,b){return function(d,e,f){d=cc(d);for(var g,h,i,j,k,l="",m={},n=0,o=0,p=d.length;p>o;o++){if(i=d[o],"M"==i[0])g=+i[1],h=+i[2];else{if(j=yc(g,h,i[1],i[2],i[3],i[4],i[5],i[6]),n+j>e){if(b&&!m.start){if(k=yc(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),l+=["C"+k.start.x,k.start.y,k.m.x,k.m.y,k.x,k.y],f)return l;m.start=l,l=["M"+k.x,k.y+"C"+k.n.x,k.n.y,k.end.x,k.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!a&&!b)return k=yc(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),{x:k.x,y:k.y,alpha:k.alpha}}n+=j,g=+i[5],h=+i[6]}l+=i.shift()+i}return m.end=l,k=a?n:b?m:c.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),k.alpha&&(k={x:k.x,y:k.y,alpha:k.alpha}),k}},Ac=zc(1),Bc=zc(),Cc=zc(0,1);c.getTotalLength=Ac,c.getPointAtLength=Bc,c.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return Cc(a,b).end;var d=Cc(a,c,1);return b?Cc(d,b).end:d},rc.getTotalLength=function(){return"path"==this.type?this.node.getTotalLength?this.node.getTotalLength():Ac(this.attrs.path):void 0},rc.getPointAtLength=function(a){return"path"==this.type?Bc(this.attrs.path,a):void 0},rc.getSubpath=function(a,b){return"path"==this.type?c.getSubpath(this.attrs.path,a,b):void 0};var Dc=c.easing_formulas={linear:function(a){return a},"<":function(a){return bb(a,1.7)},">":function(a){return bb(a,.48)},"<>":function(a){var b=.48-a/1.04,c=eb(.1734+b*b),d=c-b,e=bb(ab(d),1/3)*(0>d?-1:1),f=-c-b,g=bb(ab(f),1/3)*(0>f?-1:1),h=e+g+.5;return 3*(1-h)*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a-=1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){return a==!!a?a:bb(2,-10*a)*db((a-.075)*2*gb/.3)+1},bounce:function(a){var b,c=7.5625,d=2.75;return 1/d>a?b=c*a*a:2/d>a?(a-=1.5/d,b=c*a*a+.75):2.5/d>a?(a-=2.25/d,b=c*a*a+.9375):(a-=2.625/d,b=c*a*a+.984375),b}};Dc.easeIn=Dc["ease-in"]=Dc["<"],Dc.easeOut=Dc["ease-out"]=Dc[">"],Dc.easeInOut=Dc["ease-in-out"]=Dc["<>"],Dc["back-in"]=Dc.backIn,Dc["back-out"]=Dc.backOut;var Ec=[],Fc=a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(a){setTimeout(a,16)},Gc=function(){for(var a=+new Date,d=0;dh))if(i>h){var r=j(h/i);for(var s in k)if(k[w](s)){switch(yb[s]){case z:f=+k[s]+r*i*l[s];break;case"colour":f="rgb("+[Hc(fb(k[s].r+r*i*l[s].r)),Hc(fb(k[s].g+r*i*l[s].g)),Hc(fb(k[s].b+r*i*l[s].b))].join(",")+")";break;case"path":f=[];for(var t=0,u=k[s].length;u>t;t++){f[t]=[k[s][t][0]];for(var x=1,A=k[s][t].length;A>x;x++)f[t][x]=(+k[s][t][x]+r*i*l[s][t][x]).toFixed(4);f[t]=f[t].join(v)}f=f.join(v);break;case"transform":if(l[s].real)for(f=[],t=0,u=k[s].length;u>t;t++)for(f[t]=[k[s][t][0]],x=1,A=k[s][t].length;A>x;x++)f[t][x]=k[s][t][x]+r*i*l[s][t][x];else{var B=function(a){return+k[s][a]+r*i*l[s][a]};f=[["m",B(0),B(1),B(2),B(3),B(4),B(5)]]}break;case"csv":if("clip-rect"==s)for(f=[],t=4;t--;)f[t]=+k[s][t]+r*i*l[s][t];break;default:var C=[][y](k[s]);for(f=[],t=n.ca[s].length;t--;)f[t]=+C[t]+r*i*l[s][t]}o[s]=f}n.attr(o),function(a,c,d){setTimeout(function(){b("raphael.anim.frame."+a,c,d)})}(n.id,n,e.anim)}else{if(function(a,d,e){setTimeout(function(){b("raphael.anim.frame."+d.id,d,e),b("raphael.anim.finish."+d.id,d,e),c.is(a,"function")&&a.call(d)})}(e.callback,n,e.anim),n.attr(m),Ec.splice(d--,1),e.repeat>1&&!e.next){for(g in m)m[w](g)&&(p[g]=e.totalOrigin[g]);e.el.attr(p),q(e.anim,e.el,e.anim.percents[0],null,e.totalOrigin,e.repeat-1)}e.next&&!e.stop&&q(e.anim,e.el,e.next,null,e.totalOrigin,e.repeat)}}}c.svg&&n&&n.paper&&n.paper.safari(),Ec.length&&Fc(Gc)},Hc=function(a){return a>255?255:0>a?0:a};rc.animateWith=function(a,b,d,e,f,g){var h=this;if(h.removed)return g&&g.call(h),h;var i=d instanceof p?d:c.animation(d,e,f,g);q(i,h,i.percents[0],null,h.attr());for(var j=0,k=Ec.length;k>j;j++)if(Ec[j].anim==b&&Ec[j].el==a){Ec[k-1].start=Ec[j].start;break}return h},rc.onAnimation=function(a){return a?b.on("raphael.anim.frame."+this.id,a):b.unbind("raphael.anim.frame."+this.id),this},p.prototype.delay=function(a){var b=new p(this.anim,this.ms);return b.times=this.times,b.del=+a||0,b},p.prototype.repeat=function(a){var b=new p(this.anim,this.ms);return b.del=this.del,b.times=Z.floor($(a,0))||1,b},c.animation=function(a,b,d,e){if(a instanceof p)return a;(c.is(d,"function")||!d)&&(e=e||d||null,d=null),a=Object(a),b=+b||0;var f,g,h={};for(g in a)a[w](g)&&X(g)!=g&&X(g)+"%"!=g&&(f=!0,h[g]=a[g]);return f?(d&&(h.easing=d),e&&(h.callback=e),new p({100:h},b)):new p(a,b)},rc.animate=function(a,b,d,e){var f=this;if(f.removed)return e&&e.call(f),f;var g=a instanceof p?a:c.animation(a,b,d,e);return q(g,f,g.percents[0],null,f.attr()),f},rc.setTime=function(a,b){return a&&null!=b&&this.status(a,_(b,a.ms)/a.ms),this},rc.status=function(a,b){var c,d,e=[],f=0;if(null!=b)return q(a,this,-1,_(b,1)),this;for(c=Ec.length;c>f;f++)if(d=Ec[f],d.el.id==this.id&&(!a||d.anim==a)){if(a)return d.status;e.push({anim:d.anim,status:d.status})}return a?0:e},rc.pause=function(a){for(var c=0;cb;b++)(a=h[b]).stalk&&a.el[a.stalk](e);return e},rc.toBack=function(){if(this.removed)return this;var a,b,d,e=this,f=c._engine.getNode(e),g=e.parent,h=e.followers;for(c._toback(e,g)&&g.canvas.insertBefore(f,g.canvas.firstChild),b=0,d=h.length;d>b;b++)(a=h[b]).stalk&&a.el[a.stalk](e);return e},rc.insertAfter=function(a){if(this.removed)return this;var b,d,e,f=this,g=c._engine.getNode(f),h=c._engine.getLastNode(a),i=a.parent.canvas,j=f.followers;for(h.nextSibling?i.insertBefore(g,h.nextSibling):i.appendChild(g),c._insertafter(f,a,f.parent,a.parent),d=0,e=j.length;e>d;d++)(b=j[d]).stalk&&b.el[b.stalk](a);return f},rc.insertBefore=function(a){if(this.removed)return this;var b,d,e,f=this,g=c._engine.getNode(f),h=c._engine.getNode(a),i=f.followers;for(a.parent.canvas.insertBefore(g,h),c._insertbefore(f,a,f.parent,a.parent),f.parent=a.parent,d=0,e=i.length;e>d;d++)(b=i[d]).stalk&&b.el[b.stalk](a);return this},rc.appendChild=function(a){if(this.removed||"group"!==this.type)return this;var b,d,e,f,g=this,h=g.followers;if(a.parent===g)return a.toFront(),g;for(d=c._engine.getNode(a),c._tear(a,a.parent),g.canvas.appendChild(d),a.parent=g,!g.bottom&&(g.bottom=a),a.prev=g.top,a.next=null,g.top&&(g.top.next=a),g.top=a,e=0,f=h.length;f>e;e++)(b=h[e]).stalk&&b.el[b.stalk](a);return g},rc.removeChild=function(a){if(this.removed||"group"!==this.type||a.parent!==this)return this;var b=this,d=c._engine.getNode(a),e=b.paper;return c._tear(a,b),e.canvas.appendChild(d),b.parent=e,!e.bottom&&(e.bottom=b),b.prev=e.top,e.top&&(e.top.next=b),e.top=b,b.next=null,b};var Ic=function(a){if(this.items=[],this.length=0,this.type="set",a)for(var b=0,c=a.length;c>b;b++)!a[b]||a[b].constructor!=rc.constructor&&a[b].constructor!=Ic||(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},Jc=Ic.prototype;Jc.push=function(){for(var a,b,c=0,d=arguments.length;d>c;c++)a=arguments[c],!a||a.constructor!=rc.constructor&&a.constructor!=Ic||(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},Jc.pop=function(){return this.length&&delete this[this.length--],this.items.pop()},Jc.forEach=function(a,b){for(var c=0,d=this.items.length;d>c;c++)if(a.call(b,this.items[c],c)===!1)return this;return this};for(var Kc in rc)rc[w](Kc)&&(Jc[Kc]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a][x](c,b)})}}(Kc));Jc.attr=function(a,b){if(a&&c.is(a,B)&&c.is(a[0],C))for(var d=0,e=a.length;e>d;d++)this.items[d].attr(a[d]);else for(var f=0,g=this.items.length;g>f;f++)this.items[f].attr(a,b);return this},Jc.clear=function(){for(;this.length;)this.pop()},Jc.splice=function(a,b){a=0>a?$(this.length+a,0):a,b=$(0,_(this.length-a,isNaN(b)&&this.length||b));var c,d=[],e=[],f=[];for(c=2;cc;c++)e.push(this[a+c]);for(;cc?f[c]:d[c-g];for(c=this.items.length=this.length-=b-g;this[c];)delete this[c++];return new Ic(e)},Jc.exclude=function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]==a)return this.splice(b,1),!0},Jc.animate=function(a,b,d,e){(c.is(d,"function")||!d)&&(e=d||null);var f,g,h=this.items.length,i=h,j=this;if(!h)return this;e&&(g=function(){!--h&&e.call(j)}),d=c.is(d,A)?d:g;var k=c.animation(a,b,d,g);for(f=this.items[--i].animate(k);i--;)this.items[i]&&!this.items[i].removed&&this.items[i].animateWith(f,k,k);return this},Jc.insertAfter=function(a){for(var b=this.items.length;b--;)this.items[b].insertAfter(a);return this},Jc.getBBox=function(){for(var a=[],b=[],c=[],d=[],e=this.items.length;e--;)if(!this.items[e].removed){var f=this.items[e].getBBox();a.push(f.x),b.push(f.y),c.push(f.x+f.width),d.push(f.y+f.height)}return a=_[x](0,a),b=_[x](0,b),c=$[x](0,c),d=$[x](0,d),{x:a,y:b,x2:c,y2:d,width:c-a,height:d-b}},Jc.clone=function(a){a=new Ic;for(var b=0,c=this.items.length;c>b;b++)a.push(this.items[b].clone());return a},Jc.toString=function(){return"Raphaël‘s set"},Jc.glow=function(a){var b=this.paper.set();return this.forEach(function(c){var d=c.glow(a);null!=d&&d.forEach(function(a){b.push(a)})}),b},c.registerFont=function(a){if(!a.face)return a;this.fonts=this.fonts||{};var b={w:a.w,face:{},glyphs:{}},c=a.face["font-family"];for(var d in a.face)a.face[w](d)&&(b.face[d]=a.face[d]);if(this.fonts[c]?this.fonts[c].push(b):this.fonts[c]=[b],!a.svg){b.face["units-per-em"]=Y(a.face["units-per-em"],10);for(var e in a.glyphs)if(a.glyphs[w](e)){var f=a.glyphs[e];if(b.glyphs[e]={w:f.w,k:{},d:f.d&&"M"+f.d.replace(/[mlcxtrv]/g,function(a){return{l:"L",c:"C",x:"z",t:"m",r:"l",v:"c"}[a]||"M"})+"z"},f.k)for(var g in f.k)f[w](g)&&(b.glyphs[e].k[g]=f.k[g])}}return a},S.getFont=function(a,b,d,e){if(e=e||"normal",d=d||"normal",b=+b||{normal:400,bold:700,lighter:300,bolder:800}[b]||400,c.fonts){var f=c.fonts[a];if(!f){var g=new RegExp("(^|\\s)"+a.replace(/[^\w\d\s+!~.:_-]/g,u)+"(\\s|$)","i");for(var h in c.fonts)if(c.fonts[w](h)&&g.test(h)){f=c.fonts[h];break}}var i;if(f)for(var j=0,k=f.length;k>j&&(i=f[j],i.face["font-weight"]!=b||i.face["font-style"]!=d&&i.face["font-style"]||i.face["font-stretch"]!=e);j++);return i}},S.print=function(a,b,d,e,f,g,h){g=g||"middle",h=$(_(h||0,1),-1);var i,j=W(d)[E](u),k=0,l=0,m=u;if(c.is(e,d)&&(e=this.getFont(e)),e){i=(f||16)/e.face["units-per-em"];for(var n=e.face.bbox[E](mb),o=+n[0],p=n[3]-n[1],q=0,r=+n[1]+("baseline"==g?p+ +e.face.descent:p/2),s=0,t=j.length;t>s;s++){if("\n"==j[s])k=0,w=0,l=0,q+=p;else{var v=l&&e.glyphs[j[s-1]]||{},w=e.glyphs[j[s]];k+=l?(v.w||e.w)+(v.k&&v.k[j[s]]||0)+e.w*h:0,l=1}w&&w.d&&(m+=c.transformPath(w.d,["t",k*i,q*i,"s",i,i,o,r,"t",(a-o)/i,(b-r)/i]))}}return this.path(m).attr({fill:"#000",stroke:"none"})},S.add=function(a){if(c.is(a,"array"))for(var b,d=this.set(),e=0,f=a.length;f>e;e++)b=a[e]||{},T[w](b.type)&&d.push(this[b.type]().attr(b));return d},c.format=function(a,b){var d=c.is(b,B)?[0][y](b):arguments;return a&&c.is(a,A)&&d.length-1&&(a=a.replace(nb,function(a,b){return null==d[++b]?u:d[b]})),a||u},c.fullfill=function(){var a=/\{([^\}]+)\}/g,b=/(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g,c=function(a,c,d){var e=d;return c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),"function"==typeof e&&f&&(e=e()))}),e=(null==e||e==d?a:e)+""};return function(b,d){return String(b).replace(a,function(a,b){return c(a,b,d)})}}(),c.ninja=function(){return M.was?L.win.Raphael=M.is:delete Raphael,c};var Lc=c.vml&&.5||0;return c.crispBound=Tb(function(a,b,c,d,e){var f,g={};return a=a||0,b=b||0,c=c||0,d=d||0,e=e||0,f=e%2/2+Lc,g.x=fb(a+f)-f,g.y=fb(b+f)-f,g.width=fb(a+c+f)-f-g.x,g.height=fb(b+d+f)-f-g.y,g["stroke-width"]=e,0===g.width&&0!==c&&(g.width=1),0===g.height&&0!==d&&(g.height=1),g},c),rc.crisp=function(){var a,b=this,d=b.attrs,e=b.attr(["x","y","width","height","stroke-width"]);e=c.crispBound(e.x,e.y,e.width,e.height,e["stroke-width"]);for(a in e)d[a]===e[a]&&delete e[a];return b.attr(e)},c.st=Jc,c.define=function(a,b,d,e,f){var g,h;if(c.is(a,B))for(g=0,h=a.length;h>g;g++)c.define(a[g]);else{if(c.is(a,C))return c.define(a.name,a[a.name],a.ca,a.fn,a.e),void 0;if(a&&!c.fn[a])return c.fn[a]=function(){var g,h=arguments,i=b.apply(this,h);if(e&&c.is(e,C))for(g in e)i[g]=e[g];if(f&&c.is(f,C))for(g in f)i[g]&&i[g](f[g]);if(d){if(c.is(d,"function"))i.ca[a]=d;else for(g in d)i.ca[g]=d[g];i.ca[a]&&(c._lastArgIfGroup(h,!0),i.attr(a,J.call(h)))}return i},d&&(c.fn[a].ca=d),e&&(c.fn[a].fn=e),f&&(c.fn[a].e=f),c.fn[a]}},function(a,b,d){function e(){/in/.test(a.readyState)?setTimeout(e,9):c.eve("raphael.DOMload")}null==a.readyState&&a.addEventListener&&(a.addEventListener(b,d=function(){a.removeEventListener(b,d,!1),a.readyState="complete"},!1),a.readyState="loading"),e()}(document,"DOMContentLoaded"),b.on("raphael.DOMload",function(){s=!0}),function(){if(c.svg){var b="hasOwnProperty",d=String,e=parseFloat,f=parseInt,g=Math,h=g.max,i=g.abs,j=g.pow,k=g.sqrt,l=/[, ]+/,m=!(!/AppleWebKit/.test(c._g.win.navigator.userAgent)||/Chrome/.test(c._g.win.navigator.userAgent)&&!(c._g.win.navigator.appVersion.match(/Chrome\/(\d+)\./)[1]<29)),n=c.eve,o="",p=" ",q="http://www.w3.org/1999/xlink",r={block:"M5,0 0,2.5 5,5z",classic:"M5,0 0,2.5 5,5 3.5,3 3.5,2z",diamond:"M2.5,0 5,2.5 2.5,5 0,2.5z",open:"M6,1 1,3.5 6,6",oval:"M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"},s={},t=function(){return c._url=c._g.win.location.href.replace(/#.*?$/,o)};c.toString=function(){return"Your browser supports SVG.\nYou are running Raphaël "+this.version},c._url=/msie/i.test(navigator.userAgent)&&!a.opera?o:t(),c._url&&c._g.win.history.pushState&&(c._g.win.history.pushState=function(){var a=c._g.win.history.pushState;return function(){var b=a.apply(c._g.win.history,arguments);return t(),b}}(),c._g.win.addEventListener("popstate",t,!1));var u=c._createNode=function(a,e){if(e){"string"==typeof a&&(a=u(a));for(var f in e)e[b](f)&&("xlink:"==f.substring(0,6)?a.setAttributeNS(q,f.substring(6),d(e[f])):a.setAttribute(f,d(e[f])))}else a=c._g.doc.createElementNS("http://www.w3.org/2000/svg",a);return a},v={userSpaceOnUse:"userSpaceOnUse",objectBoundingBox:"objectBoundingBox"},w={pad:"pad",redlect:"reflect",repeat:"repeat"},x=function(a,b){var f,l,m,n,p,q="linear",r=a.id+b,s=.5,t=.5,x=a.node,y=a.paper,z=x.style,A=c._g.doc.getElementById(r);if(!A&&y.defs){if(b=d(b).replace(c._radial_gradient,function(a,b){q="radial",b=b&&b.split(",")||[],n=b[5],p=b[6];var c,d,g=b[0],h=b[1],i=b[2],r=b[3],u=b[4],w=g&&h;return i&&(f=/\%/.test(i)?i:e(i)),n===v.userSpaceOnUse?(w&&(s=g,t=h),r&&u&&(l=r,m=u,w||(s=l,t=m)),o):(w&&(s=e(g),t=e(h),c=2*(t>.5)-1,(d=j(s-.5,2))+j(t-.5,2)>.25&&.25>d&&(t=k(.25-d)*c+.5)&&.5!==t&&(t=t.toFixed(5)-1e-5*c)),r&&u&&(l=e(r),m=e(u),c=2*(m>.5)-1,(d=j(l-.5,2))+j(m-.5,2)>.25&&.25>d&&(m=k(.25-d)*c+.5)&&.5!==m&&(m=m.toFixed(5)-1e-5*c),w||(s=l,t=m)),o)}),b=b.split(/\s*\-\s*/),"linear"==q){var B,C,D=b.shift(),E=D.match(/\((.*)\)/);if(E=E&&E[1]&&E[1].split(/\s*\,\s*/),D=-e(D),isNaN(D))return null;E&&E.length?(E[0]in v?(n=E.shift(),E[0]in w&&(p=E.shift())):(E[4]&&(n=E[4]),E[5]&&(p=E[5])),B=[E[0]||"0%",E[1]||"0%",E[2]||"100%",E[3]||"0%"]):(B=[0,0,g.cos(c.rad(D)),g.sin(c.rad(D))],C=1/(h(i(B[2]),i(B[3]))||1),B[2]*=C,B[3]*=C,B[2]<0&&(B[0]=-B[2],B[2]=0),B[3]<0&&(B[1]=-B[3],B[3]=0))}var F=c._parseDots(b);if(!F)return null;if(r=r.replace(/[\(\)\s,\xb0#]/g,"_"),a.gradient&&r!==a.gradient.id&&(y.defs.removeChild(a.gradient),delete a.gradient),!a.gradient){A=u(q+"Gradient",{id:r}),a.gradient=A,n in v&&A.setAttribute("gradientUnits",d(n)),p in w&&A.setAttribute("spreadMethod",d(p)),"radial"===q?(void 0!==f&&A.setAttribute("r",d(f)),void 0!==l&&void 0!==m&&(A.setAttribute("cx",d(l)),A.setAttribute("cy",d(m))),A.setAttribute("fx",d(s)),A.setAttribute("fy",d(t))):u(A,{x1:B[0],y1:B[1],x2:B[2],y2:B[3],gradientTransform:a.matrix.invert()}),y.defs.appendChild(A);for(var G=0,H=F.length;H>G;G++)A.appendChild(u("stop",{offset:F[G].offset?F[G].offset:G?"100%":"0%","stop-color":F[G].color||"#fff","stop-opacity":void 0===F[G].opacity?1:F[G].opacity}))}}return u(x,{fill:"url('"+c._url+"#"+r+"')",opacity:1,"fill-opacity":1}),z.fill=o,z.opacity=1,z.fillOpacity=1,1},y=function(a){var b=a.getBBox(1);u(a.pattern,{patternTransform:a.matrix.invert()+" translate("+b.x+","+b.y+")"})},z=function(a,e,f){if("path"==a.type){for(var g,h,i,j,k,l=d(e).toLowerCase().split("-"),m=a.paper,n=f?"end":"start",p=a.node,q=a.attrs,t=q["stroke-width"],v=l.length,w="classic",x=3,y=3,z=5;v--;)switch(l[v]){case"block":case"classic":case"oval":case"diamond":case"open":case"none":w=l[v];
+break;case"wide":y=5;break;case"narrow":y=2;break;case"long":x=5;break;case"short":x=2}if("open"==w?(x+=2,y+=2,z+=2,i=1,j=f?4:1,k={fill:"none",stroke:q.stroke}):(j=i=x/2,k={fill:q.stroke,stroke:"none"}),a._.arrows?f?(a._.arrows.endPath&&s[a._.arrows.endPath]--,a._.arrows.endMarker&&s[a._.arrows.endMarker]--):(a._.arrows.startPath&&s[a._.arrows.startPath]--,a._.arrows.startMarker&&s[a._.arrows.startMarker]--):a._.arrows={},"none"!=w){var A="raphael-marker-"+w,B="raphael-marker-"+n+w+x+y+"-obj"+a.id;c._g.doc.getElementById(A)?s[A]++:(m.defs.appendChild(u(u("path"),{"stroke-linecap":"round",d:r[w],id:A})),s[A]=1);var C,D=c._g.doc.getElementById(B);D?(s[B]++,C=D.getElementsByTagName("use")[0]):(D=u(u("marker"),{id:B,markerHeight:y,markerWidth:x,orient:"auto",refX:j,refY:y/2}),C=u(u("use"),{"xlink:href":"#"+A,transform:(f?"rotate(180 "+x/2+" "+y/2+") ":o)+"scale("+x/z+","+y/z+")","stroke-width":(1/((x/z+y/z)/2)).toFixed(4)}),D.appendChild(C),m.defs.appendChild(D),s[B]=1),u(C,k);var E=i*("diamond"!=w&&"oval"!=w);f?(g=a._.arrows.startdx*t||0,h=c.getTotalLength(q.path)-E*t):(g=E*t,h=c.getTotalLength(q.path)-(a._.arrows.enddx*t||0)),k={},k["marker-"+n]="url('"+c._url+"#"+B+"')",(h||g)&&(k.d=Raphael.getSubpath(q.path,g,h)),u(p,k),a._.arrows[n+"Path"]=A,a._.arrows[n+"Marker"]=B,a._.arrows[n+"dx"]=E,a._.arrows[n+"Type"]=w,a._.arrows[n+"String"]=e}else f?(g=a._.arrows.startdx*t||0,h=c.getTotalLength(q.path)-g):(g=0,h=c.getTotalLength(q.path)-(a._.arrows.enddx*t||0)),a._.arrows[n+"Path"]&&u(p,{d:Raphael.getSubpath(q.path,g,h)}),delete a._.arrows[n+"Path"],delete a._.arrows[n+"Marker"],delete a._.arrows[n+"dx"],delete a._.arrows[n+"Type"],delete a._.arrows[n+"String"];for(k in s)if(s[b](k)&&!s[k]){var F=c._g.doc.getElementById(k);F&&F.parentNode.removeChild(F)}}},A={"":[0],none:[0],"-":[3,1],".":[1,1],"-.":[3,1,1,1],"-..":[3,1,1,1,1,1],". ":[1,3],"- ":[4,3],"--":[8,3],"- .":[4,3,1,3],"--.":[8,3,1,3],"--..":[8,3,1,3,1,3]},B=function(a,b,e){var f=A[d(b).toLowerCase()];if(b=f||void 0!==b&&[].concat(b)){var g,h=a.attrs["stroke-width"]||"1",i={round:h,square:h,butt:0}[a.attrs["stroke-linecap"]||e["stroke-linecap"]]||0,j=g=b.length;if(f)for(;g--;)b[g]=b[g]*h+(g%2?1:-1)*i;else for(g=0;j>g;g+=2)b[g]-=i,b[g+1]&&(b[g+1]+=i),b[g]<=0&&(b[g]=.1);c.is(b,"array")&&u(a.node,{"stroke-dasharray":b.join(",")})}},C=c._setFillAndStroke=function(a,e){if(a.paper.canvas){var g=a.node,j=a.attrs,k=a.paper,n=g.style,p=n.visibility;n.visibility="hidden";for(var r in e)if(e[b](r)){if(!c._availableAttrs[b](r))continue;var s=e[r];switch(j[r]=s,r){case"blur":a.blur(s);break;case"href":case"title":case"target":var t=g.parentNode;if("a"!=t.tagName.toLowerCase()){if(s==o)break;var v=u("a");t.insertBefore(v,g),v.appendChild(g),t=v}"target"==r?t.setAttributeNS(q,"show","blank"==s?"new":s):t.setAttributeNS(q,r,s),g.titleNode=t;break;case"cursor":n.cursor=s;break;case"transform":a.transform(s);break;case"rotation":c.is(s,"array")?a.rotate.apply(a,s):a.rotate(s);break;case"arrow-start":z(a,s);break;case"arrow-end":z(a,s,1);break;case"clip-path":var w=!0;case"clip-rect":var A=!w&&d(s).split(l);if(a._.clipispath=!!w,w||4==A.length){a.clip&&a.clip.parentNode.parentNode.removeChild(a.clip.parentNode);var C=u("clipPath"),D=u(w?"path":"rect");C.id=c.createUUID(),u(D,w?{d:s?j["clip-path"]=c._pathToAbsolute(s):c._availableAttrs.path,fill:"none"}:{x:A[0],y:A[1],width:A[2],height:A[3],transform:a.matrix.invert()}),C.appendChild(D),k.defs.appendChild(C),u(g,{"clip-path":"url('"+c._url+"#"+C.id+"')"}),a.clip=D}if(!s){var F=g.getAttribute("clip-path");if(F){var G=c._g.doc.getElementById(F.replace(/(^url\(#|\)$)/g,o));G&&G.parentNode.removeChild(G),u(g,{"clip-path":o}),delete a.clip}}break;case"path":"path"==a.type&&(u(g,{d:s?j.path=c._pathToAbsolute(s):c._availableAttrs.path}),a._.dirty=1,a._.arrows&&("startString"in a._.arrows&&z(a,a._.arrows.startString),"endString"in a._.arrows&&z(a,a._.arrows.endString,1)));break;case"width":if(g.setAttribute(r,s),a._.dirty=1,!j.fx)break;r="x",s=j.x;case"x":j.fx&&(s=-j.x-(j.width||0));case"rx":if("rx"==r&&"rect"==a.type)break;case"cx":g.setAttribute(r,s),a.pattern&&y(a),a._.dirty=1;break;case"height":if(g.setAttribute(r,s),a._.dirty=1,!j.fy)break;r="y",s=j.y;case"y":j.fy&&(s=-j.y-(j.height||0));case"ry":if("ry"==r&&"rect"==a.type)break;case"cy":g.setAttribute(r,s),a.pattern&&y(a),a._.dirty=1;break;case"r":"rect"==a.type?u(g,{rx:s,ry:s}):g.setAttribute(r,s),a._.dirty=1;break;case"src":"image"==a.type&&g.setAttributeNS(q,"href",s);break;case"stroke-width":(1!=a._.sx||1!=a._.sy)&&(s/=h(i(a._.sx),i(a._.sy))||1),k._vbSize&&(s*=k._vbSize),m&&0===s&&(s=1e-6),g.setAttribute(r,s),j["stroke-dasharray"]&&B(a,j["stroke-dasharray"],e),a._.arrows&&("startString"in a._.arrows&&z(a,a._.arrows.startString),"endString"in a._.arrows&&z(a,a._.arrows.endString,1));break;case"stroke-dasharray":B(a,s,e);break;case"fill":var H=d(s).match(c._ISURL);if(H){C=u("pattern");var I=u("image");C.id=c.createUUID(),u(C,{x:0,y:0,patternUnits:"userSpaceOnUse",height:1,width:1}),u(I,{x:0,y:0,"xlink:href":H[1]}),C.appendChild(I),function(a){c._preload(H[1],function(){var b=this.offsetWidth,c=this.offsetHeight;u(a,{width:b,height:c}),u(I,{width:b,height:c}),k.safari()})}(C),k.defs.appendChild(C),u(g,{fill:"url('"+c._url+"#"+C.id+"')"}),a.pattern=C,a.pattern&&y(a);break}var J=c.getRGB(s);if(J.error){if(("circle"==a.type||"ellipse"==a.type||"r"!=d(s).charAt())&&x(a,s)){if("opacity"in j||"fill-opacity"in j){var K=c._g.doc.getElementById(g.getAttribute("fill").replace(/^url\(#|\)$/g,o));if(K){var L=K.getElementsByTagName("stop");u(L[L.length-1],{"stop-opacity":("opacity"in j?j.opacity:1)*("fill-opacity"in j?j["fill-opacity"]:1)})}}j.gradient=s,j.fill="none";break}}else delete e.gradient,delete j.gradient,!c.is(j.opacity,"undefined")&&c.is(e.opacity,"undefined")&&u(g,{opacity:j.opacity}),!c.is(j["fill-opacity"],"undefined")&&c.is(e["fill-opacity"],"undefined")&&u(g,{"fill-opacity":j["fill-opacity"]});J[b]("opacity")?(u(g,{"fill-opacity":n.fillOpacity=J.opacity>1?J.opacity/100:J.opacity}),a._.opacitydirty=!0):a._.opacitydirty&&c.is(j["fill-opacity"],"undefined")&&c.is(e["fill-opacity"],"undefined")&&(g.removeAttribute("fill-opacity"),n.fillOpacity=o,delete a._.opacitydirty);case"stroke":J=c.getRGB(s),g.setAttribute(r,J.hex),"stroke"==r&&J[b]("opacity")&&u(g,{"stroke-opacity":J.opacity>1?J.opacity/100:J.opacity}),"stroke"==r&&a._.arrows&&("startString"in a._.arrows&&z(a,a._.arrows.startString),"endString"in a._.arrows&&z(a,a._.arrows.endString,1));break;case"gradient":("circle"==a.type||"ellipse"==a.type||"r"!=d(s).charAt())&&x(a,s);break;case"line-height":case"vertical-align":break;case"visibility":"hidden"===s?a.hide():a.show();break;case"opacity":j.gradient&&!j[b]("stroke-opacity")&&u(g,{"stroke-opacity":s>1?s/100:s});case"fill-opacity":if(j.gradient){K=c._g.doc.getElementById(g.getAttribute("fill").replace(/^url\(#|\)$/g,o)),K&&(L=K.getElementsByTagName("stop"),u(L[L.length-1],{"stop-opacity":s}));break}default:"font-size"==r&&(s=f(s,10)+"px");var M=r.replace(/(\-.)/g,function(a){return a.substring(1).toUpperCase()});n[M]=s,a._.dirty=1,g.setAttribute(r,s)}}E(a,e),n.visibility=p}},D=1.2,E=function(a,f){if("text"==a.type&&(f[b]("text")||f[b]("font")||f[b]("font-size")||f[b]("x")||f[b]("y")||f[b]("line-height")||f[b]("vertical-align"))){var g=a.attrs,h=a.node,i=h.firstChild&&c._g.doc.defaultView.getComputedStyle(h.firstChild,o),j=i?e(c._g.doc.defaultView.getComputedStyle(h.firstChild,o).getPropertyValue("font-size")):10,k=e(f["line-height"]||g["line-height"])||j*D,l=g[b]("vertical-align")?g["vertical-align"]:"middle";if(isNaN(k)&&(k=j*D),l="top"===l?-.5:"bottom"===l?.5:0,f[b]("text")&&(f.text!==g.text||a._textdirty)){for(g.text=f.text;h.firstChild;)h.removeChild(h.firstChild);for(var m,n=d(f.text).split(/\n| /gi),p=[],q=0,r=n.length;r>q;q++)m=u("tspan"),q?u(m,{dy:k,x:g.x}):u(m,{dy:k*n.length*l,x:g.x}),n[q]||(m.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),n[q]=" "),m.appendChild(c._g.doc.createTextNode(n[q])),h.appendChild(m),p[q]=m;a._textdirty=!1}else for(p=h.getElementsByTagName("tspan"),q=0,r=p.length;r>q;q++)q?u(p[q],{dy:k,x:g.x}):u(p[0],{dy:k*p.length*l,x:g.x});u(h,{x:g.x,y:g.y}),a._.dirty=1;var s=a._getBBox(),t=g.y-(s.y+s.height/2);if(s.isCalculated)switch(g["vertical-align"]){case"top":t=.75*s.height;break;case"bottom":t=-(.25*s.height);break;default:t=g.y-(s.y+.25*s.height)}t&&c.is(t,"finite")&&p[0]&&u(p[0],{dy:t})}},F=function(a,b,d){var e=this,f=d||b;e.node=e[0]=a,a.raphael=!0,a.raphaelid=e.id=c._oid++,e.matrix=c.matrix(),e.realPath=null,e.attrs=e.attrs||{},e.styles=e.styles||{},e.followers=e.followers||[],e.paper=b,e.ca=e.customAttributes=e.customAttributes||new b._CustomAttributes,e._={transform:[],sx:1,sy:1,deg:0,dx:0,dy:0,dirty:1},e.parent=f,!f.bottom&&(f.bottom=e),e.prev=f.top,f.top&&(f.top.next=e),f.top=e,e.next=null},G=c.el;F.prototype=G,G.constructor=F,c._engine.getNode=function(a){var b=a.node||a[0].node;return b.titleNode||b},c._engine.getLastNode=function(a){var b=a.node||a[a.length-1].node;return b.titleNode||b},c._engine.path=function(a,b,c){var d=u("path");c&&c.canvas&&c.canvas.appendChild(d)||b.canvas&&b.canvas.appendChild(d);var e=new F(d,b,c);return e.type="path",C(e,{fill:"none",stroke:"#000",path:a}),e},G.rotate=function(a,b,c){var f,g=this;return g.removed?g:(a=d(a).split(l),a.length-1&&(b=e(a[1]),c=e(a[2])),a=e(a[0]),null==c&&(b=c),(null==b||null==c)&&(f=g.getBBox(1),b=f.x+f.width/2,c=f.y+f.height/2),g.transform(g._.transform.concat([["r",a,b,c]])),g)},G.scale=function(a,b,c,f){var g,h=this;return h.removed?h:(a=d(a).split(l),a.length-1&&(b=e(a[1]),c=e(a[2]),f=e(a[3])),a=e(a[0]),null==b&&(b=a),null==f&&(c=f),(null==c||null==f)&&(g=h.getBBox(1)),c=null==c?g.x+g.width/2:c,f=null==f?g.y+g.height/2:f,h.transform(h._.transform.concat([["s",a,b,c,f]])),h)},G.translate=function(a,b){var c=this;return c.removed?c:(a=d(a).split(l),a.length-1&&(b=e(a[1])),a=e(a[0])||0,b=+b||0,c.transform(c._.transform.concat([["t",a,b]])),c)},G.transform=function(a){var d,e=this,f=e._;return null==a?f.transform:(c._extractTransform(e,a),e.clip&&!f.clipispath&&u(e.clip,{transform:e.matrix.invert()}),e.pattern&&y(e),e.node&&u(e.node,{transform:e.matrix}),(1!=f.sx||1!=f.sy)&&(d=e.attrs[b]("stroke-width")?e.attrs["stroke-width"]:1,e.attr({"stroke-width":d})),e)},G.hide=function(){var a=this;return!a.removed&&a.paper.safari(a.node.style.display="none"),a},G.show=function(){var a=this;return!a.removed&&a.paper.safari(a.node.style.display=o),a},G.remove=function(){if(!this.removed&&this.parent.canvas){var a,b=this,d=c._engine.getNode(b),e=b.paper,f=e.defs;for(e.__set__&&e.__set__.exclude(b),n.unbind("raphael.*.*."+b.id),b.gradient&&f&&f.removeChild(b.gradient);a=b.followers.pop();)a.el.remove();b.parent.canvas.removeChild(d),c._tear(b,e);for(a in b)b[a]="function"==typeof b[a]?c._removedFactory(a):null;b.removed=!0}},G._getBBox=function(){var a,b,c=this,d=c.node,e={},f=c.attrs;"none"===d.style.display&&(c.show(),b=!0);try{e=d.getBBox(),"text"==c.type&&(void 0===e.x&&(e.isCalculated=!0,a=f["text-anchor"],e.x=(f.x||0)-e.width*("start"===a?0:"middle"===a?.5:1)),void 0===e.y&&(e.isCalculated=!0,a=f["vertical-align"],e.y=(f.y||0)-e.height*("bottom"===a?1:"middle"===a?.5:0)))}catch(g){}finally{e=e||{}}return b&&c.hide(),e},G.css=function(a,d){if(this.removed)return this;if(null==d&&c.is(a,"string")){for(var e=a.split(l),f={},g=0,h=e.length;h>g;g++)a=e[g],a in this.styles&&(f[a]=this.styles[a]);return h-1?f:f[e[0]]}if(null==d&&c.is(a,"array")){for(f={},g=0,h=a.length;h>g;g++)f[a[g]]=this.styles(a[g]);return f}if(null!=d){var i={};i[a]=d}else null!=a&&c.is(a,"object")&&(i=a);var j,k={};for(var m in i)j=m.replace(/\B([A-Z]{1})/g,"-$1").toLowerCase(),c._availableAttrs[b](j)||"color"===j?("color"===j&&"text"===this.type&&(j="fill"),k[j]=i[m],k.dirty=!0):(n("raphael.css."+j+"."+this.id,this,i[m],j),this.node.style[j]=i[m],this.styles[j]=i[m]);for(g=0,h=this.followers.length;h>g;g++)this.followers[g].el.css(i);return k[b]("dirty")&&(delete k.dirty,this.attr(k)),this},G.attr=function(a,d){if(this.removed)return this;if(null==a){var e={};for(var f in this.attrs)this.attrs[b](f)&&(e[f]=this.attrs[f]);return e.gradient&&"none"==e.fill&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform,e.visibility="none"===this.node.style.display?"hidden":"visible",e}if(null==d&&c.is(a,"string")){if("fill"==a&&"none"==this.attrs.fill&&this.attrs.gradient)return this.attrs.gradient;if("transform"==a)return this._.transform;if("visibility"==a)return"none"===this.node.style.display?"hidden":"visible";for(var g=a.split(l),h={},i=0,j=g.length;j>i;i++)a=g[i],h[a]=a in this.attrs?this.attrs[a]:c.is(this.ca[a],"function")?this.ca[a].def:c._availableAttrs[a];return j-1?h:h[g[0]]}if(null==d&&c.is(a,"array")){for(h={},i=0,j=a.length;j>i;i++)h[a[i]]=this.attr(a[i]);return h}if(null!=d){var k={};k[a]=d}else null!=a&&c.is(a,"object")&&(k=a);for(var m in k)n("raphael.attr."+m+"."+this.id,this,k[m],m);var o={};for(m in this.ca)if(this.ca[m]&&k[b](m)&&c.is(this.ca[m],"function")&&!this.ca["_invoked"+m]){this.ca["_invoked"+m]=!0;var p=this.ca[m].apply(this,[].concat(k[m]));delete this.ca["_invoked"+m];for(var q in p)p[b](q)&&(k[q]=p[q]);this.attrs[m]=k[m],p===!1&&(o[m]=k[m],delete k[m])}C(this,k);var r;for(i=0,j=this.followers.length;j>i;i++)r=this.followers[i],r.cb&&!r.cb.call(r.el,k,this)||r.el.attr(k);for(q in o)k[q]=o[q];return this},G.blur=function(a){var b=this;if(0!==+a){var d=u("filter"),e=u("feGaussianBlur");b.attrs.blur=a,d.id=c.createUUID(),u(e,{stdDeviation:+a||1.5}),d.appendChild(e),b.paper.defs.appendChild(d),b._blur=d,u(b.node,{filter:"url('"+c._url+"#"+d.id+"')"})}else b._blur&&(b._blur.parentNode.removeChild(b._blur),delete b._blur,delete b.attrs.blur),b.node.removeAttribute("filter")},G.on=function(a,b){if(this.removed)return this;var d=b;return c.supportsTouch&&(a=c._touchMap[a]||"click"===a&&"touchstart"||a,d=function(a){a.preventDefault(),b()}),this.node["on"+a]=d,this},c._engine.group=function(a,b,c){var d=u("g");c&&c.canvas&&c.canvas.appendChild(d)||a.canvas&&a.canvas.appendChild(d);var e=new F(d,a,c);return e.type="group",e.canvas=e.node,e.top=null,e.bottom=null,b&&d.setAttribute("class",["red",b,e.id].join("-")),e},c._engine.circle=function(a,b,c,d,e){var f=u("circle");e&&e.canvas&&e.canvas.appendChild(f)||a.canvas&&a.canvas.appendChild(f);var g=new F(f,a,e);return g.attrs={cx:b,cy:c,r:d,fill:"none",stroke:"#000"},g.type="circle",u(f,g.attrs),g},c._engine.rect=function(a,b,c,d,e,f,g){var h=u("rect");g&&g.canvas&&g.canvas.appendChild(h)||a.canvas&&a.canvas.appendChild(h);var i=new F(h,a,g);return i.attrs={x:b,y:c,width:d,height:e,r:f||0,rx:f||0,ry:f||0,fill:"none",stroke:"#000"},i.type="rect",u(h,i.attrs),i},c._engine.ellipse=function(a,b,c,d,e,f){var g=u("ellipse");f&&f.canvas&&f.canvas.appendChild(g)||a.canvas&&a.canvas.appendChild(g);var h=new F(g,a,f);return h.attrs={cx:b,cy:c,rx:d,ry:e,fill:"none",stroke:"#000"},h.type="ellipse",u(g,h.attrs),h},c._engine.image=function(a,b,c,d,e,f,g){var h=u("image");u(h,{x:c,y:d,width:e,height:f,preserveAspectRatio:"none"}),h.setAttributeNS(q,"href",b),g&&g.canvas&&g.canvas.appendChild(h)||a.canvas&&a.canvas.appendChild(h);var i=new F(h,a,g);return i.attrs={x:c,y:d,width:e,height:f,src:b},i.type="image",i},c._engine.text=function(a,b,c,d,e){var f=u("text");e&&e.canvas&&e.canvas.appendChild(f)||a.canvas&&a.canvas.appendChild(f);var g=new F(f,a,e);return g.attrs={x:b,y:c,"text-anchor":"middle","vertical-align":"middle",text:d,stroke:"none",fill:"#000"},g.type="text",g._textdirty=!0,C(g,g.attrs),g},c._engine.setSize=function(a,b){return this.width=a||this.width,this.height=b||this.height,this.canvas.setAttribute("width",this.width),this.canvas.setAttribute("height",this.height),this._viewBox&&this.setViewBox.apply(this,this._viewBox),this},c._engine.create=function(){var a=c._getContainer.apply(0,arguments),b=a&&a.container,d=a.x,e=a.y,f=a.width,g=a.height;if(!b)throw new Error("SVG container not found.");var h,i=u("svg"),j="overflow:hidden;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;-ms-user-select:none;user-select:none;-o-user-select:none;cursor:default;";return d=d||0,e=e||0,f=f||512,g=g||342,u(i,{height:g,version:1.1,width:f,xmlns:"http://www.w3.org/2000/svg"}),1==b?(i.style.cssText=j+"position:absolute;left:"+d+"px;top:"+e+"px",c._g.doc.body.appendChild(i),h=1):(i.style.cssText=j+"position:relative",b.firstChild?b.insertBefore(i,b.firstChild):b.appendChild(i)),b=new c._Paper,b.width=f,b.height=g,b.canvas=i,b.clear(),b._left=b._top=0,h&&(b.renderfix=function(){}),b.renderfix(),b},c._engine.setViewBox=function(a,b,c,d,e){n("raphael.setViewBox",this,this._viewBox,[a,b,c,d,e]);var f,g,i=h(c/this.width,d/this.height),j=this.top,k=e?"meet":"xMinYMin";for(null==a?(this._vbSize&&(i=1),delete this._vbSize,f="0 0 "+this.width+p+this.height):(this._vbSize=i,f=a+p+b+p+c+p+d),u(this.canvas,{viewBox:f,preserveAspectRatio:k});i&&j;)g="stroke-width"in j.attrs?j.attrs["stroke-width"]:1,j.attr({"stroke-width":g}),j._.dirty=1,j._.dirtyT=1,j=j.prev;return this._viewBox=[a,b,c,d,!!e],this},c.prototype.renderfix=function(){var a,b=this.canvas,c=b.style;try{a=b.getScreenCTM()||b.createSVGMatrix()}catch(d){a=b.createSVGMatrix()}var e=-a.e%1,f=-a.f%1;(e||f)&&(e&&(this._left=(this._left+e)%1,c.left=this._left+"px"),f&&(this._top=(this._top+f)%1,c.top=this._top+"px"))},c.prototype.clear=function(){n("raphael.clear",this);for(var a=this.canvas;a.firstChild;)a.removeChild(a.firstChild);this.bottom=this.top=null,(this.desc=u("desc")).appendChild(c._g.doc.createTextNode(c.is(c.desc,"string")&&c.desc||"Created with Red Raphaël "+c.version)),a.appendChild(this.desc),a.appendChild(this.defs=u("defs"))},c.prototype.remove=function(){n("raphael.remove",this),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas);for(var a in this)this[a]="function"==typeof this[a]?c._removedFactory(a):null;this.removed=!0};var H=c.st;for(var I in G)G[b](I)&&!H[b](I)&&(H[I]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(I))}}(),function(){if(c.vml){var a="hasOwnProperty",b=String,d=parseFloat,e=Math,f=e.round,g=e.max,h=e.min,i=e.sqrt,j=e.abs,k="fill",l=/[, ]+/,m=c.eve,n=" progid:DXImageTransform.Microsoft",o=" ",p="",q={M:"m",L:"l",C:"c",Z:"x",m:"t",l:"r",c:"v",z:"x"},r=/([clmz]),?([^clmz]*)/gi,s=/ progid:\S+Blur\([^\)]+\)/g,t=/-?[^,\s-]+/g,u="position:absolute;left:0;top:0;width:1px;height:1px",v=21600,w={path:1,rect:1,image:1},x={circle:1,ellipse:1},y=function(a){var d=/[ahqstv]/gi,e=c._pathToAbsolute;if(b(a).match(d)&&(e=c._path2curve),d=/[clmz]/g,e==c._pathToAbsolute&&!b(a).match(d)){var g=b(a).replace(r,function(a,b,c){var d=[],e="m"==b.toLowerCase(),g=q[b];return c.replace(t,function(a){e&&2==d.length&&(g+=d+q["m"==b?"l":"L"],d=[]),d.push(f(a*v))}),g+d});return g||"m0,0"}var h,i,j=e(a);g=[];for(var k=0,l=j.length;l>k;k++){h=j[k],i=j[k][0].toLowerCase(),"z"==i&&(i="x");for(var m=1,n=h.length;n>m;m++)i+=f(h[m]*v)+(m!=n-1?",":p);g.push(i)}return g.length?g.join(o):"m0,0"},z=function(a,b,d){var e=c.matrix();return e.rotate(-a,.5,.5),{dx:e.x(b,d),dy:e.y(b,d)}},A=function(a,b,c,d,e,f){var g=a._,h=a.matrix,i=g.fillpos,l=a.node,m=l.style,n=1,p="",q=v/b,r=v/c;if(m.visibility="hidden",b&&c){if(l.coordsize=j(q)+o+j(r),m.rotation=f*(0>b*c?-1:1),f){var s=z(f,d,e);d=s.dx,e=s.dy}if(0>b&&(p+="x"),0>c&&(p+=" y")&&(n=-1),m.flip=p,l.coordorigin=d*-q+o+e*-r,i||g.fillsize){var t=l.getElementsByTagName(k);t=t&&t[0],l.removeChild(t),i&&(s=z(f,h.x(i[0],i[1]),h.y(i[0],i[1])),t.position=s.dx*n+o+s.dy*n),g.fillsize&&(t.size=g.fillsize[0]*j(b)+o+g.fillsize[1]*j(c)),l.appendChild(t)}m.visibility="visible"}};c._url=p,c.toString=function(){return"Your browser doesn’t support SVG. Falling down to VML.\nYou are running Raphaël "+this.version};var B=function(a,c,d){for(var e=b(c).toLowerCase().split("-"),f=d?"end":"start",g=e.length,h="classic",i="medium",j="medium";g--;)switch(e[g]){case"block":case"classic":case"oval":case"diamond":case"open":case"none":h=e[g];break;case"wide":case"narrow":j=e[g];break;case"long":case"short":i=e[g]}var k=a.node.getElementsByTagName("stroke")[0];k[f+"arrow"]=h,k[f+"arrowlength"]=i,k[f+"arrowwidth"]=j},C=c._setFillAndStroke=function(e,i){if(e.paper.canvas){e.attrs=e.attrs||{};var j=e.node,m=e.attrs,n=j.style,q=w[e.type]&&(i.x!=m.x||i.y!=m.y||i.width!=m.width||i.height!=m.height||i.cx!=m.cx||i.cy!=m.cy||i.rx!=m.rx||i.ry!=m.ry||i.r!=m.r),r=x[e.type]&&(m.cx!=i.cx||m.cy!=i.cy||m.r!=i.r||m.rx!=i.rx||m.ry!=i.ry),s="group"===e.type,t=e;for(var u in i)i[a](u)&&(m[u]=i[u]);if(q&&(m.path=c._getPath[e.type](e),e._.dirty=1),i.href&&(j.href=i.href),i.title&&(j.title=i.title),i.target&&(j.target=i.target),i.cursor&&(n.cursor=i.cursor),"blur"in i&&e.blur(i.blur),(i.path&&"path"==e.type||q)&&(j.path=y(~b(m.path).toLowerCase().indexOf("r")?c._pathToAbsolute(m.path):m.path),"image"==e.type&&(e._.fillpos=[m.x,m.y],e._.fillsize=[m.width,m.height],A(e,1,1,0,0,0))),"transform"in i&&e.transform(i.transform),"rotation"in i){var z=i.rotation;c.is(z,"array")?e.rotate.apply(e,z):e.rotate(z)}if("visibility"in i&&("hidden"===i.visibility?e.hide():e.show()),r){var C=+m.cx,E=+m.cy,F=+m.rx||+m.r||0,H=+m.ry||+m.r||0;j.path=c.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x",f((C-F)*v),f((E-H)*v),f((C+F)*v),f((E+H)*v),f(C*v))}if("clip-rect"in i){var I=b(i["clip-rect"]).split(l);if(4==I.length){I[0]=+I[0],I[1]=+I[1],I[2]=+I[2]+I[0],I[3]=+I[3]+I[1];var J,K=s?j:j.clipRect||c._g.doc.createElement("div"),L=K.style;s?(e.clip=I.slice(),J=e.matrix.offset(),J=[d(J[0]),d(J[1])],I[0]-=J[0],I[1]-=J[1],I[2]-=J[0],I[3]-=J[1],L.width="10800px",L.height="10800px"):j.clipRect||(L.top="0",L.left="0",L.width=e.paper.width+"px",L.height=e.paper.height+"px",j.parentNode.insertBefore(K,j),K.appendChild(j),j.clipRect=K),L.position="absolute",L.clip=c.format("rect({1}px {2}px {3}px {0}px)",I)}i["clip-rect"]||(s&&e.clip?(j.style.clip="rect(auto auto auto auto)",delete e.clip):j.clipRect&&(j.clipRect.style.clip="rect(auto auto auto auto)"))}if(e.textpath){var M=e.textpath.style;i.font&&(M.font=i.font),i["font-family"]&&(M.fontFamily='"'+i["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g,p)+'"'),i["font-size"]&&(M.fontSize=i["font-size"]),i["font-weight"]&&(M.fontWeight=i["font-weight"]),i["font-style"]&&(M.fontStyle=i["font-style"])}if("arrow-start"in i&&B(t,i["arrow-start"]),"arrow-end"in i&&B(t,i["arrow-end"],1),null!=i.opacity||null!=i["stroke-width"]||null!=i.fill||null!=i.src||null!=i.stroke||null!=i["stroke-width"]||null!=i["stroke-opacity"]||null!=i["fill-opacity"]||null!=i["stroke-dasharray"]||null!=i["stroke-miterlimit"]||null!=i["stroke-linejoin"]||null!=i["stroke-linecap"]){var N=j.getElementsByTagName(k),O=!1,P=-1;if(N=N&&N[0],!N&&(O=N=G(k)),"image"==e.type&&i.src&&(N.src=i.src),i.fill&&(N.on=!0),(null==N.on||"none"==i.fill||null===i.fill)&&(N.on=!1),N.on&&i.fill){var Q=b(i.fill).match(c._ISURL);if(Q){N.parentNode==j&&j.removeChild(N),N.rotate=!0,N.src=Q[1],N.type="tile";var R=e.getBBox(1);N.position=R.x+o+R.y,e._.fillpos=[R.x,R.y],c._preload(Q[1],function(){e._.fillsize=[this.offsetWidth,this.offsetHeight]})}else{var S=c.getRGB(i.fill);N.color=S.hex,N.src=p,N.type="solid",S.error&&(t.type in{circle:1,ellipse:1}||"r"!=b(i.fill).charAt())&&D(t,i.fill,N)?(m.fill="none",m.gradient=i.fill,N.rotate=!1):"opacity"in S&&!("fill-opacity"in i)&&(P=S.opacity)}}if(-1!==P||"fill-opacity"in i||"opacity"in i){var T=((+m["fill-opacity"]+1||2)-1)*((+m.opacity+1||2)-1)*((+P+1||2)-1);T=h(g(T,0),1),N.opacity=T,N.src&&(N.color="none")}j.appendChild(N);var U=j.getElementsByTagName("stroke")&&j.getElementsByTagName("stroke")[0],V=!1;!U&&(V=U=G("stroke")),(i.stroke&&"none"!=i.stroke||i["stroke-width"]||null!=i["stroke-opacity"]||i["stroke-dasharray"]||i["stroke-miterlimit"]||i["stroke-linejoin"]||i["stroke-linecap"])&&(U.on=!0),("none"==i.stroke||null===i.stroke||null==U.on||0==i.stroke||0==i["stroke-width"])&&(U.on=!1);var W=c.getRGB("stroke"in i?i.stroke:m.stroke);U.on&&i.stroke&&(U.color=W.hex),T=((+m["stroke-opacity"]+1||2)-1)*((+m.opacity+1||2)-1)*((+W.opacity+1||2)-1);var X=.75*(d(i["stroke-width"])||1);if(T=h(g(T,0),1),null==i["stroke-width"]&&(X=m["stroke-width"]),i["stroke-width"]&&(U.weight=X),X&&1>X&&(T*=X)&&(U.weight=1),U.opacity=T,i["stroke-linejoin"]&&(U.joinstyle=i["stroke-linejoin"])||V&&(V.joinstyle="miter"),U.miterlimit=i["stroke-miterlimit"]||8,i["stroke-linecap"]&&(U.endcap="butt"==i["stroke-linecap"]?"flat":"square"==i["stroke-linecap"]?"square":"round"),i["stroke-dasharray"]){var Y={"-":"shortdash",".":"shortdot","-.":"shortdashdot","-..":"shortdashdotdot",". ":"dot","- ":"dash","--":"longdash","- .":"dashdot","--.":"longdashdot","--..":"longdashdotdot"};U.dashstyle=Y[a](i["stroke-dasharray"])?Y[i["stroke-dasharray"]]:i["stroke-dasharray"].join&&i["stroke-dasharray"].join(" ")||p}V&&j.appendChild(U)}if("text"==t.type){t.paper.canvas.style.display=p;var Z=t.paper.span,$=100,_=m.font&&m.font.match(/\d+(?:\.\d*)?(?=px)/),ab=m["line-height"]&&(m["line-height"]+p).match(/\d+(?:\.\d*)?(?=px)/);n=Z.style,m.font&&(n.font=m.font),m["font-family"]&&(n.fontFamily=m["font-family"]),m["font-weight"]&&(n.fontWeight=m["font-weight"]),m["font-style"]&&(n.fontStyle=m["font-style"]),_=d(m["font-size"]||_&&_[0])||10,n.fontSize=_*$+"px",ab=d(m["line-height"]||ab&&ab[0])||12,m["line-height"]&&(n.lineHeight=ab*$+"px"),t.textpath.string&&(Z.innerHTML=b(t.textpath.string).replace(/"));var bb=Z.getBoundingClientRect();switch(t.W=m.w=(bb.right-bb.left)/$,t.H=m.h=(bb.bottom-bb.top)/$,t.X=m.x,t.Y=m.y,m["vertical-align"]){case"top":t.bby=t.H/2;break;case"bottom":t.bby=-t.H/2;break;default:t.bby=0}("x"in i||"y"in i||void 0!==t.bby)&&(t.path.v=c.format("m{0},{1}l{2},{1}",f(m.x*v),f((m.y+(t.bby||0))*v),f(m.x*v)+1));for(var cb=["x","y","text","font","font-family","font-weight","font-style","font-size","line-height"],db=0,eb=cb.length;eb>db;db++)if(cb[db]in i){t._.dirty=1;break}switch(m["text-anchor"]){case"start":t.textpath.style["v-text-align"]="left",t.bbx=t.W/2;break;case"end":t.textpath.style["v-text-align"]="right",t.bbx=-t.W/2;break;default:t.textpath.style["v-text-align"]="center",t.bbx=0}t.textpath.style["v-text-kern"]=!0}}},D=function(a,e,f){a.attrs=a.attrs||{};var g=(a.attrs,Math.pow),h="linear",j=".5 .5";if(a.attrs.gradient=e,e=b(e).replace(c._radial_gradient,function(a,b){h="radial",b=b&&b.split(",")||[];var c=(b[0],b[1],b[2],b[3]),e=b[4];return b[5],c&&e&&(c=d(c),e=d(e),g(c-.5,2)+g(e-.5,2)>.25&&(e=i(.25-g(c-.5,2))*(2*(e>.5)-1)+.5),j=c+o+e),p}),e=e.split(/\s*\-\s*/),"linear"==h){var k=e.shift();if(k=-d(k),isNaN(k))return null}var l=c._parseDots(e);if(!l)return null;if(a=a.shape||a.node,l.length){a.removeChild(f),f.on=!0,f.method="none",f.color=l[0].color,f.color2=l[l.length-1].color;for(var m=[],n=1,q=void 0===l[0].opacity?1:l[0].opacity,r=0,s=l.length;s>r;r++)l[r].offset&&m.push(l[r].offset+o+l[r].color),void 0!==l[r].opacity&&(n=l[r].opacity);f.colors=m.length?m.join():"0% "+f.color,f.opacity=n,f["o:opacity2"]=q,"radial"==h?(f.type="gradientTitle",f.focus="100%",f.focussize="0 0",f.focusposition=j,f.angle=0):(f.type="gradient",f.angle=(270-k)%360),a.appendChild(f)}return 1},E=function(a,b,d){var e=this,f=d||b;e.node=e[0]=a,a.raphael=!0,a.raphaelid=e.id=c._oid++,e.X=0,e.Y=0,e.attrs=e.attrs||{},e.styles=e.styles||{},e.followers=e.followers||[],e.paper=b,e.ca=e.customAttributes=e.customAttributes||new b._CustomAttributes,e.matrix=c.matrix(),e._={transform:[],sx:1,sy:1,dx:0,dy:0,deg:0,dirty:1,dirtyT:1},e.parent=f,!f.bottom&&(f.bottom=e),e.prev=f.top,f.top&&(f.top.next=e),f.top=e,e.next=null},F=c.el;E.prototype=F,F.constructor=E,F.transform=function(a){if(null==a)return this._.transform;var d,e=this.paper._viewBoxShift,f=e?"s"+[e.scale,e.scale]+"-1-1t"+[e.dx,e.dy]:p;e&&(d=a=b(a).replace(/\.{3}|\u2026/g,this._.transform||p)),c._extractTransform(this,f+a);var g,h=this.matrix.clone(),i=this.skew,j=this.node,k=~b(this.attrs.fill).indexOf("-"),l=!b(this.attrs.fill).indexOf("url(");if(h.translate(-.5,-.5),l||k||"image"==this.type)if(i.matrix="1 0 0 1",i.offset="0 0",g=h.split(),k&&g.noRotation||!g.isSimple){j.style.filter=h.toFilter();var m=this.getBBox(),n=this.getBBox(1),q=m.x2&&n.x2&&"x2"||"x",r=m.y2&&n.y2&&"y2"||"y",s=m[q]-n[q],t=m[r]-n[r];j.coordorigin=s*-v+o+t*-v,A(this,1,1,s,t,0)}else j.style.filter=p,A(this,g.scalex,g.scaley,g.dx,g.dy,g.rotate);else j.style.filter=p,i.matrix=b(h),i.offset=h.offset();return d&&(this._.transform=d),this},F.rotate=function(a,c,e){if(this.removed)return this;if(null!=a){if(a=b(a).split(l),a.length-1&&(c=d(a[1]),e=d(a[2])),a=d(a[0]),null==e&&(c=e),null==c||null==e){var f=this.getBBox(1);c=f.x+f.width/2,e=f.y+f.height/2}return this._.dirtyT=1,this.transform(this._.transform.concat([["r",a,c,e]])),this}},F.translate=function(a,c){return this.removed?this:(a=b(a).split(l),a.length-1&&(c=d(a[1])),a=d(a[0])||0,c=+c||0,this._.bbox&&(this._.bbox.x+=a,this._.bbox.y+=c),this.transform(this._.transform.concat([["t",a,c]])),this)},F.scale=function(a,c,e,f){if(this.removed)return this;if(a=b(a).split(l),a.length-1&&(c=d(a[1]),e=d(a[2]),f=d(a[3]),isNaN(e)&&(e=null),isNaN(f)&&(f=null)),a=d(a[0]),null==c&&(c=a),null==f&&(e=f),null==e||null==f)var g=this.getBBox(1);return e=null==e?g.x+g.width/2:e,f=null==f?g.y+g.height/2:f,this.transform(this._.transform.concat([["s",a,c,e,f]])),this._.dirtyT=1,this},F.hide=function(){var a=this;return!a.removed&&(a.node.style.display="none"),a},F.show=function(){var a=this;return!a.removed&&(a.node.style.display=p),a},F._getBBox=function(){return this.removed?{}:{x:this.X+(this.bbx||0)-this.W/2,y:this.Y+(this.bby||0)-this.H/2,width:this.W,height:this.H}},F.remove=function(){if(!this.removed&&this.parent.canvas){var a,b=c._engine.getNode(this);for(this.paper.__set__&&this.paper.__set__.exclude(this),m.unbind("raphael.*.*."+this.id);a=this.followers.pop();)a.el.remove();this.shape&&this.shape.parentNode.removeChild(this.shape),b.parentNode.removeChild(b),c._tear(this,this.paper);for(var a in this)this[a]="function"==typeof this[a]?c._removedFactory(a):null;this.removed=!0}},F.css=function(b,d){if(this.removed)return this;if(null==d&&c.is(b,"string")){for(var e=b.split(l),f={},g=0,h=e.length;h>g;g++)b=e[g],b in this.styles&&(f[b]=this.styles[b]);return h-1?f:f[e[0]]}if(null==d&&c.is(b,"array")){for(f={},g=0,h=b.length;h>g;g++)f[b[g]]=this.styles(b[g]);return f}if(null!=d){var i={};i[b]=d}else null!=b&&c.is(b,"object")&&(i=b);var j,k={};for(var n in i)j=n.replace(/\B([A-Z]{1})/g,"-$1").toLowerCase(),"color"===j&&"text"===this.type&&(j="fill"),c._availableAttrs[a](j)?(k[j]=i[n],k.dirty=!0):(m("raphael.css."+j+"."+this.id,this,i[n],j),void 0!=i[n]&&(this.node.style[j]=i[n]),this.styles[j]=i[n]);for(g=0,h=this.followers.length;h>g;g++)this.followers[g].el.css(i);return k[a]("dirty")&&(delete k.dirty,this.attr(k)),this},F.attr=function(b,d){if(this.removed)return this;if(null==b){var e={};for(var f in this.attrs)this.attrs[a](f)&&(e[f]=this.attrs[f]);return e.gradient&&"none"==e.fill&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform,e.visibility="none"===this.node.style.display?"hidden":"visible",e}if(null==d&&c.is(b,"string")){if(b==k&&"none"==this.attrs.fill&&this.attrs.gradient)return this.attrs.gradient;if("visibility"==b)return"none"===this.node.style.display?"hidden":"visible";for(var g=b.split(l),h={},i=0,j=g.length;j>i;i++)b=g[i],h[b]=b in this.attrs?this.attrs[b]:c.is(this.ca[b],"function")?this.ca[b].def:c._availableAttrs[b];return j-1?h:h[g[0]]}if(this.attrs&&null==d&&c.is(b,"array")){for(h={},i=0,j=b.length;j>i;i++)h[b[i]]=this.attr(b[i]);return h}var n;null!=d&&(n={},n[b]=d),null==d&&c.is(b,"object")&&(n=b);for(var o in n)m("raphael.attr."+o+"."+this.id,this,n[o],o);if(n){var p={};for(o in this.ca)if(this.ca[o]&&n[a](o)&&c.is(this.ca[o],"function")&&!this.ca["_invoked"+o]){this.ca["_invoked"+o]=!0;var q=this.ca[o].apply(this,[].concat(n[o]));
+delete this.ca["_invoked"+o];for(var r in q)q[a](r)&&(n[r]=q[r]);this.attrs[o]=n[o],q===!1&&(p[o]=n[o],delete n[o])}"text"in n&&"text"==this.type&&(this.textpath.string=n.text.replace(/ /gi,"\n")),C(this,n);var s;for(i=0,j=this.followers.length;j>i;i++)s=this.followers[i],s.cb&&!s.cb.call(s.el,n,this)||s.el.attr(n);for(var r in p)n[r]=p[r]}return this},F.blur=function(a){var b=this.node.runtimeStyle,d=b.filter;return d=d.replace(s,p),0!==+a?(this.attrs.blur=a,b.filter=d+o+n+".Blur(pixelradius="+(+a||1.5)+")",b.margin=c.format("-{0}px 0 0 -{0}px",f(+a||1.5))):(b.filter=d,b.margin=0,delete this.attrs.blur),this},F.on=function(a,b){return this.removed?this:(this.node["on"+a]=function(){var a=c._g.win.event;a.target=a.srcElement,b(a)},this)},c._engine.getNode=function(a){var b=a.node||a[0].node;return b.clipRect||b},c._engine.getLastNode=function(a){var b=a.node||a[a.length-1].node;return b.clipRect||b},c._engine.group=function(a,b,d){var e=c._g.doc.createElement("div"),f=new E(e,a,d);return e.style.cssText=u,b&&(e.className=["red",b,f.id].join("-")),(d||a).canvas.appendChild(e),f.type="group",f.canvas=f.node,f.transform=c._engine.group.transform,f.top=null,f.bottom=null,f},c._engine.group.transform=function(a){if(null==a)return this._.transform;var e,f,g,h,i,j=this,k=j.node.style,l=j.clip,m=j.paper._viewBoxShift,n=m?"s"+[m.scale,m.scale]+"-1-1t"+[m.dx,m.dy]:p;return m&&(e=a=b(a).replace(/\.{3}|\u2026/g,j._.transform||p)),c._extractTransform(j,n+a),f=j.matrix,g=f.offset(),h=d(g[0])||0,i=d(g[1])||0,k.left=h+"px",k.top=i+"px",k.zoom=(j._.tzoom=f.get(0))+p,l&&(k.clip=c.format("rect({1}px {2}px {3}px {0}px)",[l[0]-h,l[1]-i,l[2]-h,l[3]-i])),j},c._engine.path=function(a,b,c){var d=G("shape");d.style.cssText=u,d.coordsize=v+o+v,d.coordorigin=b.coordorigin;var e=new E(d,b,c),f={fill:"none",stroke:"#000"};a&&(f.path=a),e.type="path",e.path=[],e.Path=p,C(e,f),(c||b).canvas.appendChild(d);var g=G("skew");return g.on=!0,d.appendChild(g),e.skew=g,e},c._engine.rect=function(a,b,d,e,f,g,h){var i=c._rectPath(b,d,e,f,g),j=a.path(i,h),k=j.attrs;return j.X=k.x=b,j.Y=k.y=d,j.W=k.width=e,j.H=k.height=f,k.r=g,k.path=i,j.type="rect",j},c._engine.ellipse=function(a,b,c,d,e,f){var g=a.path(void 0,f);return g.X=b-d,g.Y=c-e,g.W=2*d,g.H=2*e,g.type="ellipse",C(g,{cx:b,cy:c,rx:d,ry:e}),g},c._engine.circle=function(a,b,c,d,e){var f=a.path(void 0,e);return f.X=b-d,f.Y=c-d,f.W=f.H=2*d,f.type="circle",C(f,{cx:b,cy:c,r:d}),f},c._engine.image=function(a,b,d,e,f,g,h){var i=c._rectPath(d,e,f,g),j=a.path(i,h).attr({stroke:"none"}),l=j.attrs,m=j.node,n=m.getElementsByTagName(k)[0];return l.src=b,j.X=l.x=d,j.Y=l.y=e,j.W=l.width=f,j.H=l.height=g,l.path=i,j.type="image",n.parentNode==m&&m.removeChild(n),n.rotate=!0,n.src=b,n.type="tile",j._.fillpos=[d,e],j._.fillsize=[f,g],m.appendChild(n),A(j,1,1,0,0,0),j},c._engine.text=function(a,d,e,g,h){var i=G("shape"),j=G("path"),k=G("textpath");d=d||0,e=e||0,g=g,j.v=c.format("m{0},{1}l{2},{1}",f(d*v),f(e*v),f(d*v)+1),j.textpathok=!0,k.string=b(g).replace(/ /gi,"\n"),k.on=!0,i.style.cssText=u,i.coordsize=v+o+v,i.coordorigin="0 0";var l=new E(i,a,h),m={fill:"#000",stroke:"none",text:g};l.shape=i,l.path=j,l.textpath=k,l.type="text",l.attrs.text=b(g||p),l.attrs.x=d,l.attrs.y=e,l.attrs.w=1,l.attrs.h=1,C(l,m),i.appendChild(k),i.appendChild(j),(h||a).canvas.appendChild(i);var n=G("skew");return n.on=!0,i.appendChild(n),l.skew=n,l},c._engine.setSize=function(a,b){var d=this.canvas.style;return this.width=a,this.height=b,a==+a&&(a+="px"),b==+b&&(b+="px"),d.width=a,d.height=b,d.clip="rect(0 "+a+" "+b+" 0)",this._viewBox&&c._engine.setViewBox.apply(this,this._viewBox),this},c._engine.setViewBox=function(a,b,c,d,e){m("raphael.setViewBox",this,this._viewBox,[a,b,c,d,e]);var f,h,i=this.width,j=this.height,k=1/g(c/i,d/j);return e&&(f=j/d,h=i/c,i>c*f&&(a-=(i-c*f)/2/f),j>d*h&&(b-=(j-d*h)/2/h)),this._viewBox=[a,b,c,d,!!e],this._viewBoxShift={dx:-a,dy:-b,scale:k},this.forEach(function(a){a.transform("...")}),this};var G;c._engine.initWin=function(a){var d=a.document;d.createStyleSheet().addRule(".rvml","behavior:url(#default#VML)");try{!d.namespaces.rvml&&d.namespaces.add("rvml","urn:schemas-microsoft-com:vml"),G=c._createNode=function(a,c){var e,f=d.createElement("');for(e in c)f[e]=b(c[e]);return f}}catch(e){G=c._createNode=function(a,c){var e,f=d.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');for(e in c)f[e]=b(c[e]);return f}}},c._engine.initWin(c._g.win),c._engine.create=function(){var a=c._getContainer.apply(0,arguments),b=a.container,d=a.height,e=a.width,f=a.x,g=a.y;if(!b)throw new Error("VML container not found.");var h=new c._Paper,i=h.canvas=c._g.doc.createElement("div"),j=i.style;return f=f||0,g=g||0,e=e||512,d=d||342,h.width=e,h.height=d,e==+e&&(e+="px"),d==+d&&(d+="px"),h.coordsize=1e3*v+o+1e3*v,h.coordorigin="0 0",h.span=c._g.doc.createElement("span"),h.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",i.appendChild(h.span),j.cssText=c.format("top:0;left:0;width:{0};height:{1};display:inline-block;cursor:default;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",e,d),1==b?(c._g.doc.body.appendChild(i),j.left=f+"px",j.top=g+"px",j.position="absolute"):b.firstChild?b.insertBefore(i,b.firstChild):b.appendChild(i),h.renderfix=function(){},h},c.prototype.clear=function(){m("raphael.clear",this),this.canvas.innerHTML=p,this.span=c._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},c.prototype.remove=function(){m("raphael.remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var a in this)this[a]="function"==typeof this[a]?c._removedFactory(a):null;return!0};var H=c.st;for(var I in F)F[a](I)&&!H[a](I)&&(H[I]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(I))}}(),function(){if(c.canvas){var a,b,d,e=c._g.win,f=c._g.doc,g=c._g,h="string",i="px",j=/[, ]+/,k=e.String,l=e.parseInt,m=e.parseFloat,n=e.Math,o=n.max,p=n.min,q=n.PI,r=(n.floor,c.eve),s=c.fn,t=c.el,u=c.st,v=c.clone,w=q/180,x="hasOwnProperty",y=" ",z="ontouchstart"in e||navigator.msMaxTouchPoints>0,A=("click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel".split(y),!1),B=[],C=[],D=function(a){for(var b,c=a.clientX,d=a.clientY,e=g.doc.documentElement.scrollTop||g.doc.body.scrollTop,f=g.doc.documentElement.scrollLeft||g.doc.body.scrollLeft,h=C.length;h--;){if(b=C[h],z){for(var i,j=a.touches.length;j--;)if(i=a.touches[j],i.identifier==b.el._drag.id){c=i.clientX,d=i.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}else a.preventDefault();c+=f,d+=e,r("raphael.drag.move."+b.el.id,b.move_scope||b.el,c-b.el._drag.x,d-b.el._drag.y,c,d,a)}},E=function(a){c.unmousemove(D).unmouseup(E);for(var b,d=C.length;d--;)b=C[d],b.el._drag={},r("raphael.drag.end."+b.el.id,b.end_scope||b.start_scope||b.move_scope||b.el,a);C=[]};if(c.canvas){a=c._createNode=function(b,c){if(c){typeof b===h&&(b=a(b));for(var d in c)c.hasOwnProperty(d)&&b.setAttribute(d,k(c[d]))}else b=f.createElement(b);return b},c._getConnectedNodes=function(){return{above:[],below:[]}},c._getTargetNode=function(a){a[0],a[1]},c._containerEventHandler=function(a){if(a=a||e.event,!A){var b=a.offsetX,d=a.offsetY;a.type,c._getTargetNode([b,d])}},b=function(a){this.type="basic",this.owner=a,this._rElement=null,this.mouseInteractions=!1,this.matrix=null,this.outlinePath=null,this.conf={}},b.prototype={constructor:b,render:function(){var a=this;return a.draw(),a.setBBox(),a},draw:function(){var a,b=this,c=b.context,d=b._rElement,e=d.matrix,f=b.isClipped,g=b.validateAttrs();d.attrs=g,c.save(),c.fillStyle=g.fill,c.strokeStyle=g.stroke,c.lineWidth=g["stroke-width"],(a=g["clip-rect"])&&(a=a.split(" "),c.rect(a[0],a[1],a[2],a[3]),c.clip(),f=b.isClipped=!0),b.applyTransform(e),b.paint(),c.restore()},paint:function(){},redraw:function(){this.COMInstance.redraw(this)},clear:function(){var a=this,b=a.context,c=a._bbox;c&&b.clearRect(c.x,c.y,c.width,c.height)},addMouseInteractivity:function(){var b,c=this,d=c._rElement.attrs,e=c._bbox,f=c.owner.wrapper._map,g="circle"===c.type?"circle":"rect",h="circle"===g?[d.cx,d.cy,d.r].join(","):[e.x,e.y,e.x2,e.y2].join(",");b=a("area",{shape:g,coords:h}),f.firstChild?f.insertBefore(b,f.firstChild):f.appendChild(b),c._mouseArea=b,c.eventListeners={}},updateMapAreaCoords:function(){var a=this,b=a._mouseArea,c=a._bbox;if(b)if(a instanceof K){var d=c.width/2;b.setAttribute("coords",[c.x+d,c.y+d,d].join(","))}else b.setAttribute("coords",[c.x,c.y,c.x2,c.y2].join(","))},applyTransform:function(a){var b,c=this,d=c.context;a&&(b=a.split(),d.translate(b.dx,b.dy),!b.noRotation&&d.rotate(w*b.rotate),d.scale(b.scalex,b.scaley))},setBBox:function(){var a=this,b=a._rElement,d=b.matrix,e=a.owner,f=e.getTransformMatrix&&e.getTransformMatrix();f&&(f=f.clone(),f.add(d),d=f),a.outlinePath?a._bbox=c.pathBBox(c.transformPath(a.outlinePath,d.toTransformString()).toString()):a.setShapeBBox(d),a._mouseArea&&a.updateMapAreaCoords()},getBBox:function(){return this._bbox},drawPath:function(a){var b=this,c=b.context,d=(a&&a.length||0,PathParser);for(d.reset(),d.setTokens(a),null!=c&&c.beginPath();!d.isEnd();)switch(d.nextCommand(),d.command){case"M":case"m":var e=d.getAsCurrentPoint();for(d.addMarker(e),null!=c&&c.moveTo(e.x,e.y),d.start=d.current;!d.isCommandOrEnd();){var e=d.getAsCurrentPoint();d.addMarker(e,d.start),null!=c&&c.lineTo(e.x,e.y)}break;case"L":case"l":for(;!d.isCommandOrEnd();){var f=d.current,e=d.getAsCurrentPoint();d.addMarker(e,f),null!=c&&c.lineTo(e.x,e.y)}break;case"H":case"h":for(;!d.isCommandOrEnd();){var g=new Point((d.isRelativeCommand()?d.current.x:0)+d.getScalar(),d.current.y);d.addMarker(g,d.current),d.current=g,null!=c&&c.lineTo(d.current.x,d.current.y)}break;case"V":case"v":for(;!d.isCommandOrEnd();){var g=new Point(d.current.x,(d.isRelativeCommand()?d.current.y:0)+d.getScalar());d.addMarker(g,d.current),d.current=g,null!=c&&c.lineTo(d.current.x,d.current.y)}break;case"C":case"c":for(;!d.isCommandOrEnd();){var h=d.current,i=d.getPoint(),j=d.getAsControlPoint(),k=d.getAsCurrentPoint();d.addMarker(k,j,i),null!=c&&c.bezierCurveTo(i.x,i.y,j.x,j.y,k.x,k.y)}break;case"S":case"s":for(;!d.isCommandOrEnd();){var h=d.current,i=d.getReflectedControlPoint(),j=d.getAsControlPoint(),k=d.getAsCurrentPoint();d.addMarker(k,j,i),null!=c&&c.bezierCurveTo(i.x,i.y,j.x,j.y,k.x,k.y)}break;case"Q":case"q":for(;!d.isCommandOrEnd();){var h=d.current,j=d.getAsControlPoint(),k=d.getAsCurrentPoint();d.addMarker(k,j,j),null!=c&&c.quadraticCurveTo(j.x,j.y,k.x,k.y)}break;case"T":case"t":for(;!d.isCommandOrEnd();){var h=d.current,j=d.getReflectedControlPoint();d.control=j;var k=d.getAsCurrentPoint();d.addMarker(k,j,j),null!=c&&c.quadraticCurveTo(j.x,j.y,k.x,k.y)}break;case"A":case"a":for(;!d.isCommandOrEnd();){var h=d.current,l=d.getScalar(),m=d.getScalar(),n=d.getScalar()*(Math.PI/180),o=d.getScalar(),p=d.getScalar(),k=d.getAsCurrentPoint(),q=new Point(Math.cos(n)*(h.x-k.x)/2+Math.sin(n)*(h.y-k.y)/2,-Math.sin(n)*(h.x-k.x)/2+Math.cos(n)*(h.y-k.y)/2),r=Math.pow(q.x,2)/Math.pow(l,2)+Math.pow(q.y,2)/Math.pow(m,2);r>1&&(l*=Math.sqrt(r),m*=Math.sqrt(r));var s=(o==p?-1:1)*Math.sqrt((Math.pow(l,2)*Math.pow(m,2)-Math.pow(l,2)*Math.pow(q.y,2)-Math.pow(m,2)*Math.pow(q.x,2))/(Math.pow(l,2)*Math.pow(q.y,2)+Math.pow(m,2)*Math.pow(q.x,2)));isNaN(s)&&(s=0);var t=new Point(s*l*q.y/m,s*-m*q.x/l),u=new Point((h.x+k.x)/2+Math.cos(n)*t.x-Math.sin(n)*t.y,(h.y+k.y)/2+Math.sin(n)*t.x+Math.cos(n)*t.y),v=function(a){return Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2))},w=function(a,b){return(a[0]*b[0]+a[1]*b[1])/(v(a)*v(b))},x=function(a,b){return(a[0]*b[1]=1&&(B=0);var C=1-p?1:-1,D=y+C*(B/2),E=new Point(u.x+l*Math.cos(D),u.y+m*Math.sin(D));if(d.addMarkerAngle(E,D-C*Math.PI/2),d.addMarkerAngle(k,D-C*Math.PI),null!=c){var w=l>m?l:m,F=l>m?1:l/m,G=l>m?m/l:1;c.translate(u.x,u.y),c.rotate(n),c.scale(F,G),c.arc(0,0,w,y,y+B,1-p),c.scale(1/F,1/G),c.rotate(-n),c.translate(-u.x,-u.y)}}break;case"Z":case"z":null!=c&&c.closePath(),d.current=d.start}return b.outlinePath=a,b},addEventListener:function(){var a,b,d=this,e=arguments,f=e&&e[0],g=e&&e[1];if(d._mouseArea||d.addMouseInteractivity(),a=d._mouseArea,"string"==typeof f&&"function"==typeof g)if(d._path)if("mouseover"===f||"mouseout"===f||"mousemove"===f){if(!d._mousemoveAdded){var h=function(a){var b=!1,d=!0,e=!1;return function(f){var g=f.layerX,h=f.layerY;e=!1,c.isPointInsidePath(a._transformPath,g,h)?(b=!0,d&&(d=!1,e=!0)):(d=!0,b&&(b=!1,e=!0)),d&&e&&a.eventListeners.mouseout&&a.eventListeners.mouseout.apply(this,arguments),b&&(e&&a.eventListeners.mouseover&&a.eventListeners.mouseover.apply(this,arguments),a.eventListeners.mousemove&&a.eventListeners.mousemove.apply(this,arguments))}}(d);a.addEventListener("mousemove",h,!1),d._mousemoveAdded=!0}d.eventListeners[f]=g}else{var b=function(a,b){return function(d){c.isPointInsidePath(a._path,d.layerX,d.layerY)&&b.apply(this,arguments)}}(d,g);a.addEventListener(f,b,!1)}else a.addEventListener(f,g,!1)},removeEventListener:function(){var a,b=this,c=arguments,d=c&&c[0],e=c&&c[1];b._mouseArea&&(a=b._mouseArea,"string"==typeof d&&"function"==typeof e&&a.removeEventListener(d,e))},attachEvent:function(){},detachEvent:function(){},validateAttrs:function(a){var b,c,d=this,e=v(d._rElement.attrs);if(null===a){if(d._isValid)return e;d._isValid=!0}a=a||e;for(b in a)switch(c=a[b],b){default:continue}return a},attrs:function(){}};var F=function(a){this.node=a,this.next=null,this.prev=null},G=function(){this.top=null,this.bottom=null};G.prototype={constructor:G,add:function(a){a=new F(a),this.bottom||(this.bottom=a),this.top&&(this.top.next=a),a.next=null,a.prev=this.top,this.top=a},addList:function(a){this.bottom||(this.bottom=a.bottom),this.top&&(this.top.next=a.bottom,a.bottom.prev=this.top),this.top=a.top},toFront:function(a){return this.top===a?!1:(this.bottom===a&&(this.bottom=a.next),a.prev&&(a.prev.next=a.next),a.next&&(a.next.prev=a.prev),this.top.next=a,a.prev=this.top,a.next=null,this.top=a,void 0)},toBack:function(a){return this.bottom===a?!1:(this.top===a&&(this.top=a.prev),a.prev&&(a.prev.next=a.next),a.next&&(a.next.prev=a.prev),this.bottom.prev=a,a.prev=null,a.next=this.bottom,this.bottom=a,void 0)},insertBefore:function(){},insertAfter:function(){},each:function(a,b){for(var c=this.bottom;c;)a.apply(c.node,b),c=c.next},iterate:function(a,b){for(var c=this.bottom,d=!0;c&&(d=a.apply(c.node,b),d!==!1);)c=c.next},dispose:function(){this.each(function(){this.node.dispose&&this.node.dispose()}),this.top=null,this.bottom=null}};var H=function(a,b){this.items=new G,this.owner=a,this.element=null,b?this.element=b:this.init()};H.prototype={constructor:H,appendChild:function(){var a=this,b=a.owner.wrapper,c=this.element;b._image?b.insertBefore(c,b._image):b.appendChild(c)},insertBefore:function(){},insertAfter:function(){},init:function(){this.element=a("canvas"),a(this.element,{width:this.owner.wrapper.offsetWidth,height:this.owner.wrapper.offsetHeight}),this.element.style.cssText="position:absolute;left:0;top:0;",this.appendChild()},getCanvas:function(){return this.element},getContext:function(){return this.element.getContext("2d")},addToLayer:function(a){this.items.add(a)},mergeWithLayerOnTop:function(a){this.items.addList(a.items),a.dispose(!0)},mergeWithLayerOnBottom:function(a){a.items.addList(this.items),this.items=a.items,a.dispose(!0)},dispose:function(a){a||this.items.each(function(){this.dispose()}),this.items=null,this.owner=null,this.element.parentNode.removeChild(this.element),this.element=null}};var I=function(a,b,c){this.nodeItems=new G,this.collectionItems=new G,this.layerItems=new G,this.owner=this.parent=a,this.layerOnTop=null,this.currentLayer=null,this.baseLayer=null,b?(this.wrapper=b,this.currentLayer=this.baseLayer=new H(this,c)):this.init()};I.prototype={constructor:I,init:function(){var b=this,c=b.parent,d=c.wrapper._image,e=a("div");e.style.cssText="width:100%;height:100%;position:absolute;left:0;top:0;",e._map=c.wrapper._map,d?c.wrapper.insertBefore(e,d):c.wrapper.appendChild(e),b.wrapper=e,b.currentLayer=b.baseLayer=new H(b)},getCurrentContext:function(){return this.currentLayer.getContext()},setLayerOnTop:function(a){this.layerOnTop=a},getCurrentCanvas:function(){return this.currentLayer.getCanvas()},addNode:function(a){this.nodeItems.add(a),"group"===a.type?this.addCollection(a):this.currentLayer.addToLayer(a)},addCollection:function(a){a=a||new I(this),this.collectionItems.add(a),this.currentLayer=new H(this),this.layerItems.add(this.currentLayer),a.setLayerOnTop(this.currentLayer)},dispose:function(){this.nodeItems.dispose(),this.collectionItems.dispose(),this.layerItems.dispose(),this.owner=this.parent=null,this.ownerLayer=null,this.currentLayer=null,this.baseLayer=null}};var J=function(a,c,d,e){var f=this,g=new I(null,c,a);f.width=d,f.height=e,f.createNode=function(a,c){c=c||g;var d,e=c.nodeItems,f=c.currentLayer,h=f.getCanvas();switch(a){case"rect":d=new RectFauxNode(c);break;case"circle":d=new K(c);break;case"path":d=new L(c);break;case"text":d=new M(c);break;case"group":d=new N(c),c.addCollection(d);break;default:d=new b(h)}return d.COMInstance=this,e.add(d),f.addToLayer(d),d},f.redraw=function(a){var b,c,d;if("group"===a.type)b=a.nodeItems,a.render();else for(d=a.layer,b=d.items,c=b.bottom,d.element.width=d.element.width;c;)fNode=c.node,"group"!==fNode.type&&fNode.render(),c=c.next},f.insertBefore=function(){},f.insertAfter=function(){},f.removeNode=function(){},f.refreshNode=function(){},f.refreshAll=function(){}};Point=function(a,b){this.x=a,this.y=b},Point.prototype.angleTo=function(a){return Math.atan2(a.y-this.y,a.x-this.x)},Point.prototype.applyTransform=function(a){var b=this.x*a[0]+this.y*a[2]+a[4],c=this.x*a[1]+this.y*a[3]+a[5];this.x=b,this.y=c},PathParser=new function(){this.tokens=null,this.setTokens=function(a){this.tokens="string"==typeof a?a.split(" "):a},this.reset=function(){this.i=-1,this.command="",this.previousCommand="",this.start=new Point(0,0),this.control=new Point(0,0),this.current=new Point(0,0),this.points=[],this.angles=[]},this.isEnd=function(){return this.i>=this.tokens.length-1},this.isCommandOrEnd=function(){return this.isEnd()?!0:null!=this.tokens[this.i+1].toString().match(/^[A-Za-z]$/)},this.isRelativeCommand=function(){switch(this.command){case"m":case"l":case"h":case"v":case"c":case"s":case"q":case"t":case"a":case"z":return!0}return!1},this.getToken=function(){return this.i++,this.tokens[this.i]},this.getScalar=function(){return parseFloat(this.getToken())},this.nextCommand=function(){this.previousCommand=this.command,this.command=this.getToken()},this.getPoint=function(){var a=new Point(this.getScalar(),this.getScalar());return this.makeAbsolute(a)},this.getAsControlPoint=function(){var a=this.getPoint();return this.control=a,a},this.getAsCurrentPoint=function(){var a=this.getPoint();return this.current=a,a},this.getReflectedControlPoint=function(){if("c"!=this.previousCommand.toLowerCase()&&"s"!=this.previousCommand.toLowerCase()&&"q"!=this.previousCommand.toLowerCase()&&"t"!=this.previousCommand.toLowerCase())return this.current;var a=new Point(2*this.current.x-this.control.x,2*this.current.y-this.control.y);return a},this.makeAbsolute=function(a){return this.isRelativeCommand()&&(a.x+=this.current.x,a.y+=this.current.y),a},this.addMarker=function(a,b,c){null!=c&&this.angles.length>0&&null==this.angles[this.angles.length-1]&&(this.angles[this.angles.length-1]=this.points[this.points.length-1].angleTo(c)),this.addMarkerAngle(a,null==b?null:b.angleTo(a))},this.addMarkerAngle=function(a,b){this.points.push(a),this.angles.push(b)},this.getMarkerPoints=function(){return this.points},this.getMarkerAngles=function(){for(var a=0;ah&&(a.r=h),0>c&&(a.r=0);break;case"width":case"height":0>c&&(a[b]=0);break;default:continue}return a},setShapeBBox:function(a){var b=this,c=b._rElement,d=c.attrs,e=a.get(0),f=a.get(3),g=a.get(4),h=a.get(5),i=d["stroke-width"];b._bbox={x:d.x*e+g-i,y:d.y*f+h-i,width:d.width*e+2*i,height:d.height*f+2*i},b._bbox.x2=b._bbox.x+b._bbox.width,b._bbox.y2=b._bbox.y+b._bbox.height,b.X=b._bbox.x,b.Y=b._bbox.y,b.W=b._bbox.width,b.H=b._bbox.height}});var K=function(a){this.type="circle",this._isValid=!1,this.parent=this.owner=a,this.context=a.getCurrentContext(),this.layer=a.currentLayer},L=function(a){this.type="path",this._isValid=!1,this.parent=this.owner=a,this.context=a.getCurrentContext(),this.layer=a.currentLayer},M=function(a){this.type="text",this._isValid=!1,this.parent=this.owner=a,this.context=a.getCurrentContext(),this.layer=a.currentLayer},N=function(a){this.type="group",this.nodeItems=new G,this.collectionItems=new G,this.layerItems=new G,this.owner=this.parent=a,this.layerOnTop=a.currentLayer,this.currentLayer=null,this.baseLayer=null,this.init()};K.prototype=c.extend(new b,{constructor:K,paint:function(){var a=this,b=a.context,c=a.validateAttrs(),d=c.cx,e=c.cy,f=c.r,g=f||c.rx,h=f||c.ry;if(c.r){if(a.drawPath(["M",d+f,e,"A",g,h,0,1,0,d-f,e,"A",g,h,0,1,0,d+f,e,"Z"]),c["stroke-width"]){var i=void 0===c["stroke-opacity"]?c.opacity:c["stroke-opacity"];void 0!==i&&(b.globalAlpha=i),b.stroke()}var j=void 0===c["fill-opacity"]?c.opacity:c["fill-opacity"];void 0!==j&&(b.globalAlpha=j),b.fill()}},setShapeBBox:function(a){var b=this,c=b._rElement,d=c.attrs,e=a.get(0),f=a.get(3),g=a.get(4),h=a.get(5),i=d["stroke-width"];b._bbox={x:g+(d.cx-d.r)*e-i,y:h+(d.cy-d.r)*f-i,width:2*(i+d.r*e),height:2*(d.r*f+i)},b._bbox.x2=b._bbox.x+b._bbox.width,b._bbox.y2=b._bbox.y+b._bbox.height,b.X=b._bbox.x,b.Y=b._bbox.y,b.W=b._bbox.width,b.H=b._bbox.height}}),L.prototype=c.extend(new b,{constructor:L,paint:function(){var a=this,b=a._rElement,d=b.attrs,e=b.attr("path"),f=b.matrix,g=a.context;a.drawPath(e),a._transformPath=c.transformPath(e,f.toTransformString());var h=void 0===d["stroke-opacity"]?d.opacity:d["stroke-opacity"];void 0!==h&&(g.globalAlpha=h),g.stroke();var i=void 0===d["fill-opacity"]?d.opacity:d["fill-opacity"];void 0!==i&&(g.globalAlpha=i),g.fill()}}),M.prototype=c.extend(new b,{constructor:M,paint:function(){var a=this,b=a._rElement,c=b.attr(),d=c.text,e=c.stroke,f=c["vertical-align"],g=c["text-anchor"],h=c.x,i=c.y,j=(b.matrix,a.context),m=c["font-size"]||10,n=c["line-height"]||1.2*l(m,10),q=["normal",m,c.font];if(j.fillStyle=e,j.font=q.join(" "),d){var r,s,t,u,v=k(d).split(/\n| /gi),w=v.length*n,x=-1/0,y=1/0;r="top"===f?i+n:"middle"===f?i-w/2+n/2:i-w+n;for(var z=0,A=v.length;A>z;z+=1)d=v[z],u=r+n*z,s=j.measureText(d).width,t="start"===g?h:"middle"===g?h-s/2:h-s,x=o(x,s),y=p(y,t),j.fillText(d,t,u);b._textdirty=!1}a.outlinePath=["M",y,r-n/1.4,"H",y+x,"V",r-n+w,"H",y,"V",r-n/1.4]}}),N.prototype=c.extend(c.extend(new b,I.prototype),{constructor:N,draw:function(){this.layerItems.each(function(){this.element.width=this.element.width}),b.prototype.draw.apply(this,arguments)},render:function(){var a=this;return a.draw(),a.setBBox(),a},paint:function(){var a=this,b=a.nodeList,c=a._rElement,d=(a.canvas,c.attrs),e=b.bottom;for(void 0!==d.opacity&&this.layerItems.each(function(){this.getContext().globalAlpha=d.opacity});e;)e.render(),e=e.next},setBBox:function(){},addMouseInteractivity:function(){},applyTransform:function(a){var c=this,d=c.parent,e=d.getTransformMatrix&&d.getTransformMatrix();e?(c.matrixApplied=e.clone(),c.matrixApplied.add(a.a,a.b,a.c,a.d,a.e,a.f)):c.matrixApplied=a,this.layerItems.each(function(){b.prototype.applyTransform.apply(this,[c.matrixApplied])})},getTransformMatrix:function(){return this.matrixApplied}}),d=function(a,b,d){var e=this,f=d||b;e.node=e[0]=a,a.raphael=!0,a.raphaelid=e.id=c._oid++,a._rElement=e,e.X=0,e.Y=0,e.attrs=e.attrs||{},e.styles=e.styles||{},e.followers=e.followers||[],e.paper=b,e.com=f.com,e.ca=e.customAttributes=e.customAttributes||new b._CustomAttributes,e.matrix=c.matrix(),e._={transform:[],sx:1,sy:1,dx:0,dy:0,deg:0},e.parent=f,!f.bottom&&(f.bottom=e),e.prev=f.top||null,f.top&&(f.top.next=e),f.top=e,e.next=null},d.prototype=t,t.constructor=d;var O=function(a,b){var d,e=S(a),f=c._getConnectedNodes(e),g=a.attrs;f.above,f.below;for(d in b)g[d]=b[d];e.redraw()},P=function(a,b){var d,e,f=(a.attrs,a.node),g={},h=!1,i=!1,j=!1;for(d in b)if(b[x](d)){if(!c._availableAttrs[x](d))continue;switch(e=b[d],d){case"fill-opacity":case"opacity":case"stroke-opcaity":case"stroke":case"fill":g[d]=e,h=!0;break;case"stroke-width":case"cx":case"cy":case"x":case"y":g[d]=e,i=!0;break;case"width":case"height":g[d]=e,j=!0;break;case"clip-rect":g[d]=e,h=!0;break;case"font-size":case"font":case"vertical-align":case"text-anchor":g[d]=e,h=!0;default:continue}}R(a,b,g),g=f.validateAttrs(g),(h||i||j)&&O(a,g,i,j)},Q=1.2,R=function(a,b,c){if("text"==a.type&&(b[x]("text")||b[x]("font")||b[x]("font-size")||b[x]("x")||b[x]("y")||b[x]("line-height")||b[x]("vertical-align"))){var d=a.attr(),e=b["font-size"]||d["font-size"]||10,f=m(b["line-height"]||d["line-height"])||l(e,10)*Q,g=b["vertical-align"]||d["vertical-align"]||"middle";isNaN(f)&&(f=e*Q),c["font-size"]=l(e,10)+"px",c.font=b.font||d.font||"Verdana",c["vertical-align"]=g,c.x=b.x||d.x||0,c.y=b.y||d.y||0,c["line-height"]=l(f,10),c["text-anchor"]=b["text-anchor"]||d["text-anchor"]||"middle"}};c._engine.initWin=function(a){a=a,f=a.document},c._engine.setSize=function(a,b){var c=this,d=c.canvas.style;return d.width=(c.width=+a||c.width)+i,d.height=(c.height=+b||c.height)+i,c},c._engine.create=function(){var b,d,e,g,h,i,j=c._getContainer.apply(0,arguments)||{},k=j.container,l=j.x,m=j.y,n=j.width,o=j.height;if(!k)throw new Error("Canvas container not found.");return h=new c._Paper,h.canvas=b=a("div"),l=l||0,m=m||0,h.width=n=n||512,h.height=o=o||342,h.left=h.top=0,1==k?(b.style.cssText=d+c.format(";width:100%;height:100%;position:absolute;left:{0}px;top:{1}px;",[l,m]),f.body.appendChild(b)):(b.style.cssText=d+";width:100%;height:100%;position:absolute",k.firstChild?k.insertBefore(b,k.firstChild):k.appendChild(b)),d="overflow:hidden;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;-ms-user-select:none;user-select:none;-o-user-select:none;cursor:default;"+c.format("width:{0}px;height:{1}px;",[n,o]),i=a("canvas"),i.style.cssText="position:absolute;left:0;top:0",i.setAttribute("width",h.width),i.setAttribute("height",h.height),h.com=new J(i,b,h.width,h.height),b.appendChild(i),e=a("img"),e.src="image1.png",e.style.cssText="opacity: 0;z-index: 100;background: transparent;position: absolute;left: 0;top: 0;width: "+n+"px;height: "+o+"px",b.appendChild(e),g=a("map"),g.setAttribute("name","mousemap"),g.setAttribute("id","mousemap"),b.appendChild(g),e.setAttribute("usemap","#mousemap"),b._image=e,b._map=g,h};var S=c._engine.getNode=function(a){return a.node||a[0].node};c._engine.getLastNode=function(a){return a.node||a[a.length-1].node},c._engine.rect=function(a,b,c,e,f,g,h){var i=a.com.createNode("rect",h&&h.node),j=new d(i,a,h),k=j.attrs;return k.x=b,k.y=c,k.width=e,k.height=f,k.fill="#fff",k.stroke="#000",k["stroke-width"]=1,k.r=g||0,k.rx=g||0,k.ry=g||0,j.type="rect",i.render(),j},c._engine.circle=function(a,b,c,e,f){var g=a.com.createNode("circle",f&&f.node),h=new d(g,a,f),i=h.attrs;return i.cx=b,i.cy=c,i.r=e,i.fill="none",i.stroke="#000",i["stroke-width"]=1,h.type="circle",g.render(),h},c._engine.ellipse=function(a,c,e,f,g,h){var i=new b,j=new d(i,a,h);return j.type="ellipse",j},c._engine.image=function(a,c,e,f,g,h,i){var j=new b,k=new d(j,a,i);return k.type="image",k},c._engine.text=function(a,b,c,e,f){var g=a.com.createNode("text",f&&f.node),h=new d(g,a,f),i=h.attrs;return i.x=b,i.y=c,i.text=e,i.fill="none",i.stroke="#000",i.font="Verdana",i["font-size"]="12px",i["vertical-align"]="middle",i["text-anchor"]="middle",h.type="text",g.render(),h},c._engine.path=function(a,b,c){var e=b.com.createNode("path",c&&c.node),f=new d(e,b,c),g=f.attrs;return g.path=a,g.fill="#fff",g.stroke="#000",g["stroke-width"]=1,f.type="path",e.render(),f},c._engine.group=function(a,b,c){var e=a.com.createNode("group",c&&c.node),f=new d(e,a,c),g=e.wrapper;return b&&g.setAttribute("class",["red",b].join("-")),f.canvas=g,f.type="group",f},t._getBBox=function(){return this.removed?{}:{x:this.X+(this.bbx||0)-this.W/2,y:this.Y+(this.bby||0)-this.H/2,width:this.W,height:this.H}},t.toFront=function(){if(this.removed)return this;var a,b,d,e=this,f=e.node,g=e.parent,h=f.owner,i=e.followers;for(c._tofront(e,g)&&("group"===t.type?g.canvas.appendChild(f):h.nodeList.tofront(f)),b=0,d=i.length;d>b;b++)(a=i[b]).stalk&&a.el[a.stalk](e);return e},t.toBack=function(){if(this.removed)return this;var a,b,d,e=this,f=e.node,g=e.parent,h=f.owner,i=e.followers;for(c._toback(e,g)&&("group"===t.type?g.canvas.appendChild(f):h.nodeList.toback(f)),b=0,d=i.length;d>b;b++)(a=i[b]).stalk&&a.el[a.stalk](e);return e},t.insertAfter=function(a){if(this.removed)return this;var b,d,e,f=this,g=f.node,h=a.node,i=h.owner,j=f.followers;for(h.next?i.nodeList.insertBefore(g,h.next):i.appendChild(g),c._insertafter(f,a,f.parent,a.parent),d=0,e=j.length;e>d;d++)(b=j[d]).stalk&&b.el[b.stalk](a);return f},t.insertBefore=function(a){if(this.removed)return this;var b,d,e,f=this,g=f.node,h=a.node,i=h.owner,j=f.followers;for(h?i.nodeList.insertBefore(g,h):i.appendChild(g),c._insertafter(f,a,f.parent,a.parent),d=0,e=j.length;e>d;d++)(b=j[d]).stalk&&b.el[b.stalk](a);return f},t.appendChild=function(){return this},t.removeChild=function(){return this},t.attr=function(a,b){if(this.removed)return this;var d,e,f,g,h,i,k,l,m,n,o,p=this,q=p.attrs,s=p.ca;if(null==a){g={};for(h in q)q.hasOwnProperty(h)&&(g[h]=q[h]);return g.gradient&&"none"==g.fill&&(g.fill=g.gradient)&&delete g.gradient,g.transform=p._.transform,g}if(null==b&&c.is(a,"string")){if("fill"==a&&"none"==q.fill&&q.gradient)return q.gradient;if("transform"==a)return p._.transform;for(d=a.split(j),i={},o=0,n=d.length;n>o;o++)a=d[o],i[a]=a in q?q[a]:c.is(s[a],"function")?s[a].def:c._availableAttrs[a];return n-1?i:i[d[0]]}if(null==b&&c.is(a,"array")){for(i={},o=0,n=a.length;n>o;o++)i[a[o]]=p.attr(a[o]);return i}null!=b?(e={},e[a]=b):null!=a&&c.is(a,"object")&&(e=a);for(h in e)r("raphael.attr."+h+"."+p.id,p,e[h],h);l={};for(h in s)if(s[h]&&e.hasOwnProperty(h)&&c.is(s[h],"function")&&!s["_invoked"+h]){s["_invoked"+h]=!0,f=s[h].apply(p,[].concat(e[h])),delete s["_invoked"+h];for(k in f)f.hasOwnProperty(k)&&(e[k]=f[k]);q[h]=e[h],f===!1&&(l[h]=e[h],delete e[h])}for(P(this,e),o=0,n=p.followers.length;n>o;o++)m=p.followers[o],m.cb&&!m.cb.call(m.el,e,p)||m.el.attr(e);
+for(k in l)e[k]=l[k];return this},t.css=function(){return this},t.drag=function(a,b,d,e,f,h){function i(i){(i.originalEvent||i).preventDefault();var j=g.doc.documentElement.scrollTop||g.doc.body.scrollTop,k=g.doc.documentElement.scrollLeft||g.doc.body.scrollLeft;this._drag.x=i.clientX+k,this._drag.y=i.clientY+j,this._drag.id=i.identifier,!C.length&&c.mousemove(D).mouseup(E),C.push({el:this,move_scope:e,start_scope:f,end_scope:h}),b&&r.on("raphael.drag.start."+this.id,b),a&&r.on("raphael.drag.move."+this.id,a),d&&r.on("raphael.drag.end."+this.id,d),r("raphael.drag.start."+this.id,f||e||this,i.clientX+k,i.clientY+j,i)}return this._drag={},B.push({el:this,start:i}),this.mousedown(i),this},t.undrag=function(){for(var a=B.length;a--;)B[a].el==this&&(this.unmousedown(B[a].start),B.splice(a,1),r.unbind("raphael.drag.*."+this.id));!B.length&&c.unmousemove(D).unmouseup(E)},t.rotate=function(a,b,c){var d,e=this;return e.removed?e:(a=k(a).split(j),a.length-1&&(b=m(a[1]),c=m(a[2])),a=m(a[0]),null==c&&(b=c),(null==b||null==c)&&(d=e.getBBox(1),b=d.x+d.width/2,c=d.y+d.height/2),e.transform(e._.transform.concat([["r",a,b,c]])),e)},t.scale=function(a,b,c,d){var e,f=this;return f.removed?f:(a=k(a).split(j),a.length-1&&(b=m(a[1]),c=m(a[2]),d=m(a[3])),a=m(a[0]),null==b&&(b=a),null==d&&(c=d),(null==c||null==d)&&(e=f.getBBox(1)),c=null==c?e.x+e.width/2:c,d=null==d?e.y+e.height/2:d,f.transform(f._.transform.concat([["s",a,b,c,d]])),f)},t.translate=function(a,b){var c=this;return c.removed?c:(a=k(a).split(j),a.length-1&&(b=m(a[1])),a=m(a[0])||0,b=+b||0,c.transform(c._.transform.concat([["t",a,b]])),c)},t.transform=function(a){var b,d=this,e=d._;return null===a?e.transform:(c._extractTransform(d,a),(1!=e.sx||1!=e.sy)&&(b=d.attrs[x]("stroke-width")?d.attrs["stroke-width"]:1,d.attr({"stroke-width":b})),d.node&&d.node.redraw(),d)},t.hide=function(){return this},t.show=function(){return this},t.blur=function(){return this},t.on=function(a,b){var c=this,d=c.listeners;d||(d=c.listeners={}),d[a]||(d[a]=[]),d[a].push(b)},t.remove=function(){return this},s.clear=function(){return r("raphael.clear",this),this},s.remove=function(){if(!this.removed){var a,b=this,d=b.canvas,e=d.parentNode;r("raphael.remove",b),e.removeChild(d);for(a in b)b[a]="function"==typeof b[a]?c._removedFactory(a):null;this.removed=!0}},c.toString=function(){return"Your browser supports canvas.\nYou are running RedRaphael "+c.version};for(var T in t)t.hasOwnProperty(T)&&!u.hasOwnProperty(T)&&(u[T]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(T))}}}(),M.was?L.win.Raphael=c:Raphael=c,c});
\ No newline at end of file
diff --git a/package/raphael.js b/package/raphael.js
new file mode 100644
index 0000000..fd21694
--- /dev/null
+++ b/package/raphael.js
@@ -0,0 +1,12310 @@
+/**!
+ * RedRaphael 1.0.0 - JavaScript Vector Library
+ * Copyright (c) 2012-2013 FusionCharts Technologies
+ *
+ * Raphael 2.1.0
+ * Copyright (c) 2008-2012 Dmitry Baranovskiy
+ * Copyright © 2008-2012 Sencha Labs
+ *
+ * Licensed under the MIT license.
+ */
+// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ┌────────────────────────────────────────────────────────────┐ \\
+// │ Eve 0.4.2 - JavaScript Events Library │ \\
+// ├────────────────────────────────────────────────────────────┤ \\
+// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
+// └────────────────────────────────────────────────────────────┘ \\
+
+(function (glob) {
+ var version = "0.4.2",
+ has = "hasOwnProperty",
+ separator = /[\.\/]/,
+ wildcard = "*",
+ fun = function () {},
+ numsort = function (a, b) {
+ return a - b;
+ },
+ current_event,
+ stop,
+ events = {n: {}},
+ /*\
+ * eve
+ [ method ]
+
+ * Fires event with given `name`, given scope and other parameters.
+
+ > Arguments
+
+ - name (string) name of the *event*, dot (`.`) or slash (`/`) separated
+ - scope (object) context for the event handlers
+ - varargs (...) the rest of arguments will be sent to event handlers
+
+ = (object) array of returned values from the listeners
+ \*/
+ eve = function (name, scope) {
+ name = String(name);
+ var e = events,
+ oldstop = stop,
+ args = Array.prototype.slice.call(arguments, 2),
+ listeners = eve.listeners(name),
+ z = 0,
+ f = false,
+ l,
+ indexed = [],
+ queue = {},
+ out = [],
+ ce = current_event,
+ errors = [];
+ current_event = name;
+ stop = 0;
+ for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
+ indexed.push(listeners[i].zIndex);
+ if (listeners[i].zIndex < 0) {
+ queue[listeners[i].zIndex] = listeners[i];
+ }
+ }
+ indexed.sort(numsort);
+ while (indexed[z] < 0) {
+ l = queue[indexed[z++]];
+ out.push(l.apply(scope, args));
+ if (stop) {
+ stop = oldstop;
+ return out;
+ }
+ }
+ for (i = 0; i < ii; i++) {
+ l = listeners[i];
+ if ("zIndex" in l) {
+ if (l.zIndex == indexed[z]) {
+ out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ do {
+ z++;
+ l = queue[indexed[z]];
+ l && out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ } while (l)
+ } else {
+ queue[l.zIndex] = l;
+ }
+ } else {
+ out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ }
+ }
+ stop = oldstop;
+ current_event = ce;
+ return out.length ? out : null;
+ };
+ // Undocumented. Debug only.
+ eve._events = events;
+ /*\
+ * eve.listeners
+ [ method ]
+
+ * Internal method which gives you array of all event handlers that will be triggered by the given `name`.
+
+ > Arguments
+
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated
+
+ = (array) array of event handlers
+ \*/
+ eve.listeners = function (name) {
+ var names = name.split(separator),
+ e = events,
+ item,
+ items,
+ k,
+ i,
+ ii,
+ j,
+ jj,
+ nes,
+ es = [e],
+ out = [];
+ for (i = 0, ii = names.length; i < ii; i++) {
+ nes = [];
+ for (j = 0, jj = es.length; j < jj; j++) {
+ e = es[j].n;
+ items = [e[names[i]], e[wildcard]];
+ k = 2;
+ while (k--) {
+ item = items[k];
+ if (item) {
+ nes.push(item);
+ out = out.concat(item.f || []);
+ }
+ }
+ }
+ es = nes;
+ }
+ return out;
+ };
+
+ /*\
+ * eve.on
+ [ method ]
+ **
+ * Binds given event handler with a given name. You can use wildcards “`*`” for the names:
+ | eve.on("*.under.*", f);
+ | eve("mouse.under.floor"); // triggers f
+ * Use @eve to trigger the listener.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ **
+ = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
+ > Example:
+ | eve.on("mouse", eatIt)(2);
+ | eve.on("mouse", scream);
+ | eve.on("mouse", catchIt)(1);
+ * This will ensure that `catchIt()` function will be called before `eatIt()`.
+ *
+ * If you want to put your handler before non-indexed handlers, specify a negative value.
+ * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
+ \*/
+ eve.on = function (name, f) {
+ name = String(name);
+ if (typeof f != "function") {
+ return function () {};
+ }
+ var names = name.split(separator),
+ e = events;
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ e = e.n;
+ e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}});
+ }
+ e.f = e.f || [];
+ for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
+ return fun;
+ }
+ e.f.push(f);
+ return function (zIndex) {
+ if (+zIndex == +zIndex) {
+ f.zIndex = +zIndex;
+ }
+ };
+ };
+ /*\
+ * eve.f
+ [ method ]
+ **
+ * Returns function that will fire given event with optional arguments.
+ * Arguments that will be passed to the result function will be also
+ * concated to the list of final arguments.
+ | el.onclick = eve.f("click", 1, 2);
+ | eve.on("click", function (a, b, c) {
+ | console.log(a, b, c); // 1, 2, [event object]
+ | });
+ > Arguments
+ - event (string) event name
+ - varargs (…) and any other arguments
+ = (function) possible event handler function
+ \*/
+ eve.f = function (event) {
+ var attrs = [].slice.call(arguments, 1);
+ return function () {
+ eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0)));
+ };
+ };
+ /*\
+ * eve.stop
+ [ method ]
+ **
+ * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
+ \*/
+ eve.stop = function () {
+ stop = 1;
+ };
+ /*\
+ * eve.nt
+ [ method ]
+ **
+ * Could be used inside event handler to figure out actual name of the event.
+ **
+ > Arguments
+ **
+ - subname (string) #optional subname of the event
+ **
+ = (string) name of the event, if `subname` is not specified
+ * or
+ = (boolean) `true`, if current event’s name contains `subname`
+ \*/
+ eve.nt = function (subname) {
+ if (subname) {
+ return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
+ }
+ return current_event;
+ };
+ /*\
+ * eve.nts
+ [ method ]
+ **
+ * Could be used inside event handler to figure out actual name of the event.
+ **
+ **
+ = (array) names of the event
+ \*/
+ eve.nts = function () {
+ return current_event.split(separator);
+ };
+ /*\
+ * eve.off
+ [ method ]
+ **
+ * Removes given function from the list of event listeners assigned to given name.
+ * If no arguments specified all the events will be cleared.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ \*/
+ /*\
+ * eve.unbind
+ [ method ]
+ **
+ * See @eve.off
+ \*/
+ eve.off = eve.unbind = function (name, f) {
+ if (!name) {
+ eve._events = events = {n: {}};
+ return;
+ }
+ var names = name.split(separator),
+ e,
+ key,
+ splice,
+ i, ii, j, jj,
+ cur = [events];
+ for (i = 0, ii = names.length; i < ii; i++) {
+ for (j = 0; j < cur.length; j += splice.length - 2) {
+ splice = [j, 1];
+ e = cur[j].n;
+ if (names[i] != wildcard) {
+ if (e[names[i]]) {
+ splice.push(e[names[i]]);
+ }
+ } else {
+ for (key in e) if (e[has](key)) {
+ splice.push(e[key]);
+ }
+ }
+ cur.splice.apply(cur, splice);
+ }
+ }
+ for (i = 0, ii = cur.length; i < ii; i++) {
+ e = cur[i];
+ while (e.n) {
+ if (f) {
+ if (e.f) {
+ for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) {
+ e.f.splice(j, 1);
+ break;
+ }
+ !e.f.length && delete e.f;
+ }
+ for (key in e.n) if (e.n[has](key) && e.n[key].f) {
+ var funcs = e.n[key].f;
+ for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) {
+ funcs.splice(j, 1);
+ break;
+ }
+ !funcs.length && delete e.n[key].f;
+ }
+ } else {
+ delete e.f;
+ for (key in e.n) if (e.n[has](key) && e.n[key].f) {
+ delete e.n[key].f;
+ }
+ }
+ e = e.n;
+ }
+ }
+ };
+ /*\
+ * eve.once
+ [ method ]
+ **
+ * Binds given event handler with a given name to only run once then unbind itself.
+ | eve.once("login", f);
+ | eve("login"); // triggers f
+ | eve("login"); // no listeners
+ * Use @eve to trigger the listener.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ **
+ = (function) same return function as @eve.on
+ \*/
+ eve.once = function (name, f) {
+ var f2 = function () {
+ eve.unbind(name, f2);
+ return f.apply(this, arguments);
+ };
+ return eve.on(name, f2);
+ };
+ /*\
+ * eve.version
+ [ property (string) ]
+ **
+ * Current version of the library.
+ \*/
+ eve.version = version;
+ eve.toString = function () {
+ return "You are running Eve " + version;
+ };
+ (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define != "undefined" ? (define("eve", [], function() { return eve; })) : (glob.eve = eve));
+})(this);
+/**!
+ * RedRaphael 1.0.0 - JavaScript Vector Library
+ * Copyright (c) 2012-2013 FusionCharts Technologies
+ *
+ * Raphael 2.1.0
+ * Copyright (c) 2008-2012 Dmitry Baranovskiy
+ * Copyright © 2008-2012 Sencha Labs
+ *
+ * Licensed under the MIT license.
+ */
+(function (glob, factory) {
+ // AMD support
+ if (typeof define === "function" && define.amd) {
+ // Define as an anonymous module
+ define(["eve"], function( eve ) {
+ return factory(glob, eve);
+ });
+ } else {
+ // Browser globals (glob is window)
+ // Raphael adds itself to window
+ factory(glob, glob.eve);
+ }
+}(this, function (window, eve) {
+ /*\
+ * Raphael
+ [ method ]
+ **
+ * Creates a canvas object on which to draw.
+ * You must do this first, as all future calls to drawing methods
+ * from this instance will be bound to this canvas.
+ > Parameters
+ **
+ - container (HTMLElement|string) DOM element or its ID which is going to be a parent for drawing surface
+ - width (number)
+ - height (number)
+ - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+ * or
+ - x (number)
+ - y (number)
+ - width (number)
+ - height (number)
+ - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+ * or
+ - all (array) (first 3 or 4 elements in the array are equal to [containerID, width, height] or [x, y, width, height]. The rest are element descriptions in format {type: type, }). See @Paper.add.
+ - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+ * or
+ - onReadyCallback (function) function that is going to be called on DOM ready event. You can also subscribe to this event via Eve’s “DOMLoad” event. In this case method returns `undefined`.
+ = (object) @Paper
+ > Usage
+ | // Each of the following examples create a canvas
+ | // that is 320px wide by 200px high.
+ | // Canvas is created at the viewport’s 10,50 coordinate.
+ | var paper = Raphael(10, 50, 320, 200);
+ | // Canvas is created at the top left corner of the #notepad element
+ | // (or its top right corner in dir="rtl" elements)
+ | var paper = Raphael(document.getElementById("notepad"), 320, 200);
+ | // Same as above
+ | var paper = Raphael("notepad", 320, 200);
+ | // Image dump
+ | var set = Raphael(["notepad", 320, 200, {
+ | type: "rect",
+ | x: 10,
+ | y: 10,
+ | width: 25,
+ | height: 25,
+ | stroke: "#f00"
+ | }, {
+ | type: "text",
+ | x: 30,
+ | y: 40,
+ | text: "Dump"
+ | }]);
+ \*/
+ function R(first) {
+ var args,
+ f;
+
+
+ if (R._url) { // reinitialize URL to be safe from popstate event
+ R._url = (R._g && R._g.win || window).location.href.replace(/#.*?$/, "");
+ }
+ if (R.is(first, "function")) {
+ return loaded ? first() : eve.on("raphael.DOMload", first);
+ }
+ else if (R.is(first, array)) {
+ return R._engine.create[apply](R, first.splice(0, 3 + R.is(first[0], nu))).add(first);
+ }
+ else {
+ args = Array.prototype.slice.call(arguments, 0);
+ if (R.is(args[args.length - 1], "function")) {
+ f = args.pop();
+ return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("raphael.DOMload", function() {
+ f.call(R._engine.create[apply](R, args));
+ });
+ } else {
+ return R._engine.create[apply](R, arguments);
+ }
+ }
+ }
+
+ R.upgrade = "1.0.0";
+ R.version = "2.1.0";
+ R.eve = eve;
+
+ var loaded,
+
+ undef,
+ E = "",
+ S = " ",
+ proto = "prototype",
+ has = "hasOwnProperty",
+ appendChild = "appendChild",
+ apply = "apply",
+ concat = "concat",
+ nu = "number",
+ string = "string",
+ array = "array",
+ object = "object",
+ finite = "finite",
+ toString = "toString",
+ fillString = "fill",
+ push = "push",
+ setAttribute = "setAttribute",
+ split = "split",
+ none = "none",
+ OBJECTSTRING = "object",
+ arrayToStr = "[object Array]",
+ objectToStr = "[object Object]",
+ arraySlice = Array.prototype.slice,
+ arraySplice = Array.prototype.splice,
+ g = {
+ doc: document,
+ win: window
+ },
+ oldRaphael = {
+ was: Object.prototype[has].call(g.win, "Raphael"),
+ is: g.win.Raphael
+ },
+ doc = g.doc,
+ win = g.win,
+
+ supportsTouch = R.supportsTouch = "createTouch" in doc,
+
+ CustomAttributes = function () {
+ /*\
+ * Raphael.ca
+ [ property (object) ]
+ **
+ * Shortcut for @Raphael.customAttributes
+ \*/
+ /*\
+ * Raphael.customAttributes
+ [ property (object) ]
+ **
+ * If you have a set of attributes that you would like to represent
+ * as a function of some number across all papers you can do it
+ * easily with custom attributes:
+ > Usage
+ | Raphael.customAttributes.hue = function (num) {
+ | num = num % 1;
+ | return {fill: "hsb(" + num + ", 0.75, 1)"};
+ | };
+ | // Custom attribute “hue” will change fill
+ | // to be given hue with fixed saturation and brightness.
+ | // Now you can use it like this:
+ | var c = paper.circle(10, 10, 10).attr({hue: .45});
+ | // or even like this:
+ | c.animate({hue: 1}, 1e3);
+ |
+ | // You could also create custom attribute
+ | // with multiple parameters:
+ | Raphael.customAttributes.hsb = function (h, s, b) {
+ | return {fill: "hsb(" + [h, s, b].join(",") + ")"};
+ | };
+ | c.attr({hsb: "0.5 .8 1"});
+ | c.animate({hsb: [1, 0, 0.5]}, 1e3);
+ \*/
+ },
+ caproto = R.ca = R.customAttributes = CustomAttributes.prototype,
+
+ Paper = function () {
+ /*\
+ * Paper.ca
+ [ property (object) ]
+ **
+ * Shortcut for @Paper.customAttributes
+ \*/
+ /*\
+ * Paper.customAttributes
+ [ property (object) ]
+ **
+ * If you have a set of attributes that you would like to represent
+ * as a function of some number you can do it easily with custom attributes:
+ > Usage
+ | paper.customAttributes.hue = function (num) {
+ | num = num % 1;
+ | return {fill: "hsb(" + num + ", 0.75, 1)"};
+ | };
+ | // Custom attribute “hue” will change fill
+ | // to be given hue with fixed saturation and brightness.
+ | // Now you can use it like this:
+ | var c = paper.circle(10, 10, 10).attr({hue: .45});
+ | // or even like this:
+ | c.animate({hue: 1}, 1e3);
+ |
+ | // You could also create custom attribute
+ | // with multiple parameters:
+ | paper.customAttributes.hsb = function (h, s, b) {
+ | return {fill: "hsb(" + [h, s, b].join(",") + ")"};
+ | };
+ | c.attr({hsb: "0.5 .8 1"});
+ | c.animate({hsb: [1, 0, 0.5]}, 1e3);
+ \*/
+ this.ca = this.customAttributes = new CustomAttributes();
+ this._CustomAttributes = function () {};
+ this._CustomAttributes.prototype = this.ca;
+ },
+
+ /*\
+ * Raphael.fn
+ [ property (object) ]
+ **
+ * You can add your own method to the canvas. For example if you want to draw a pie chart,
+ * you can create your own pie chart function and ship it as a Raphaël plugin. To do this
+ * you need to extend the `Raphael.fn` object. You should modify the `fn` object before a
+ * Raphaël instance is created, otherwise it will take no effect. Please note that the
+ * ability for namespaced plugins was removed in Raphael 2.0. It is up to the plugin to
+ * ensure any namespacing ensures proper context.
+ > Usage
+ | Raphael.fn.arrow = function (x1, y1, x2, y2, size) {
+ | return this.path( ... );
+ | };
+ | // or create namespace
+ | Raphael.fn.mystuff = {
+ | arrow: function () {…},
+ | star: function () {…},
+ | // etc…
+ | };
+ | var paper = Raphael(10, 10, 630, 480);
+ | // then use it
+ | paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"});
+ | paper.mystuff.arrow();
+ | paper.mystuff.star();
+ \*/
+ paperproto = R.fn = Paper.prototype = R.prototype,
+
+ elements = {
+ circle: 1,
+ rect: 1,
+ path: 1,
+ ellipse: 1,
+ text: 1,
+ image: 1,
+ group: 1
+ },
+ events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S),
+ touchMap = R._touchMap = {
+ mousedown: "touchstart",
+ mousemove: "touchmove",
+ mouseup: "touchend"
+ },
+
+ Str = win.String,
+ toFloat = win.parseFloat,
+ toInt = win.parseInt,
+ math = win.Math,
+ mmax = math.max,
+ mmin = math.min,
+ abs = math.abs,
+ pow = math.pow,
+ mathCos = math.cos,
+ mathSin = math.sin,
+ mathSqrt = math.sqrt,
+ round = math.round,
+ PI = math.PI,
+ deg2rad = PI / 180,
+ rad2deg = 180 / PI,
+
+ lowerCase = Str.prototype.toLowerCase,
+ upperCase = Str.prototype.toUpperCase,
+ objectToString = win.Object.prototype.toString,
+ paper = {},
+
+ separator = /[, ]+/,
+ formatrg = /\{(\d+)\}/g,
+ ISURL = R._ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i,
+ colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i,
+ bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
+ whitespace = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]/g,
+ commaSpaces = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/,
+ p2s = /,?([achlmqrstvxz]),?/gi,
+ pathCommand = /([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig,
+ tCommand = /([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig,
+ pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig,
+ radial_gradient = R._radial_gradient = /^x?r(?:\(([^\)]*?)\))?/,
+
+ isnan = {
+ "NaN": 1,
+ "Infinity": 1,
+ "-Infinity": 1
+ },
+ hsrg = {
+ hs: 1,
+ rg: 1
+ },
+ availableAttrs = R._availableAttrs = {
+ "arrow-end": none,
+ "arrow-start": none,
+ blur: 0,
+ "clip-rect": "0 0 1e9 1e9",
+ "clip-path": E,
+ cursor: "default",
+ cx: 0,
+ cy: 0,
+ fill: "#fff",
+ "fill-opacity": 1,
+ font: '10px "Arial"',
+ "font-family": '"Arial"',
+ "font-size": "10",
+ "font-style": "normal",
+ "font-weight": 400,
+ gradient: 0,
+ height: 0,
+ href: "about:blank",
+ "letter-spacing": 0,
+ "line-height": 12,
+ "vertical-align": "middle",
+ opacity: 1,
+ path: "M0,0",
+ r: 0,
+ rx: 0,
+ ry: 0,
+ src: E,
+ stroke: "#000",
+ "stroke-dasharray": E,
+ "stroke-linecap": "butt",
+ "stroke-linejoin": "butt",
+ "stroke-miterlimit": 0,
+ "stroke-opacity": 1,
+ "stroke-width": 1,
+ target: "_blank",
+ "text-anchor": "middle",
+ "visibility": E,
+ title: E,
+ transform: E,
+ rotation: 0,
+ width: 0,
+ x: 0,
+ y: 0
+ },
+ availableAnimAttrs = R._availableAnimAttrs = {
+ blur: nu,
+ "clip-rect": "csv",
+ "clip-path": "path",
+ cx: nu,
+ cy: nu,
+ fill: "colour",
+ "fill-opacity": nu,
+ "font-size": nu,
+ height: nu,
+ opacity: nu,
+ path: "path",
+ r: nu,
+ rx: nu,
+ ry: nu,
+ stroke: "colour",
+ "stroke-opacity": nu,
+ "stroke-width": nu,
+ transform: "transform",
+ width: nu,
+ x: nu,
+ y: nu
+ },
+ eldata = {},
+
+ sortByKey = function(a, b) {
+ return a.key - b.key;
+ },
+ sortByNumber = function(a, b) {
+ return toFloat(a) - toFloat(b);
+ },
+ fun = function() {
+ },
+ pipe = function(x) {
+ return x;
+ },
+
+ rectPath = R._rectPath = function(x, y, w, h, r) {
+ if (r) {
+ return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]];
+ }
+ return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]];
+ },
+
+ ellipsePath = function(x, y, rx, ry) {
+ if (ry == null) {
+ ry = rx;
+ }
+ return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]];
+ },
+
+ getPath = R._getPath = {
+ group: function() {
+ return false;
+ },
+ path: function(el) {
+ return el.attr("path");
+ },
+ circle: function(el) {
+ var a = el.attrs;
+ return ellipsePath(a.cx, a.cy, a.r);
+ },
+ ellipse: function(el) {
+ var a = el.attrs;
+ return ellipsePath(a.cx, a.cy, a.rx, a.ry);
+ },
+ rect: function(el) {
+ var a = el.attrs;
+ return rectPath(a.x, a.y, a.width, a.height, a.r);
+ },
+ image: function(el) {
+ var a = el.attrs;
+ return rectPath(a.x, a.y, a.width, a.height);
+ },
+ text: function(el) {
+ var bbox = el._getBBox();
+ return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
+ }
+ },
+
+ /*\
+ * Raphael.mapPath
+ [ method ]
+ **
+ * Transform the path string with given matrix.
+ > Parameters
+ - path (string) path string
+ - matrix (object) see @Matrix
+ = (string) transformed path string
+ \*/
+ mapPath = R.mapPath = function(path, matrix) {
+ if (!matrix) {
+ return path;
+ }
+ var x,
+ y,
+ i,
+ j,
+ ii,
+ jj,
+ pathi;
+
+ path = path2curve(path);
+ for (i = 0, ii = path.length; i < ii; i++) {
+ pathi = path[i];
+ for (j = 1, jj = pathi.length; j < jj; j += 2) {
+ x = matrix.x(pathi[j], pathi[j + 1]);
+ y = matrix.y(pathi[j], pathi[j + 1]);
+ pathi[j] = x;
+ pathi[j + 1] = y;
+ }
+ }
+ return path;
+ },
+
+ /*\
+ * Raphael.pick
+ [ method ]
+ **
+ * Returns the first truthy argument.
+ \*/
+ pick = R.pick = function() {
+ for (var arg, i = 0, ii = arguments.length; i < ii; i += 1) {
+ arg = arguments[i];
+ if (!arg && arg !== false && arg !== 0) {
+ continue;
+ }
+ return arg;
+ }
+ return undef;
+ },
+
+ lastArgIfGroup = R._lastArgIfGroup = function (args, clear) {
+ var last = args.length - 1,
+ arg = args[last];
+
+ if (arg && (arg.constructor === R.el.constructor) && arg.type === 'group') {
+ if (clear) {
+ arraySplice.call(args, last, 1);
+ }
+ return arg;
+ }
+ },
+
+ merge = R.merge = function (obj1, obj2, skipUndef, tgtArr, srcArr) {
+ var item,
+ srcVal,
+ tgtVal,
+ str,
+ cRef;
+ //check whether obj2 is an array
+ //if array then iterate through it's index
+ //**** MOOTOOLS precution
+
+ if (!srcArr) {
+ tgtArr = [obj1];
+ srcArr = [obj2];
+ }
+ else {
+ tgtArr.push(obj1);
+ srcArr.push(obj2);
+ }
+
+ if (obj2 instanceof Array) {
+ for (item = 0; item < obj2.length; item += 1) {
+ try {
+ srcVal = obj1[item];
+ tgtVal = obj2[item];
+ }
+ catch (e) {
+ continue;
+ }
+
+ if (typeof tgtVal !== OBJECTSTRING) {
+ if (!(skipUndef && tgtVal === undefined)) {
+ obj1[item] = tgtVal;
+ }
+ }
+ else {
+ if (srcVal === null || typeof srcVal !== OBJECTSTRING) {
+ srcVal = obj1[item] = tgtVal instanceof Array ? [] : {};
+ }
+ cRef = checkCyclicRef(tgtVal, srcArr);
+ if (cRef !== -1) {
+ srcVal = obj1[item] = tgtArr[cRef];
+ }
+ else {
+ merge(srcVal, tgtVal, skipUndef, tgtArr, srcArr);
+ }
+ }
+ }
+ }
+ else {
+ for (item in obj2) {
+ try {
+ srcVal = obj1[item];
+ tgtVal = obj2[item];
+ }
+ catch (e) {
+ continue;
+ }
+
+ if (tgtVal !== null && typeof tgtVal === OBJECTSTRING) {
+ // Fix for issue BUG: FWXT-602
+ // IE < 9 Object.prototype.toString.call(null) gives
+ // "[object Object]" instead of "[object Null]"
+ // that's why null value becomes Object in IE < 9
+ str = objectToString.call(tgtVal);
+ if (str === objectToStr) {
+ if (srcVal === null || typeof srcVal !== OBJECTSTRING) {
+ srcVal = obj1[item] = {};
+ }
+ cRef = checkCyclicRef(tgtVal, srcArr);
+ if (cRef !== -1) {
+ srcVal = obj1[item] = tgtArr[cRef];
+ }
+ else {
+ merge(srcVal, tgtVal, skipUndef, tgtArr, srcArr);
+ }
+ }
+ else if (str === arrayToStr) {
+ if (srcVal === null || !(srcVal instanceof Array)) {
+ srcVal = obj1[item] = [];
+ }
+ cRef = checkCyclicRef(tgtVal, srcArr);
+ if (cRef !== -1) {
+ srcVal = obj1[item] = tgtArr[cRef];
+ }
+ else {
+ merge(srcVal, tgtVal, skipUndef, tgtArr, srcArr);
+ }
+ }
+ else {
+ obj1[item] = tgtVal;
+ }
+ }
+ else {
+ obj1[item] = tgtVal;
+ }
+ }
+ }
+ return obj1;
+ },
+
+ extend = R.extend = function (obj1, obj2, skipUndef) {
+ if (typeof obj1 !== OBJECTSTRING && typeof obj2 !== OBJECTSTRING) {//if none of the arguments are object then return back
+ return null;
+ }
+
+ if (typeof obj2 !== OBJECTSTRING || obj2 === null) {
+ return obj1;
+ }
+
+ if (typeof obj1 !== OBJECTSTRING) {
+ obj1 = obj2 instanceof Array ? [] : {};
+ }
+ merge(obj1, obj2, skipUndef);
+ return obj1;
+
+ },
+
+ /*\
+ * Raphael.is
+ [ method ]
+ **
+ * Handfull replacement for `typeof` operator.
+ > Parameters
+ - o (…) any object or primitive
+ - type (string) name of the type, i.e. “string”, “function”, “number”, etc.
+ = (boolean) is given value is of given type
+ \*/
+ is = R.is = function(o, type) {
+ type = lowerCase.call(type);
+
+ if (type == finite) {
+ return !isnan[has](+o);
+ }
+ if (type == array) {
+ return o instanceof Array;
+ }
+ if (type === 'object' && (o === undef || o === null)) {
+ return false;
+ }
+ return (type == "null" && o === null) ||
+ (type == typeof o && o !== null) ||
+ (type == object && o === Object(o)) ||
+ (type == "array" && Array.isArray && Array.isArray(o)) ||
+ objectToString.call(o).slice(8, -1).toLowerCase() == type;
+ },
+
+ /*\
+ * Raphael.clone
+ [ method ]
+ **
+ * Returns a recursively cloned version of an object.
+ \*/
+ clone = R.clone = function (obj) {
+ if (Object(obj) !== obj) {
+ return obj;
+ }
+ var res = new obj.constructor;
+ for (var key in obj)
+ if (obj[has](key)) {
+ res[key] = clone(obj[key]);
+ }
+ return res;
+ },
+
+ /*\
+ * Raphael.createUUID
+ [ method ]
+ **
+ * Returns RFC4122, version 4 ID
+ \*/
+ createUUID = R.createUUID = (function(uuidRegEx, uuidReplacer) {
+ return function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase();
+ };
+ })(/[xy]/g, function(c) {
+ var r = math.random() * 16 | 0,
+ v = c == "x" ? r : (r & 3 | 8);
+ return v.toString(16);
+ });
+
+ R._g = g;
+
+ /*\
+ * Raphael.type
+ [ property (string) ]
+ **
+ * Can be “SVG”, “VML” or empty, depending on browser support.
+ \*/
+ R.type = (win.ENABLE_RED_CANVAS && (win.CanvasRenderingContext2D || doc.createElement('canvas').getContext)) ? "CANVAS" :
+ (win.SVGAngle || doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML");
+
+ if (R.type == "VML") {
+ var d = doc.createElement("div"),
+ b;
+
+ d.innerHTML = ' ';
+ b = d.firstChild;
+ b.style.behavior = "url(#default#VML)";
+ if (!(b && typeof b.adj == object)) {
+ return (R.type = E);
+ }
+ d = null;
+ }
+
+ /*\
+ * Raphael.svg
+ [ property (boolean) ]
+ **
+ * `true` if browser supports SVG.
+ \*/
+ /*\
+ * Raphael.vml
+ [ property (boolean) ]
+ **
+ * `true` if browser supports VML.
+ \*/
+ R.svg = !((R.vml = R.type == "VML") || (R.canvas = R.type == "CANVAS"));
+
+ R._Paper = Paper;
+ R._id = 0;
+ R._oid = 0;
+
+ /*\
+ * Raphael.angle
+ [ method ]
+ **
+ * Returns angle between two or three points
+ > Parameters
+ - x1 (number) x coord of first point
+ - y1 (number) y coord of first point
+ - x2 (number) x coord of second point
+ - y2 (number) y coord of second point
+ - x3 (number) #optional x coord of third point
+ - y3 (number) #optional y coord of third point
+ = (number) angle in degrees.
+ \*/
+ R.angle = function (x1, y1, x2, y2, x3, y3) {
+ if (x3 == null) {
+ var x = x1 - x2,
+ y = y1 - y2;
+ if (!x && !y) {
+ return 0;
+ }
+ return (180 + math.atan2(-y, -x) * rad2deg + 360) % 360;
+ }
+ else {
+ return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3);
+ }
+ };
+
+ /*\
+ * Raphael.rad
+ [ method ]
+ **
+ * Transform angle to radians
+ > Parameters
+ - deg (number) angle in degrees
+ = (number) angle in radians.
+ \*/
+ R.rad = function (deg) {
+ return deg % 360 * deg2rad;
+ };
+
+ /*\
+ * Raphael.deg
+ [ method ]
+ **
+ * Transform angle to degrees
+ > Parameters
+ - deg (number) angle in radians
+ = (number) angle in degrees.
+ \*/
+ R.deg = function (rad) {
+ return rad * rad2deg % 360;
+ };
+
+ /*\
+ * Raphael.snapTo
+ [ method ]
+ **
+ * Snaps given value to given grid.
+ > Parameters
+ - values (array|number) given array of values or step of the grid
+ - value (number) value to adjust
+ - tolerance (number) #optional tolerance for snapping. Default is `10`.
+ = (number) adjusted value.
+ \*/
+ R.snapTo = function (values, value, tolerance) {
+ var rem,
+ i;
+
+ if (!is(tolerance, finite)) {
+ tolerance = 10;
+ }
+
+ if (is(values, array)) {
+ i = values.length;
+ while (i--) {
+ if (abs(values[i] - value) <= tolerance) {
+ return values[i];
+ }
+ }
+ }
+ else {
+ values = +values;
+ rem = value % values;
+
+ if (rem < tolerance) {
+ return value - rem;
+ }
+ if (rem > values - tolerance) {
+ return value - rem + values;
+ }
+ }
+ return value;
+ };
+
+ /*\
+ * Raphael.setWindow
+ [ method ]
+ **
+ * Used when you need to draw in `<iframe>`. Switched window to the iframe one.
+ > Parameters
+ - newwin (window) new window object
+ \*/
+ R.setWindow = function (newwin) {
+ eve("raphael.setWindow", R, g.win, newwin);
+ win = g.win = newwin;
+ doc = g.doc = g.win.document;
+ if (R._engine.initWin) {
+ R._engine.initWin(g.win);
+ }
+ };
+
+ var toHex = function (color) {
+ if (R.vml) {
+ // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/
+ var trim = /^\s+|\s+$/g;
+ var bod;
+ try {
+ var docum = new ActiveXObject("htmlfile");
+ docum.write("");
+ docum.close();
+ bod = docum.body;
+ } catch (e) {
+ bod = createPopup().document.body;
+ }
+ var range = bod.createTextRange();
+ toHex = cacher(function(color) {
+ try {
+ bod.style.color = Str(color).replace(trim, E);
+ var value = range.queryCommandValue("ForeColor");
+ value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16);
+ return "#" + ("000000" + value.toString(16)).slice(-6);
+ } catch (e) {
+ return none;
+ }
+ });
+ } else {
+ var i = g.doc.createElement("i");
+ i.title = "Rapha\xebl Colour Picker";
+ i.style.display = none;
+ g.doc.body.appendChild(i);
+ toHex = cacher(function(color) {
+ i.style.color = color;
+ return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
+ });
+ }
+ return toHex(color);
+ },
+ hsbtoString = function() {
+ return "hsb(" + [this.h, this.s, this.b] + ")";
+ },
+ hsltoString = function() {
+ return "hsl(" + [this.h, this.s, this.l] + ")";
+ },
+ rgbtoString = function() {
+ return this.hex;
+ },
+ prepareRGB = function(r, g, b) {
+ if (g == null && is(r, object) && "r" in r && "g" in r && "b" in r) {
+ b = r.b;
+ g = r.g;
+ r = r.r;
+ }
+ if (g == null && is(r, string)) {
+ var clr = R.getRGB(r);
+ r = clr.r;
+ g = clr.g;
+ b = clr.b;
+ }
+ if (r > 1 || g > 1 || b > 1) {
+ r /= 255;
+ g /= 255;
+ b /= 255;
+ }
+
+ return [r, g, b];
+ },
+ packageRGB = function(r, g, b, o) {
+ var rgb = {
+ r: (r *= 255),
+ g: (g *= 255),
+ b: (b *= 255),
+ hex: R.rgb(r, g, b),
+ toString: rgbtoString
+ };
+ is(o, "finite") && (rgb.opacity = o);
+ return rgb;
+ };
+
+ /*\
+ * Raphael.color
+ [ method ]
+ **
+ * Parses the color string and returns object with all values for the given color.
+ > Parameters
+ - clr (string) color string in one of the supported formats (see @Raphael.getRGB)
+ = (object) Combined RGB & HSB object in format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••,
+ o error (boolean) `true` if string can’t be parsed,
+ o h (number) hue,
+ o s (number) saturation,
+ o v (number) value (brightness),
+ o l (number) lightness
+ o }
+ \*/
+ R.color = function(clr) {
+ var rgb;
+ if (R.is(clr, object) && "h" in clr && "s" in clr && "b" in clr) {
+ rgb = R.hsb2rgb(clr);
+ clr.r = rgb.r;
+ clr.g = rgb.g;
+ clr.b = rgb.b;
+ clr.hex = rgb.hex;
+ } else if (R.is(clr, object) && "h" in clr && "s" in clr && "l" in clr) {
+ rgb = R.hsl2rgb(clr);
+ clr.r = rgb.r;
+ clr.g = rgb.g;
+ clr.b = rgb.b;
+ clr.hex = rgb.hex;
+ } else {
+ if (R.is(clr, "string")) {
+ clr = R.getRGB(clr);
+ }
+ if (R.is(clr, object) && "r" in clr && "g" in clr && "b" in clr) {
+ rgb = R.rgb2hsl(clr);
+ clr.h = rgb.h;
+ clr.s = rgb.s;
+ clr.l = rgb.l;
+ rgb = R.rgb2hsb(clr);
+ clr.v = rgb.b;
+ } else {
+ clr = {
+ hex: none
+ };
+ clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1;
+ }
+ }
+ clr.toString = rgbtoString;
+ return clr;
+ };
+
+ /*\
+ * Raphael.hsb2rgb
+ [ method ]
+ **
+ * Converts HSB values to RGB object.
+ > Parameters
+ - h (number) hue
+ - s (number) saturation
+ - v (number) value or brightness
+ = (object) RGB object in format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••
+ o }
+ \*/
+ R.hsb2rgb = function(h, s, v, o) {
+ if (this.is(h, object) && "h" in h && "s" in h && "b" in h) {
+ v = h.b;
+ s = h.s;
+ h = h.h;
+ o = h.o;
+ }
+ h *= 360;
+ var R, G, B, X, C;
+ h = (h % 360) / 60;
+ C = v * s;
+ X = C * (1 - abs(h % 2 - 1));
+ R = G = B = v - C;
+
+ h = ~~h;
+ R += [C, X, 0, 0, X, C][h];
+ G += [X, C, C, X, 0, 0][h];
+ B += [0, 0, X, C, C, X][h];
+ return packageRGB(R, G, B, o);
+ };
+
+ /*\
+ * Raphael.hsl2rgb
+ [ method ]
+ **
+ * Converts HSL values to RGB object.
+ > Parameters
+ - h (number) hue
+ - s (number) saturation
+ - l (number) luminosity
+ = (object) RGB object in format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••
+ o }
+ \*/
+ R.hsl2rgb = function(h, s, l, o) {
+ if (this.is(h, object) && "h" in h && "s" in h && "l" in h) {
+ l = h.l;
+ s = h.s;
+ h = h.h;
+ }
+ if (h > 1 || s > 1 || l > 1) {
+ h /= 360;
+ s /= 100;
+ l /= 100;
+ }
+ h *= 360;
+ var R, G, B, X, C;
+ h = (h % 360) / 60;
+ C = 2 * s * (l < .5 ? l : 1 - l);
+ X = C * (1 - abs(h % 2 - 1));
+ R = G = B = l - C / 2;
+
+ h = ~~h;
+ R += [C, X, 0, 0, X, C][h];
+ G += [X, C, C, X, 0, 0][h];
+ B += [0, 0, X, C, C, X][h];
+ return packageRGB(R, G, B, o);
+ };
+
+ /*\
+ * Raphael.rgb2hsb
+ [ method ]
+ **
+ * Converts RGB values to HSB object.
+ > Parameters
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (object) HSB object in format:
+ o {
+ o h (number) hue
+ o s (number) saturation
+ o b (number) brightness
+ o }
+ \*/
+ R.rgb2hsb = function(r, g, b) {
+ b = prepareRGB(r, g, b);
+ r = b[0];
+ g = b[1];
+ b = b[2];
+
+ var H, S, V, C;
+ V = mmax(r, g, b);
+ C = V - mmin(r, g, b);
+ H = (C == 0 ? null :
+ V == r ? (g - b) / C :
+ V == g ? (b - r) / C + 2 :
+ (r - g) / C + 4
+ );
+ H = ((H + 360) % 6) * 60 / 360;
+ S = C == 0 ? 0 : C / V;
+ return {
+ h: H,
+ s: S,
+ b: V,
+ toString: hsbtoString
+ };
+ };
+
+ /*\
+ * Raphael.rgb2hsl
+ [ method ]
+ **
+ * Converts RGB values to HSL object.
+ > Parameters
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (object) HSL object in format:
+ o {
+ o h (number) hue
+ o s (number) saturation
+ o l (number) luminosity
+ o }
+ \*/
+ R.rgb2hsl = function(r, g, b) {
+ b = prepareRGB(r, g, b);
+ r = b[0];
+ g = b[1];
+ b = b[2];
+
+ var H, S, L, M, m, C;
+ M = mmax(r, g, b);
+ m = mmin(r, g, b);
+ C = M - m;
+ H = (C == 0 ? null :
+ M == r ? (g - b) / C :
+ M == g ? (b - r) / C + 2 :
+ (r - g) / C + 4);
+ H = ((H + 360) % 6) * 60 / 360;
+ L = (M + m) / 2;
+ S = (C == 0 ? 0 :
+ L < .5 ? C / (2 * L) :
+ C / (2 - 2 * L));
+ return {
+ h: H,
+ s: S,
+ l: L,
+ toString: hsltoString
+ };
+ };
+
+ R._path2string = function() {
+ return this.join(",").replace(p2s, "$1");
+ };
+
+ function repush(array, item) {
+ for (var i = 0, ii = array.length; i < ii; i++) {
+ if (array[i] === item) {
+ return array.push(array.splice(i, 1)[0]);
+ }
+ }
+ }
+
+ var cacher = R._cacher = function (f, scope, postprocessor) {
+ function cachedfunction() {
+ var arg = arraySlice.call(arguments, 0),
+ args = arg.join("\u2400"),
+ cache = cachedfunction.cache = cachedfunction.cache || {},
+ count = cachedfunction.count = cachedfunction.count || [];
+ if (cache[has](args)) {
+ repush(count, args);
+ return postprocessor ? postprocessor(cache[args]) : cache[args];
+ }
+ count.length >= 1e3 && delete cache[count.shift()];
+ count.push(args);
+ cache[args] = f[apply](scope, arg);
+ return postprocessor ? postprocessor(cache[args]) : cache[args];
+ }
+ return cachedfunction;
+ };
+
+ var preload = R._preload = function(src, f) {
+ var img = doc.createElement("img");
+ img.style.cssText = "position:absolute;left:-9999em;top:-9999em";
+ img.onload = function() {
+ f.call(this);
+ this.onload = null;
+ doc.body.removeChild(this);
+ };
+ img.onerror = function() {
+ doc.body.removeChild(this);
+ };
+ doc.body.appendChild(img);
+ img.src = src;
+ };
+
+ function clrToString() {
+ return this.hex;
+ }
+
+ /*\
+ * Raphael.getRGB
+ [ method ]
+ **
+ * Parses colour string as RGB object
+ > Parameters
+ - colour (string) colour string in one of formats:
+ #
+ # Colour name (“red
”, “green
”, “cornflowerblue
”, etc)
+ # #••• — shortened HTML colour: (“#000
”, “#fc0
”, etc)
+ # #•••••• — full length HTML colour: (“#000000
”, “#bd2300
”)
+ # rgb(•••, •••, •••) — red, green and blue channels’ values: (“rgb(200, 100, 0)
”)
+ # rgb(•••%, •••%, •••%) — same as above, but in %: (“rgb(100%, 175%, 0%)
”)
+ # hsb(•••, •••, •••) — hue, saturation and brightness values: (“hsb(0.5, 0.25, 1)
”)
+ # hsb(•••%, •••%, •••%) — same as above, but in %
+ # hsl(•••, •••, •••) — same as hsb
+ # hsl(•••%, •••%, •••%) — same as hsb
+ #
+ = (object) RGB object in format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue
+ o hex (string) color in HTML/CSS format: #••••••,
+ o error (boolean) true if string can’t be parsed
+ o }
+ \*/
+ R.getRGB = cacher(function(colour) {
+ var opacity,
+ res,
+ red,
+ green,
+ blue,
+ t,
+ values,
+ rgb;
+
+ colour && is(colour, 'object') && "opacity" in colour &&
+ (opacity = colour.opacity);
+ if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
+ return {
+ r: -1,
+ g: -1,
+ b: -1,
+ hex: none,
+ error: 1,
+ toString: clrToString
+ };
+ }
+ if (colour == none) {
+ return {
+ r: -1,
+ g: -1,
+ b: -1,
+ hex: none,
+ toString: clrToString
+ };
+ }
+ !(hsrg[has](colour.toLowerCase().substring(0, 2)) ||
+ colour.charAt() === "#") && (colour = toHex(colour));
+
+
+ if ((rgb = colour.match(colourRegExp))) {
+ if (rgb[2]) {
+ blue = toInt(rgb[2].substring(5), 16);
+ green = toInt(rgb[2].substring(3, 5), 16);
+ red = toInt(rgb[2].substring(1, 3), 16);
+ }
+ if (rgb[3]) {
+ blue = toInt((t = rgb[3].charAt(3)) + t, 16);
+ green = toInt((t = rgb[3].charAt(2)) + t, 16);
+ red = toInt((t = rgb[3].charAt(1)) + t, 16);
+ }
+ if (rgb[4]) {
+ values = rgb[4][split](commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red *= 2.55);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green *= 2.55);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue *= 2.55);
+ rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ }
+ if (rgb[5]) {
+ values = rgb[5][split](commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red *= 2.55);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green *= 2.55);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue *= 2.55);
+ (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
+ rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ return R.hsb2rgb(red, green, blue, opacity);
+ }
+ if (rgb[6]) {
+ values = rgb[6][split](commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red *= 2.55);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green *= 2.55);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue *= 2.55);
+ (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
+ rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ return R.hsl2rgb(red, green, blue, opacity);
+ }
+ rgb = {
+ r: red,
+ g: green,
+ b: blue,
+ toString: clrToString
+ };
+ rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
+ R.is(opacity, "finite") && (rgb.opacity = opacity);
+ return rgb;
+ }
+ return {
+ r: -1,
+ g: -1,
+ b: -1,
+ hex: none,
+ error: 1,
+ toString: clrToString
+ };
+ }, R);
+
+ R.tintshade = cacher(function(colour, percent) {
+ var rgb = R.getRGB(colour),
+ tint,
+ offset = 255;
+
+ (percent < 0) && (percent *= -1, offset = 0);
+ (percent > 1) && (percent = 1);
+
+ tint = percent === 0 ? rgb : {
+ r: offset - (offset - rgb.r) * percent,
+ g: offset - (offset - rgb.g) * percent,
+ b: offset - (offset - rgb.b) * percent,
+ toString: clrToString
+ };
+ tint.hex = R.rgb(tint.r, tint.g, tint.b);
+ rgb.error && (tint.error = rgb.error);
+
+ if ("opacity" in rgb) {
+ tint.rgba = 'rgba(' + [tint.r, tint.g, tint.b, rgb.opacity].join(',') + ')';
+ tint.opacity = rgb.opacity;
+ }
+ else {
+ tint.rgba = 'rgb(' + [tint.r, tint.g, tint.b].join(',') + ')';
+ }
+ return tint;
+ }, R);
+
+ /*\
+ * Raphael.hsb
+ [ method ]
+ **
+ * Converts HSB values to hex representation of the colour.
+ > Parameters
+ - h (number) hue
+ - s (number) saturation
+ - b (number) value or brightness
+ = (string) hex representation of the colour.
+ \*/
+ R.hsb = cacher(function(h, s, b) {
+ return R.hsb2rgb(h, s, b).hex;
+ });
+
+ /*\
+ * Raphael.hsl
+ [ method ]
+ **
+ * Converts HSL values to hex representation of the colour.
+ > Parameters
+ - h (number) hue
+ - s (number) saturation
+ - l (number) luminosity
+ = (string) hex representation of the colour.
+ \*/
+ R.hsl = cacher(function(h, s, l) {
+ return R.hsl2rgb(h, s, l).hex;
+ });
+
+ /*\
+ * Raphael.rgb
+ [ method ]
+ **
+ * Converts RGB values to hex representation of the colour.
+ > Parameters
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (string) hex representation of the colour.
+ \*/
+ R.rgb = cacher(function(r, g, b) {
+ return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1);
+ });
+
+ /*\
+ * Raphael.getColor
+ [ method ]
+ **
+ * On each call returns next colour in the spectrum. To reset it back to red call @Raphael.getColor.reset
+ > Parameters
+ - value (number) #optional brightness, default is `0.75`
+ = (string) hex representation of the colour.
+ \*/
+ R.getColor = function(value) {
+ var start = this.getColor.start = this.getColor.start || {
+ h: 0,
+ s: 1,
+ b: value || .75
+ },
+ rgb = this.hsb2rgb(start.h, start.s, start.b);
+ start.h += .075;
+ if (start.h > 1) {
+ start.h = 0;
+ start.s -= .2;
+ start.s <= 0 && (this.getColor.start = {
+ h: 0,
+ s: 1,
+ b: start.b
+ });
+ }
+ return rgb.hex;
+ };
+
+ /*\
+ * Raphael.getColor.reset
+ [ method ]
+ **
+ * Resets spectrum position for @Raphael.getColor back to red.
+ \*/
+ R.getColor.reset = function() {
+ delete this.start;
+ };
+
+ // http://schepers.cc/getting-to-the-point
+ function catmullRom2bezier(crp, z) {
+ var d = [];
+ for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
+ var p = [
+ {
+ x: +crp[i - 2],
+ y: +crp[i - 1]
+ },
+ {
+ x: +crp[i],
+ y: +crp[i + 1]
+ },
+ {
+ x: +crp[i + 2],
+ y: +crp[i + 3]
+ },
+ {
+ x: +crp[i + 4],
+ y: +crp[i + 5]
+ }
+ ];
+ if (z) {
+ if (!i) {
+ p[0] = {
+ x: +crp[iLen - 2],
+ y: +crp[iLen - 1]
+ };
+ } else if (iLen - 4 == i) {
+ p[3] = {
+ x: +crp[0],
+ y: +crp[1]
+ };
+ } else if (iLen - 2 == i) {
+ p[2] = {
+ x: +crp[0],
+ y: +crp[1]
+ };
+ p[3] = {
+ x: +crp[2],
+ y: +crp[3]
+ };
+ }
+ } else {
+ if (iLen - 4 == i) {
+ p[3] = p[2];
+ } else if (!i) {
+ p[0] = {
+ x: +crp[i],
+ y: +crp[i + 1]
+ };
+ }
+ }
+ d.push(["C",
+ (-p[0].x + 6 * p[1].x + p[2].x) / 6,
+ (-p[0].y + 6 * p[1].y + p[2].y) / 6,
+ (p[1].x + 6 * p[2].x - p[3].x) / 6,
+ (p[1].y + 6 * p[2].y - p[3].y) / 6,
+ p[2].x,
+ p[2].y
+ ]);
+ }
+
+ return d;
+ }
+
+ /*\
+ * Raphael.parsePathString
+ [ method ]
+ **
+ * Utility method
+ **
+ * Parses given path string into an array of arrays of path segments.
+ > Parameters
+ - pathString (string|array) path string or array of segments (in the last case it will be returned straight away)
+ = (array) array of segments.
+ \*/
+ R.parsePathString = function(pathString) {
+ if (!pathString) {
+ return null;
+ }
+ var pth = paths(pathString);
+ if (pth.arr) {
+ return pathClone(pth.arr);
+ }
+
+ var paramCounts = {
+ a: 7,
+ c: 6,
+ h: 1,
+ l: 2,
+ m: 2,
+ r: 4,
+ q: 4,
+ s: 4,
+ t: 2,
+ v: 1,
+ z: 0
+ },
+ data = [];
+ if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption
+ data = pathClone(pathString);
+ }
+ if (!data.length) {
+ Str(pathString).replace(pathCommand, function(a, b, c) {
+ var params = [],
+ name = b.toLowerCase();
+ c.replace(pathValues, function(a, b) {
+ b && params.push(+b);
+ });
+ if (name == "m" && params.length > 2) {
+ data.push([b][concat](params.splice(0, 2)));
+ name = "l";
+ b = b == "m" ? "l" : "L";
+ }
+ if (name == "r") {
+ data.push([b][concat](params));
+ } else
+ while (params.length >= paramCounts[name]) {
+ data.push([b][concat](params.splice(0, paramCounts[name])));
+ if (!paramCounts[name]) {
+ break;
+ }
+ }
+ });
+ }
+ data.toString = R._path2string;
+ pth.arr = pathClone(data);
+ return data;
+ };
+
+ /*\
+ * Raphael.parseTransformString
+ [ method ]
+ **
+ * Utility method
+ **
+ * Parses given path string into an array of transformations.
+ > Parameters
+ - TString (string|array) transform string or array of transformations (in the last case it will be returned straight away)
+ = (array) array of transformations.
+ \*/
+ R.parseTransformString = cacher(function(TString) {
+ if (!TString) {
+ return null;
+ }
+ var paramCounts = {
+ r: 3,
+ s: 4,
+ t: 2,
+ m: 6
+ },
+ data = [];
+ if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption
+ data = pathClone(TString);
+ }
+ if (!data.length) {
+ Str(TString).replace(tCommand, function(a, b, c) {
+ var params = [],
+ name = lowerCase.call(b);
+ c.replace(pathValues, function(a, b) {
+ b && params.push(+b);
+ });
+ data.push([b][concat](params));
+ });
+ }
+ data.toString = R._path2string;
+ return data;
+ });
+ // PATHS
+ var paths = function(ps) {
+ var p = paths.ps = paths.ps || {};
+ if (p[ps]) {
+ p[ps].sleep = 100;
+ } else {
+ p[ps] = {
+ sleep: 100
+ };
+ }
+ setTimeout(function() {
+ for (var key in p)
+ if (p[has](key) && key != ps) {
+ p[key].sleep--;
+ !p[key].sleep && delete p[key];
+ }
+ });
+ return p[ps];
+ };
+
+ /*\
+ * Raphael.findDotsAtSegment
+ [ method ]
+ **
+ * Utility method
+ **
+ * Find dot coordinates on the given cubic bezier curve at the given t.
+ > Parameters
+ - p1x (number) x of the first point of the curve
+ - p1y (number) y of the first point of the curve
+ - c1x (number) x of the first anchor of the curve
+ - c1y (number) y of the first anchor of the curve
+ - c2x (number) x of the second anchor of the curve
+ - c2y (number) y of the second anchor of the curve
+ - p2x (number) x of the second point of the curve
+ - p2y (number) y of the second point of the curve
+ - t (number) position on the curve (0..1)
+ = (object) point information in format:
+ o {
+ o x: (number) x coordinate of the point
+ o y: (number) y coordinate of the point
+ o m: {
+ o x: (number) x coordinate of the left anchor
+ o y: (number) y coordinate of the left anchor
+ o }
+ o n: {
+ o x: (number) x coordinate of the right anchor
+ o y: (number) y coordinate of the right anchor
+ o }
+ o start: {
+ o x: (number) x coordinate of the start of the curve
+ o y: (number) y coordinate of the start of the curve
+ o }
+ o end: {
+ o x: (number) x coordinate of the end of the curve
+ o y: (number) y coordinate of the end of the curve
+ o }
+ o alpha: (number) angle of the curve derivative at the point
+ o }
+ \*/
+ R.findDotsAtSegment = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+ var t1 = 1 - t,
+ t13 = pow(t1, 3),
+ t12 = pow(t1, 2),
+ t2 = t * t,
+ t3 = t2 * t,
+ x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
+ y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y,
+ mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x),
+ my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y),
+ nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x),
+ ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y),
+ ax = t1 * p1x + t * c1x,
+ ay = t1 * p1y + t * c1y,
+ cx = t1 * c2x + t * p2x,
+ cy = t1 * c2y + t * p2y,
+ alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI);
+ (mx > nx || my < ny) && (alpha += 180);
+ return {
+ x: x,
+ y: y,
+ m: {
+ x: mx,
+ y: my
+ },
+ n: {
+ x: nx,
+ y: ny
+ },
+ start: {
+ x: ax,
+ y: ay
+ },
+ end: {
+ x: cx,
+ y: cy
+ },
+ alpha: alpha
+ };
+ };
+
+ /*\
+ * Raphael.bezierBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Return bounding box of a given cubic bezier curve
+ > Parameters
+ - p1x (number) x of the first point of the curve
+ - p1y (number) y of the first point of the curve
+ - c1x (number) x of the first anchor of the curve
+ - c1y (number) y of the first anchor of the curve
+ - c2x (number) x of the second anchor of the curve
+ - c2y (number) y of the second anchor of the curve
+ - p2x (number) x of the second point of the curve
+ - p2y (number) y of the second point of the curve
+ * or
+ - bez (array) array of six points for bezier curve
+ = (object) point information in format:
+ o {
+ o min: {
+ o x: (number) x coordinate of the left point
+ o y: (number) y coordinate of the top point
+ o }
+ o max: {
+ o x: (number) x coordinate of the right point
+ o y: (number) y coordinate of the bottom point
+ o }
+ o }
+ \*/
+ R.bezierBBox = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
+ if (!R.is(p1x, "array")) {
+ p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y];
+ }
+ var bbox = curveDim.apply(null, p1x);
+ return {
+ x: bbox.min.x,
+ y: bbox.min.y,
+ x2: bbox.max.x,
+ y2: bbox.max.y,
+ width: bbox.max.x - bbox.min.x,
+ height: bbox.max.y - bbox.min.y
+ };
+ };
+
+ /*\
+ * Raphael.isPointInsideBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if given point is inside bounding boxes.
+ > Parameters
+ - bbox (string) bounding box
+ - x (string) x coordinate of the point
+ - y (string) y coordinate of the point
+ = (boolean) `true` if point inside
+ \*/
+ R.isPointInsideBBox = function(bbox, x, y) {
+ return x >= bbox.x && x <= bbox.x2 && y >= bbox.y && y <= bbox.y2;
+ };
+
+ /*\
+ * Raphael.isBBoxIntersect
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if two bounding boxes intersect
+ > Parameters
+ - bbox1 (string) first bounding box
+ - bbox2 (string) second bounding box
+ = (boolean) `true` if they intersect
+ \*/
+ R.isBBoxIntersect = function(bbox1, bbox2) {
+ var i = R.isPointInsideBBox;
+ return i(bbox2, bbox1.x, bbox1.y) ||
+ i(bbox2, bbox1.x2, bbox1.y) ||
+ i(bbox2, bbox1.x, bbox1.y2) ||
+ i(bbox2, bbox1.x2, bbox1.y2) ||
+ i(bbox1, bbox2.x, bbox2.y) ||
+ i(bbox1, bbox2.x2, bbox2.y) ||
+ i(bbox1, bbox2.x, bbox2.y2) ||
+ i(bbox1, bbox2.x2, bbox2.y2) ||
+ (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x ||
+ bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) &&
+ (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y);
+ };
+
+ function base3(t, p1, p2, p3, p4) {
+ var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4,
+ t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
+ return t * t2 - 3 * p1 + 3 * p2;
+ }
+
+ function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) {
+ if (z == null) {
+ z = 1;
+ }
+ z = z > 1 ? 1 : z < 0 ? 0 : z;
+ var z2 = z / 2,
+ n = 12,
+ Tvalues = [-0.1252, 0.1252, -0.3678, 0.3678, -0.5873, 0.5873, -0.7699, 0.7699, -0.9041, 0.9041, -0.9816, 0.9816],
+ Cvalues = [0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472],
+ sum = 0;
+ for (var i = 0; i < n; i++) {
+ var ct = z2 * Tvalues[i] + z2,
+ xbase = base3(ct, x1, x2, x3, x4),
+ ybase = base3(ct, y1, y2, y3, y4),
+ comb = xbase * xbase + ybase * ybase;
+ sum += Cvalues[i] * mathSqrt(comb);
+ }
+ return z2 * sum;
+ }
+
+ function getTatLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) {
+ if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) {
+ return;
+ }
+ var t = 1,
+ step = t / 2,
+ t2 = t - step,
+ l,
+ e = .01;
+ l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
+ while (abs(l - ll) > e) {
+ step /= 2;
+ t2 += (l < ll ? 1 : -1) * step;
+ l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
+ }
+ return t2;
+ }
+
+ function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
+ if (
+ mmax(x1, x2) < mmin(x3, x4) ||
+ mmin(x1, x2) > mmax(x3, x4) ||
+ mmax(y1, y2) < mmin(y3, y4) ||
+ mmin(y1, y2) > mmax(y3, y4)
+ ) {
+ return;
+ }
+ var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4),
+ ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4),
+ denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+
+ if (!denominator) {
+ return;
+ }
+ var px = nx / denominator,
+ py = ny / denominator,
+ px2 = +px.toFixed(2),
+ py2 = + py.toFixed(2);
+ if (
+ px2 < +mmin(x1, x2).toFixed(2) ||
+ px2 > +mmax(x1, x2).toFixed(2) ||
+ px2 < +mmin(x3, x4).toFixed(2) ||
+ px2 > +mmax(x3, x4).toFixed(2) ||
+ py2 < +mmin(y1, y2).toFixed(2) ||
+ py2 > +mmax(y1, y2).toFixed(2) ||
+ py2 < +mmin(y3, y4).toFixed(2) ||
+ py2 > +mmax(y3, y4).toFixed(2)
+ ) {
+ return;
+ }
+ return {
+ x: px,
+ y: py
+ };
+ }
+
+ function inter(bez1, bez2) {
+ return interHelper(bez1, bez2);
+ }
+
+ function interCount(bez1, bez2) {
+ return interHelper(bez1, bez2, 1);
+ }
+
+ function interHelper(bez1, bez2, justCount) {
+ var bbox1 = R.bezierBBox(bez1),
+ bbox2 = R.bezierBBox(bez2);
+
+ if (!R.isBBoxIntersect(bbox1, bbox2)) {
+ return justCount ? 0 : [];
+ }
+ var l1 = bezlen.apply(0, bez1),
+ l2 = bezlen.apply(0, bez2),
+ n1 = mmax(~~(l1 / 5), 1),
+ n2 = mmax(~~(l2 / 5), 1),
+ dots1 = [],
+ dots2 = [],
+ xy = {},
+ res = justCount ? 0 : [];
+
+ for (var i = 0; i < n1 + 1; i++) {
+ var p = R.findDotsAtSegment.apply(R, bez1.concat(i / n1));
+ dots1.push({
+ x: p.x,
+ y: p.y,
+ t: i / n1
+ });
+ }
+ for (i = 0; i < n2 + 1; i++) {
+ p = R.findDotsAtSegment.apply(R, bez2.concat(i / n2));
+ dots2.push({
+ x: p.x,
+ y: p.y,
+ t: i / n2
+ });
+ }
+ for (i = 0; i < n1; i++) {
+ for (var j = 0; j < n2; j++) {
+ var di = dots1[i],
+ di1 = dots1[i + 1],
+ dj = dots2[j],
+ dj1 = dots2[j + 1],
+ ci = abs(di1.x - di.x) < .001 ? "y" : "x",
+ cj = abs(dj1.x - dj.x) < .001 ? "y" : "x",
+ is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y);
+ if (is) {
+ if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) {
+ continue;
+ }
+ xy[is.x.toFixed(4)] = is.y.toFixed(4);
+ var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t),
+ t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t);
+ if (t1 >= 0 && t1 <= 1.001 && t2 >= 0 && t2 <= 1.001) {
+ if (justCount) {
+ res++;
+ } else {
+ res.push({
+ x: is.x,
+ y: is.y,
+ t1: mmin(t1, 1),
+ t2: mmin(t2, 1)
+ });
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+
+ /*\
+ * Raphael.pathIntersection
+ [ method ]
+ **
+ * Utility method
+ **
+ * Finds intersections of two paths
+ > Parameters
+ - path1 (string) path string
+ - path2 (string) path string
+ = (array) dots of intersection
+ o [
+ o {
+ o x: (number) x coordinate of the point
+ o y: (number) y coordinate of the point
+ o t1: (number) t value for segment of path1
+ o t2: (number) t value for segment of path2
+ o segment1: (number) order number for segment of path1
+ o segment2: (number) order number for segment of path2
+ o bez1: (array) eight coordinates representing beziér curve for the segment of path1
+ o bez2: (array) eight coordinates representing beziér curve for the segment of path2
+ o }
+ o ]
+ \*/
+ R.pathIntersection = function(path1, path2) {
+ return interPathHelper(path1, path2);
+ };
+ R.pathIntersectionNumber = function(path1, path2) {
+ return interPathHelper(path1, path2, 1);
+ };
+ function interPathHelper(path1, path2, justCount) {
+ path1 = R._path2curve(path1);
+ path2 = R._path2curve(path2);
+ var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2,
+ res = justCount ? 0 : [];
+ for (var i = 0, ii = path1.length; i < ii; i++) {
+ var pi = path1[i];
+ if (pi[0] == "M") {
+ x1 = x1m = pi[1];
+ y1 = y1m = pi[2];
+ } else {
+ if (pi[0] == "C") {
+ bez1 = [x1, y1].concat(pi.slice(1));
+ x1 = bez1[6];
+ y1 = bez1[7];
+ } else {
+ bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m];
+ x1 = x1m;
+ y1 = y1m;
+ }
+ for (var j = 0, jj = path2.length; j < jj; j++) {
+ var pj = path2[j];
+ if (pj[0] == "M") {
+ x2 = x2m = pj[1];
+ y2 = y2m = pj[2];
+ } else {
+ if (pj[0] == "C") {
+ bez2 = [x2, y2].concat(pj.slice(1));
+ x2 = bez2[6];
+ y2 = bez2[7];
+ } else {
+ bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m];
+ x2 = x2m;
+ y2 = y2m;
+ }
+ var intr = interHelper(bez1, bez2, justCount);
+ if (justCount) {
+ res += intr;
+ } else {
+ for (var k = 0, kk = intr.length; k < kk; k++) {
+ intr[k].segment1 = i;
+ intr[k].segment2 = j;
+ intr[k].bez1 = bez1;
+ intr[k].bez2 = bez2;
+ }
+ res = res.concat(intr);
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+
+ /*\
+ * Raphael.isPointInsidePath
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if given point is inside a given closed path.
+ > Parameters
+ - path (string) path string
+ - x (number) x of the point
+ - y (number) y of the point
+ = (boolean) true, if point is inside the path
+ \*/
+ R.isPointInsidePath = function(path, x, y) {
+ var bbox = R.pathBBox(path);
+ return R.isPointInsideBBox(bbox, x, y) &&
+ ((interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1) ||
+ (interPathHelper(path, [["M", x, y], ["V", bbox.y2 + 10]], 1) % 2 == 1))
+ };
+ R._removedFactory = function(methodname) {
+ return function() {
+ eve("raphael.log", null, "Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object", methodname);
+ };
+ };
+
+ /*\
+ * Raphael.pathBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Return bounding box of a given path
+ > Parameters
+ - path (string) path string
+ = (object) bounding box
+ o {
+ o x: (number) x coordinate of the left top point of the box
+ o y: (number) y coordinate of the left top point of the box
+ o x2: (number) x coordinate of the right bottom point of the box
+ o y2: (number) y coordinate of the right bottom point of the box
+ o width: (number) width of the box
+ o height: (number) height of the box
+ o cx: (number) x coordinate of the center of the box
+ o cy: (number) y coordinate of the center of the box
+ o }
+ \*/
+ var pathDimensions = R.pathBBox = function(path) {
+ var pth = paths(path);
+ if (pth.bbox) {
+ return pth.bbox;
+ }
+ if (!path) {
+ return {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+ x2: 0,
+ y2: 0
+ };
+ }
+ path = path2curve(path);
+ var x = 0,
+ y = 0,
+ X = [],
+ Y = [],
+ p;
+ for (var i = 0, ii = path.length; i < ii; i++) {
+ p = path[i];
+ if (p[0] == "M") {
+ x = p[1];
+ y = p[2];
+ X.push(x);
+ Y.push(y);
+ } else {
+ var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+ X = X[concat](dim.min.x, dim.max.x);
+ Y = Y[concat](dim.min.y, dim.max.y);
+ x = p[5];
+ y = p[6];
+ }
+ }
+ var xmin = mmin[apply](0, X),
+ ymin = mmin[apply](0, Y),
+ xmax = mmax[apply](0, X),
+ ymax = mmax[apply](0, Y),
+ bb = {
+ x: xmin,
+ y: ymin,
+ x2: xmax,
+ y2: ymax,
+ width: xmax - xmin,
+ height: ymax - ymin
+ };
+ pth.bbox = clone(bb);
+ return bb;
+ },
+ pathClone = function(pathArray) {
+ var res = clone(pathArray);
+ res.toString = R._path2string;
+ return res;
+ },
+ pathToRelative = R._pathToRelative = function(pathArray) {
+ var pth = paths(pathArray);
+ if (pth.rel) {
+ return pathClone(pth.rel);
+ }
+ if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
+ pathArray = R.parsePathString(pathArray);
+ }
+ var res = [],
+ x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ start = 0;
+ if (pathArray[0][0] == "M") {
+ x = pathArray[0][1];
+ y = pathArray[0][2];
+ mx = x;
+ my = y;
+ start++;
+ res.push(["M", x, y]);
+ }
+ for (var i = start, ii = pathArray.length; i < ii; i++) {
+ var r = res[i] = [],
+ pa = pathArray[i];
+ if (pa[0] != lowerCase.call(pa[0])) {
+ r[0] = lowerCase.call(pa[0]);
+ switch (r[0]) {
+ case "a":
+ r[1] = pa[1];
+ r[2] = pa[2];
+ r[3] = pa[3];
+ r[4] = pa[4];
+ r[5] = pa[5];
+ r[6] = +(pa[6] - x).toFixed(3);
+ r[7] = +(pa[7] - y).toFixed(3);
+ break;
+ case "v":
+ r[1] = +(pa[1] - y).toFixed(3);
+ break;
+ case "m":
+ mx = pa[1];
+ my = pa[2];
+ default:
+ for (var j = 1, jj = pa.length; j < jj; j++) {
+ r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
+ }
+ }
+ } else {
+ r = res[i] = [];
+ if (pa[0] == "m") {
+ mx = pa[1] + x;
+ my = pa[2] + y;
+ }
+ for (var k = 0, kk = pa.length; k < kk; k++) {
+ res[i][k] = pa[k];
+ }
+ }
+ var len = res[i].length;
+ switch (res[i][0]) {
+ case "z":
+ x = mx;
+ y = my;
+ break;
+ case "h":
+ x += +res[i][len - 1];
+ break;
+ case "v":
+ y += +res[i][len - 1];
+ break;
+ default:
+ x += +res[i][len - 2];
+ y += +res[i][len - 1];
+ }
+ }
+ res.toString = R._path2string;
+ pth.rel = pathClone(res);
+ return res;
+ },
+ pathToAbsolute = R._pathToAbsolute = function(pathArray) {
+ var pth = paths(pathArray), res;
+ if (pth.abs) {
+ return pathClone(pth.abs);
+ }
+ if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
+ pathArray = R.parsePathString(pathArray);
+ }
+ if (!pathArray || !pathArray.length) {
+ res = ["M", 0, 0];
+ res.toString = R._path2string;
+ return res;
+ }
+ var x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ start = 0;
+ res = [];
+ if (pathArray[0][0] == "M") {
+ x = +pathArray[0][1];
+ y = +pathArray[0][2];
+ mx = x;
+ my = y;
+ start++;
+ res[0] = ["M", x, y];
+ }
+ var crz = pathArray.length == 3 && pathArray[0][0] == "M" && pathArray[1][0].toUpperCase() == "R" && pathArray[2][0].toUpperCase() == "Z";
+ for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
+ res.push(r = []);
+ pa = pathArray[i];
+ if (pa[0] != upperCase.call(pa[0])) {
+ r[0] = upperCase.call(pa[0]);
+ switch (r[0]) {
+ case "A":
+ r[1] = pa[1];
+ r[2] = pa[2];
+ r[3] = pa[3];
+ r[4] = pa[4];
+ r[5] = pa[5];
+ r[6] = +(pa[6] + x);
+ r[7] = +(pa[7] + y);
+ break;
+ case "V":
+ r[1] = +pa[1] + y;
+ break;
+ case "H":
+ r[1] = +pa[1] + x;
+ break;
+ case "R":
+ var dots = [x, y][concat](pa.slice(1));
+ for (var j = 2, jj = dots.length; j < jj; j++) {
+ dots[j] = +dots[j] + x;
+ dots[++j] = +dots[j] + y;
+ }
+ res.pop();
+ res = res[concat](catmullRom2bezier(dots, crz));
+ break;
+ case "M":
+ mx = +pa[1] + x;
+ my = +pa[2] + y;
+ default:
+ for (j = 1, jj = pa.length; j < jj; j++) {
+ r[j] = +pa[j] + ((j % 2) ? x : y);
+ }
+ }
+ } else if (pa[0] == "R") {
+ dots = [x, y][concat](pa.slice(1));
+ res.pop();
+ res = res[concat](catmullRom2bezier(dots, crz));
+ r = ["R"][concat](pa.slice(-2));
+ } else {
+ for (var k = 0, kk = pa.length; k < kk; k++) {
+ r[k] = pa[k];
+ }
+ }
+ switch (r[0]) {
+ case "Z":
+ x = mx;
+ y = my;
+ break;
+ case "H":
+ x = r[1];
+ break;
+ case "V":
+ y = r[1];
+ break;
+ case "M":
+ mx = r[r.length - 2];
+ my = r[r.length - 1];
+ default:
+ x = r[r.length - 2];
+ y = r[r.length - 1];
+ }
+ }
+ res.toString = R._path2string;
+ pth.abs = pathClone(res);
+ return res;
+ },
+ l2c = function(x1, y1, x2, y2) {
+ return [x1, y1, x2, y2, x2, y2];
+ },
+ q2c = function(x1, y1, ax, ay, x2, y2) {
+ var _13 = 1 / 3,
+ _23 = 2 / 3;
+ return [
+ _13 * x1 + _23 * ax,
+ _13 * y1 + _23 * ay,
+ _13 * x2 + _23 * ax,
+ _13 * y2 + _23 * ay,
+ x2,
+ y2
+ ];
+ },
+ a2c = function(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
+ // for more information of where this math came from visit:
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+ var _120 = PI * 120 / 180,
+ rad = deg2rad * (+angle || 0),
+ res = [],
+ xy,
+ rotate = cacher(function(x, y, rad) {
+ var X = x * mathCos(rad) - y * mathSin(rad),
+ Y = x * mathSin(rad) + y * mathCos(rad);
+ return {
+ x: X,
+ y: Y
+ };
+ });
+ if (!recursive) {
+ xy = rotate(x1, y1, -rad);
+ x1 = xy.x;
+ y1 = xy.y;
+ xy = rotate(x2, y2, -rad);
+ x2 = xy.x;
+ y2 = xy.y;
+ var cos = mathCos(deg2rad * angle),
+ sin = mathSin(deg2rad * angle),
+ x = (x1 - x2) / 2,
+ y = (y1 - y2) / 2;
+ var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
+ if (h > 1) {
+ h = mathSqrt(h);
+ rx = h * rx;
+ ry = h * ry;
+ }
+ var rx2 = rx * rx,
+ ry2 = ry * ry,
+ k = (large_arc_flag == sweep_flag ? -1 : 1) *
+ mathSqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
+ cx = k * rx * y / ry + (x1 + x2) / 2,
+ cy = k * -ry * x / rx + (y1 + y2) / 2,
+ f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
+ f2 = math.asin(((y2 - cy) / ry).toFixed(9));
+
+ f1 = x1 < cx ? PI - f1 : f1;
+ f2 = x2 < cx ? PI - f2 : f2;
+ f1 < 0 && (f1 = PI * 2 + f1);
+ f2 < 0 && (f2 = PI * 2 + f2);
+ if (sweep_flag && f1 > f2) {
+ f1 = f1 - PI * 2;
+ }
+ if (!sweep_flag && f2 > f1) {
+ f2 = f2 - PI * 2;
+ }
+ } else {
+ f1 = recursive[0];
+ f2 = recursive[1];
+ cx = recursive[2];
+ cy = recursive[3];
+ }
+ var df = f2 - f1;
+ if (abs(df) > _120) {
+ var f2old = f2,
+ x2old = x2,
+ y2old = y2;
+ f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
+ x2 = cx + rx * mathCos(f2);
+ y2 = cy + ry * mathSin(f2);
+ res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
+ }
+ df = f2 - f1;
+ var c1 = mathCos(f1),
+ s1 = mathSin(f1),
+ c2 = mathCos(f2),
+ s2 = mathSin(f2),
+ t = math.tan(df / 4),
+ hx = 4 / 3 * rx * t,
+ hy = 4 / 3 * ry * t,
+ m1 = [x1, y1],
+ m2 = [x1 + hx * s1, y1 - hy * c1],
+ m3 = [x2 + hx * s2, y2 - hy * c2],
+ m4 = [x2, y2];
+ m2[0] = 2 * m1[0] - m2[0];
+ m2[1] = 2 * m1[1] - m2[1];
+ if (recursive) {
+ return [m2, m3, m4][concat](res);
+ } else {
+ res = [m2, m3, m4][concat](res).join()[split](",");
+ var newres = [];
+ for (var i = 0, ii = res.length; i < ii; i++) {
+ newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
+ }
+ return newres;
+ }
+ },
+ findDotAtSegment = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+ var t1 = 1 - t;
+ return {
+ x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
+ y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
+ };
+ },
+ curveDim = cacher(function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
+ var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
+ b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
+ c = p1x - c1x,
+ t1 = (-b + mathSqrt(b * b - 4 * a * c)) / 2 / a,
+ t2 = (-b - mathSqrt(b * b - 4 * a * c)) / 2 / a,
+ y = [p1y, p2y],
+ x = [p1x, p2x],
+ dot;
+ abs(t1) > "1e12" && (t1 = .5);
+ abs(t2) > "1e12" && (t2 = .5);
+ if (t1 > 0 && t1 < 1) {
+ dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ if (t2 > 0 && t2 < 1) {
+ dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
+ b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
+ c = p1y - c1y;
+ t1 = (-b + mathSqrt(b * b - 4 * a * c)) / 2 / a;
+ t2 = (-b - mathSqrt(b * b - 4 * a * c)) / 2 / a;
+ abs(t1) > "1e12" && (t1 = .5);
+ abs(t2) > "1e12" && (t2 = .5);
+ if (t1 > 0 && t1 < 1) {
+ dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ if (t2 > 0 && t2 < 1) {
+ dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ return {
+ min: {
+ x: mmin[apply](0, x),
+ y: mmin[apply](0, y)
+ },
+ max: {
+ x: mmax[apply](0, x),
+ y: mmax[apply](0, y)
+ }
+ };
+ }),
+ path2curve = R._path2curve = cacher(function(path, path2) {
+ var pth = !path2 && paths(path);
+ if (!path2 && pth.curve) {
+ return pathClone(pth.curve);
+ }
+ var p = pathToAbsolute(path),
+ p2 = path2 && pathToAbsolute(path2),
+ attrs = {
+ x: 0,
+ y: 0,
+ bx: 0,
+ by: 0,
+ X: 0,
+ Y: 0,
+ qx: null,
+ qy: null
+ },
+ attrs2 = {
+ x: 0,
+ y: 0,
+ bx: 0,
+ by: 0,
+ X: 0,
+ Y: 0,
+ qx: null,
+ qy: null
+ },
+ processPath = function(path, d) {
+ var nx, ny;
+ if (!path) {
+ return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
+ }
+ !(path[0] in {
+ T: 1,
+ Q: 1
+ }) && (d.qx = d.qy = null);
+ switch (path[0]) {
+ case "M":
+ d.X = path[1];
+ d.Y = path[2];
+ break;
+ case "A":
+ path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1))));
+ break;
+ case "S":
+ nx = d.x + (d.x - (d.bx || d.x));
+ ny = d.y + (d.y - (d.by || d.y));
+ path = ["C", nx, ny][concat](path.slice(1));
+ break;
+ case "T":
+ d.qx = d.x + (d.x - (d.qx || d.x));
+ d.qy = d.y + (d.y - (d.qy || d.y));
+ path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
+ break;
+ case "Q":
+ d.qx = path[1];
+ d.qy = path[2];
+ path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
+ break;
+ case "L":
+ path = ["C"][concat](l2c(d.x, d.y, path[1], path[2]));
+ break;
+ case "H":
+ path = ["C"][concat](l2c(d.x, d.y, path[1], d.y));
+ break;
+ case "V":
+ path = ["C"][concat](l2c(d.x, d.y, d.x, path[1]));
+ break;
+ case "Z":
+ path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y));
+ break;
+ }
+ return path;
+ },
+ fixArc = function(pp, i) {
+ if (pp[i].length > 7) {
+ pp[i].shift();
+ var pi = pp[i];
+ while (pi.length) {
+ pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6)));
+ }
+ pp.splice(i, 1);
+ ii = mmax(p.length, p2 && p2.length || 0);
+ }
+ },
+ fixM = function(path1, path2, a1, a2, i) {
+ if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
+ path2.splice(i, 0, ["M", a2.x, a2.y]);
+ a1.bx = 0;
+ a1.by = 0;
+ a1.x = path1[i][1];
+ a1.y = path1[i][2];
+ ii = mmax(p.length, p2 && p2.length || 0);
+ }
+ };
+ for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
+ p[i] = processPath(p[i], attrs);
+ fixArc(p, i);
+ p2 && (p2[i] = processPath(p2[i], attrs2));
+ p2 && fixArc(p2, i);
+ fixM(p, p2, attrs, attrs2, i);
+ fixM(p2, p, attrs2, attrs, i);
+ var seg = p[i],
+ seg2 = p2 && p2[i],
+ seglen = seg.length,
+ seg2len = p2 && seg2.length;
+ attrs.x = seg[seglen - 2];
+ attrs.y = seg[seglen - 1];
+ attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
+ attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
+ attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
+ attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
+ attrs2.x = p2 && seg2[seg2len - 2];
+ attrs2.y = p2 && seg2[seg2len - 1];
+ }
+ if (!p2) {
+ pth.curve = pathClone(p);
+ }
+ return p2 ? [p, p2] : p;
+ }, null, pathClone),
+ parseDots = R._parseDots = cacher(function(gradient) {
+ var dots = [];
+ for (var i = 0, ii = gradient.length; i < ii; i++) {
+ var dot = {},
+ par = gradient[i].match(/^([^:]*):?([\d\.]*)/);
+ dot.color = R.getRGB(par[1]);
+ if (dot.color.error) {
+ return null;
+ }
+ //store opacity information
+ dot.opacity = dot.color.opacity;
+ dot.color = dot.color.hex;
+ par[2] && (dot.offset = par[2] + "%");
+ dots.push(dot);
+ }
+ for (i = 1, ii = dots.length - 1; i < ii; i++) {
+ if (!dots[i].offset) {
+ var start = toFloat(dots[i - 1].offset || 0),
+ end = 0;
+ for (var j = i + 1; j < ii; j++) {
+ if (dots[j].offset) {
+ end = dots[j].offset;
+ break;
+ }
+ }
+ if (!end) {
+ end = 100;
+ j = ii;
+ }
+ end = toFloat(end);
+ var d = (end - start) / (j - i + 1);
+ for (; i < j; i++) {
+ start += d;
+ dots[i].offset = start + "%";
+ }
+ }
+ }
+ return dots;
+ }),
+ tear = R._tear = function(el, paper) {
+ el == paper.top && (paper.top = el.prev);
+ el == paper.bottom && (paper.bottom = el.next);
+ el.next && (el.next.prev = el.prev);
+ el.prev && (el.prev.next = el.next);
+ },
+ tofront = R._tofront = function(el, paper) {
+ if (paper.top === el) {
+ return false;
+ }
+ tear(el, paper);
+ el.next = null;
+ el.prev = paper.top;
+ paper.top.next = el;
+ paper.top = el;
+ return true;
+ },
+ toback = R._toback = function(el, paper) {
+ if (paper.bottom === el) {
+ return false;
+ }
+ tear(el, paper);
+ el.next = paper.bottom;
+ el.prev = null;
+ paper.bottom.prev = el;
+ paper.bottom = el;
+ return true;
+ },
+ insertafter = R._insertafter = function(el, el2, paper, paper2) {
+ tear(el, paper);
+ el.parent = paper2;
+ el2 === paper2.top && (paper2.top = el);
+ el2.next && (el2.next.prev = el);
+ el.next = el2.next;
+ el.prev = el2;
+ el2.next = el;
+ },
+ insertbefore = R._insertbefore = function(el, el2, paper, paper2) {
+ tear(el, paper);
+ el.parent = paper2;
+ el2 === paper2.bottom && (paper2.bottom = el);
+ el2.prev && (el2.prev.next = el);
+ el.prev = el2.prev;
+ el2.prev = el;
+ el.next = el2;
+ },
+
+ /*\
+ * Raphael.toMatrix
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns matrix of transformations applied to a given path
+ > Parameters
+ - path (string) path string
+ - transform (string|array) transformation string
+ = (object) @Matrix
+ \*/
+ toMatrix = R.toMatrix = function(path, transform) {
+ var bb = pathDimensions(path),
+ el = {
+ _: {
+ transform: E
+ },
+ getBBox: function() {
+ return bb;
+ }
+ };
+ extractTransform(el, transform);
+ return el.matrix;
+ },
+
+ /*\
+ * Raphael.transformPath
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns path transformed by a given transformation
+ > Parameters
+ - path (string) path string
+ - transform (string|array) transformation string
+ = (string) path
+ \*/
+ transformPath = R.transformPath = function(path, transform) {
+ return mapPath(path, toMatrix(path, transform));
+ },
+ extractTransform = R._extractTransform = function(el, tstr) {
+ if (tstr == null) {
+ return el._.transform;
+ }
+ tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
+ var tdata = R.parseTransformString(tstr),
+ deg = 0,
+ dx = 0,
+ dy = 0,
+ sx = 1,
+ sy = 1,
+ _ = el._,
+ m = new Matrix;
+ _.transform = tdata || [];
+ if (tdata) {
+ for (var i = 0, ii = tdata.length; i < ii; i++) {
+ var t = tdata[i],
+ tlen = t.length,
+ command = Str(t[0]).toLowerCase(),
+ absolute = t[0] != command,
+ inver = absolute ? m.invert() : 0,
+ x1,
+ y1,
+ x2,
+ y2,
+ bb;
+ if (command == "t" && tlen == 3) {
+ if (absolute) {
+ x1 = inver.x(0, 0);
+ y1 = inver.y(0, 0);
+ x2 = inver.x(t[1], t[2]);
+ y2 = inver.y(t[1], t[2]);
+ m.translate(x2 - x1, y2 - y1);
+ } else {
+ m.translate(t[1], t[2]);
+ }
+ } else if (command == "r") {
+ if (tlen == 2) {
+ bb = bb || el.getBBox(1);
+ m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
+ deg += t[1];
+ } else if (tlen == 4) {
+ if (absolute) {
+ x2 = inver.x(t[2], t[3]);
+ y2 = inver.y(t[2], t[3]);
+ m.rotate(t[1], x2, y2);
+ } else {
+ m.rotate(t[1], t[2], t[3]);
+ }
+ deg += t[1];
+ }
+ } else if (command == "s") {
+ if (tlen == 2 || tlen == 3) {
+ bb = bb || el.getBBox(1);
+ m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
+ sx *= t[1];
+ sy *= t[tlen - 1];
+ } else if (tlen == 5) {
+ if (absolute) {
+ x2 = inver.x(t[3], t[4]);
+ y2 = inver.y(t[3], t[4]);
+ m.scale(t[1], t[2], x2, y2);
+ } else {
+ m.scale(t[1], t[2], t[3], t[4]);
+ }
+ sx *= t[1];
+ sy *= t[2];
+ }
+ } else if (command == "m" && tlen == 7) {
+ m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
+ }
+ _.dirtyT = 1;
+ el.matrix = m;
+ }
+ }
+
+ /*\
+ * Element.matrix
+ [ property (object) ]
+ **
+ * Keeps @Matrix object, which represents element transformation
+ \*/
+ el.matrix = m;
+
+ _.sx = sx;
+ _.sy = sy;
+ _.deg = deg;
+ _.dx = dx = m.e;
+ _.dy = dy = m.f;
+
+ if (sx == 1 && sy == 1 && !deg && _.bbox) {
+ _.bbox.x += +dx;
+ _.bbox.y += +dy;
+ } else {
+ _.dirtyT = 1;
+ }
+ },
+ getEmpty = function(item) {
+ var l = item[0];
+ switch (l.toLowerCase()) {
+ case "t":
+ return [l, 0, 0];
+ case "m":
+ return [l, 1, 0, 0, 1, 0, 0];
+ case "r":
+ if (item.length == 4) {
+ return [l, 0, item[2], item[3]];
+ } else {
+ return [l, 0];
+ }
+ case "s":
+ if (item.length == 5) {
+ return [l, 1, 1, item[3], item[4]];
+ } else if (item.length == 3) {
+ return [l, 1, 1];
+ } else {
+ return [l, 1];
+ }
+ }
+ },
+ equaliseTransform = R._equaliseTransform = function(t1, t2) {
+ t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
+ t1 = R.parseTransformString(t1) || [];
+ t2 = R.parseTransformString(t2) || [];
+ var maxlength = mmax(t1.length, t2.length),
+ from = [],
+ to = [],
+ i = 0, j, jj,
+ tt1, tt2;
+ for (; i < maxlength; i++) {
+ tt1 = t1[i] || getEmpty(t2[i]);
+ tt2 = t2[i] || getEmpty(tt1);
+ if ((tt1[0] != tt2[0]) ||
+ (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
+ (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
+ ) {
+ return;
+ }
+ from[i] = [];
+ to[i] = [];
+ for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) {
+ j in tt1 && (from[i][j] = tt1[j]);
+ j in tt2 && (to[i][j] = tt2[j]);
+ }
+ }
+ return {
+ from: from,
+ to: to
+ };
+ };
+ R._getContainer = function(x, y, w, h) {
+ var container;
+ container = h == null && !R.is(x, object) ? g.doc.getElementById(x) : x;
+ if (container == null) {
+ return;
+ }
+ if (container.tagName) {
+ if (y == null) {
+ return {
+ container: container,
+ width: container.style.pixelWidth || container.offsetWidth,
+ height: container.style.pixelHeight || container.offsetHeight
+ };
+ } else {
+ return {
+ container: container,
+ width: y,
+ height: w
+ };
+ }
+ }
+ return {
+ container: 1,
+ x: x,
+ y: y,
+ width: w,
+ height: h
+ };
+ };
+
+ /*\
+ * Raphael.pathToRelative
+ [ method ]
+ **
+ * Utility method
+ **
+ * Converts path to relative form
+ > Parameters
+ - pathString (string|array) path string or array of segments
+ = (array) array of segments.
+ \*/
+ R.pathToRelative = pathToRelative;
+ R._engine = {};
+
+ /*\
+ * Raphael.path2curve
+ [ method ]
+ **
+ * Utility method
+ **
+ * Converts path to a new path where all segments are cubic bezier curves.
+ > Parameters
+ - pathString (string|array) path string or array of segments
+ = (array) array of segments.
+ \*/
+ R.path2curve = path2curve;
+
+ /*\
+ * Raphael.matrix
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns matrix based on given parameters.
+ > Parameters
+ - a (number)
+ - b (number)
+ - c (number)
+ - d (number)
+ - e (number)
+ - f (number)
+ = (object) @Matrix
+ \*/
+ R.matrix = function(a, b, c, d, e, f) {
+ return new Matrix(a, b, c, d, e, f);
+ };
+
+ function Matrix(a, b, c, d, e, f) {
+ if (a != null) {
+ this.a = +a;
+ this.b = +b;
+ this.c = +c;
+ this.d = +d;
+ this.e = +e;
+ this.f = +f;
+ } else {
+ this.a = 1;
+ this.b = 0;
+ this.c = 0;
+ this.d = 1;
+ this.e = 0;
+ this.f = 0;
+ }
+ }
+ (function(matrixproto) {
+
+ /*\
+ * Matrix.add
+ [ method ]
+ **
+ * Adds given matrix to existing one.
+ > Parameters
+ - a (number)
+ - b (number)
+ - c (number)
+ - d (number)
+ - e (number)
+ - f (number)
+ or
+ - matrix (object) @Matrix
+ \*/
+ matrixproto.add = function(a, b, c, d, e, f) {
+ var out = [[], [], []],
+ m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
+ matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
+ x, y, z, res;
+
+ if (a && a instanceof Matrix) {
+ matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
+ }
+
+ for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++) {
+ res = 0;
+ for (z = 0; z < 3; z++) {
+ res += m[x][z] * matrix[z][y];
+ }
+ out[x][y] = res;
+ }
+ }
+ this.a = out[0][0];
+ this.b = out[1][0];
+ this.c = out[0][1];
+ this.d = out[1][1];
+ this.e = out[0][2];
+ this.f = out[1][2];
+ };
+
+ /*\
+ * Matrix.invert
+ [ method ]
+ **
+ * Returns inverted version of the matrix
+ = (object) @Matrix
+ \*/
+ matrixproto.invert = function() {
+ var me = this,
+ x = me.a * me.d - me.b * me.c;
+ return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x);
+ };
+
+ /*\
+ * Matrix.clone
+ [ method ]
+ **
+ * Returns copy of the matrix
+ = (object) @Matrix
+ \*/
+ matrixproto.clone = function() {
+ return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
+ };
+
+ /*\
+ * Matrix.translate
+ [ method ]
+ **
+ * Translate the matrix
+ > Parameters
+ - x (number)
+ - y (number)
+ \*/
+ matrixproto.translate = function(x, y) {
+ this.add(1, 0, 0, 1, x, y);
+ };
+
+ /*\
+ * Matrix.scale
+ [ method ]
+ **
+ * Scales the matrix
+ > Parameters
+ - x (number)
+ - y (number) #optional
+ - cx (number) #optional
+ - cy (number) #optional
+ \*/
+ matrixproto.scale = function(x, y, cx, cy) {
+ y == null && (y = x);
+ (cx || cy) && this.add(1, 0, 0, 1, cx, cy);
+ this.add(x, 0, 0, y, 0, 0);
+ (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
+ };
+
+ /*\
+ * Matrix.rotate
+ [ method ]
+ **
+ * Rotates the matrix
+ > Parameters
+ - a (number)
+ - x (number)
+ - y (number)
+ \*/
+ matrixproto.rotate = function(a, x, y) {
+ a = R.rad(a);
+ x = x || 0;
+ y = y || 0;
+ var cos = +mathCos(a).toFixed(9),
+ sin = + mathSin(a).toFixed(9);
+ this.add(cos, sin, -sin, cos, x, y);
+ this.add(1, 0, 0, 1, -x, -y);
+ };
+
+ /*\
+ * Matrix.x
+ [ method ]
+ **
+ * Return x coordinate for given point after transformation described by the matrix. See also @Matrix.y
+ > Parameters
+ - x (number)
+ - y (number)
+ = (number) x
+ \*/
+ matrixproto.x = function(x, y) {
+ return x * this.a + y * this.c + this.e;
+ };
+
+ /*\
+ * Matrix.y
+ [ method ]
+ **
+ * Return y coordinate for given point after transformation described by the matrix. See also @Matrix.x
+ > Parameters
+ - x (number)
+ - y (number)
+ = (number) y
+ \*/
+ matrixproto.y = function(x, y) {
+ return x * this.b + y * this.d + this.f;
+ };
+ matrixproto.get = function(i) {
+ return +this[Str.fromCharCode(97 + i)].toFixed(4);
+ };
+ matrixproto.toString = function() {
+ return R.svg ?
+ "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" :
+ [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join();
+ };
+ matrixproto.toMatrixString = function() {
+ return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")";
+ };
+ matrixproto.toFilter = function() {
+ return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) +
+ ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) +
+ ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')";
+ };
+ matrixproto.offset = function() {
+ return [this.e.toFixed(4), this.f.toFixed(4)];
+ };
+ function norm(a) {
+ return a[0] * a[0] + a[1] * a[1];
+ }
+ function normalize(a) {
+ var mag = mathSqrt(norm(a));
+ a[0] && (a[0] /= mag);
+ a[1] && (a[1] /= mag);
+ }
+
+ /*\
+ * Matrix.split
+ [ method ]
+ **
+ * Splits matrix into primitive transformations
+ = (object) in format:
+ o dx (number) translation by x
+ o dy (number) translation by y
+ o scalex (number) scale by x
+ o scaley (number) scale by y
+ o shear (number) shear
+ o rotate (number) rotation in deg
+ o isSimple (boolean) could it be represented via simple transformations
+ \*/
+ matrixproto.split = function() {
+ var out = {};
+ // translation
+ out.dx = this.e;
+ out.dy = this.f;
+
+ // scale and shear
+ var row = [[this.a, this.c], [this.b, this.d]];
+ out.scalex = mathSqrt(norm(row[0]));
+ normalize(row[0]);
+
+ out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
+ row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
+
+ out.scaley = mathSqrt(norm(row[1]));
+ normalize(row[1]);
+ out.shear /= out.scaley;
+
+ // rotation
+ var sin = -row[0][1],
+ cos = row[1][1];
+ if (cos < 0) {
+ out.rotate = R.deg(math.acos(cos));
+ if (sin < 0) {
+ out.rotate = 360 - out.rotate;
+ }
+ } else {
+ out.rotate = R.deg(math.asin(sin));
+ }
+
+ out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
+ out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
+ out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
+ return out;
+ };
+
+ /*\
+ * Matrix.toTransformString
+ [ method ]
+ **
+ * Return transform string that represents given matrix
+ = (string) transform string
+ \*/
+ matrixproto.toTransformString = function(shorter) {
+ var s = shorter || this[split]();
+ if (s.isSimple) {
+ s.scalex = +s.scalex.toFixed(4);
+ s.scaley = +s.scaley.toFixed(4);
+ s.rotate = +s.rotate.toFixed(4);
+ return (s.dx || s.dy ? "t" + [s.dx, s.dy] : E) +
+ (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) +
+ (s.rotate ? "r" + [s.rotate, 0, 0] : E);
+ } else {
+ return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
+ }
+ };
+ })(Matrix.prototype);
+
+ // WebKit rendering bug workaround method
+ var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/);
+ if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") ||
+ (navigator.vendor == "Google Inc." && version && version[1] < 8)) {
+
+ /*\
+ * Paper.safari
+ [ method ]
+ **
+ * There is an inconvenient rendering bug in Safari (WebKit):
+ * sometimes the rendering should be forced.
+ * This method should help with dealing with this bug.
+ \*/
+ paperproto.safari = function() {
+ var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({
+ stroke: "none"
+ });
+ setTimeout(function() {
+ rect.remove();
+ });
+ return true;
+ };
+ } else {
+ paperproto.safari = fun;
+ }
+
+ var preventDefault = function() {
+ this.returnValue = false;
+ },
+ preventTouch = function() {
+ return this.originalEvent.preventDefault();
+ },
+ stopPropagation = function() {
+ this.cancelBubble = true;
+ },
+ stopTouch = function() {
+ return this.originalEvent.stopPropagation();
+ },
+ addEvent = R.addEvent = (function() {
+ if (g.doc.addEventListener) {
+ return function(obj, type, fn, element) {
+ var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
+ f = function(e) {
+ var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
+ if (supportsTouch && touchMap[has](type)) {
+ for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
+ if (e.targetTouches[i].target == obj) {
+ var olde = e;
+ e = e.targetTouches[i];
+ e.originalEvent = olde;
+ e.preventDefault = preventTouch;
+ e.stopPropagation = stopTouch;
+ break;
+ }
+ }
+ }
+ return fn.call(element, e, e.clientX + scrollX, e.clientY + scrollY);
+ };
+ obj.addEventListener(realName, f, false);
+ return function() {
+ obj.removeEventListener(realName, f, false);
+ return true;
+ };
+ };
+ } else if (g.doc.attachEvent) {
+ return function(obj, type, fn, element) {
+ var f = function(e) {
+ e = e || g.win.event;
+ var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
+ x = e.clientX + scrollX,
+ y = e.clientY + scrollY;
+ e.preventDefault = e.preventDefault || preventDefault;
+ e.stopPropagation = e.stopPropagation || stopPropagation;
+ return fn.call(element, e, x, y);
+ };
+ obj.attachEvent("on" + type, f);
+ var detacher = function() {
+ obj.detachEvent("on" + type, f);
+ return true;
+ };
+ return detacher;
+ };
+ }
+ })(),
+ drag = [],
+ dragMove = function(e) {
+ var x = e.clientX,
+ y = e.clientY,
+ scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
+ dragi,
+ j = drag.length;
+ while (j--) {
+ dragi = drag[j];
+ if (supportsTouch) {
+ var i = e.touches.length,
+ touch;
+ while (i--) {
+ touch = e.touches[i];
+ if (touch.identifier == dragi.el._drag.id) {
+ x = touch.clientX;
+ y = touch.clientY;
+ (e.originalEvent ? e.originalEvent : e).preventDefault();
+ break;
+ }
+ }
+ } else {
+ e.preventDefault();
+ }
+ var node = dragi.el.node,
+ o,
+ next = node.nextSibling,
+ parent = node.parentNode,
+ display = node.style.display;
+ g.win.opera && parent.removeChild(node);
+ node.style.display = "none";
+ o = dragi.el.paper.getElementByPoint(x, y);
+ node.style.display = display;
+ g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
+ o && eve("raphael.drag.over." + dragi.el.id, dragi.el, o);
+ x += scrollX;
+ y += scrollY;
+ eve("raphael.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
+ }
+ },
+ dragUp = function(e) {
+ R.unmousemove(dragMove).unmouseup(dragUp);
+ var i = drag.length,
+ dragi;
+ while (i--) {
+ dragi = drag[i];
+ dragi.el._drag = {};
+ eve("raphael.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
+ }
+ drag = [];
+ },
+
+ /*\
+ * Raphael.el
+ [ property (object) ]
+ **
+ * You can add your own method to elements. This is usefull when you want to hack default functionality or
+ * want to wrap some common transformation or attributes in one method. In difference to canvas methods,
+ * you can redefine element method at any time. Expending element methods wouldn’t affect set.
+ > Usage
+ | Raphael.el.red = function () {
+ | this.attr({fill: "#f00"});
+ | };
+ | // then use it
+ | paper.circle(100, 100, 20).red();
+ \*/
+ elproto = R.el = {};
+
+ /*\
+ * Element.click
+ [ method ]
+ **
+ * Adds event handler for click for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unclick
+ [ method ]
+ **
+ * Removes event handler for click for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.dblclick
+ [ method ]
+ **
+ * Adds event handler for double click for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.undblclick
+ [ method ]
+ **
+ * Removes event handler for double click for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mousedown
+ [ method ]
+ **
+ * Adds event handler for mousedown for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmousedown
+ [ method ]
+ **
+ * Removes event handler for mousedown for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mousemove
+ [ method ]
+ **
+ * Adds event handler for mousemove for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmousemove
+ [ method ]
+ **
+ * Removes event handler for mousemove for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseout
+ [ method ]
+ **
+ * Adds event handler for mouseout for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseout
+ [ method ]
+ **
+ * Removes event handler for mouseout for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseover
+ [ method ]
+ **
+ * Adds event handler for mouseover for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseover
+ [ method ]
+ **
+ * Removes event handler for mouseover for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseup
+ [ method ]
+ **
+ * Adds event handler for mouseup for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseup
+ [ method ]
+ **
+ * Removes event handler for mouseup for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchstart
+ [ method ]
+ **
+ * Adds event handler for touchstart for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchstart
+ [ method ]
+ **
+ * Removes event handler for touchstart for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchmove
+ [ method ]
+ **
+ * Adds event handler for touchmove for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchmove
+ [ method ]
+ **
+ * Removes event handler for touchmove for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchend
+ [ method ]
+ **
+ * Adds event handler for touchend for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchend
+ [ method ]
+ **
+ * Removes event handler for touchend for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchcancel
+ [ method ]
+ **
+ * Adds event handler for touchcancel for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchcancel
+ [ method ]
+ **
+ * Removes event handler for touchcancel for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ for (var i = events.length; i--; ) {
+ (function(eventName) {
+ R[eventName] = elproto[eventName] = function(fn, scope) {
+ if (R.is(fn, "function")) {
+ this.events = this.events || [];
+ this.events.push({
+ name: eventName,
+ f: fn,
+ unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)
+ });
+ }
+ return this;
+ };
+ R["un" + eventName] = elproto["un" + eventName] = function(fn) {
+ var events = this.events || [],
+ l = events.length;
+ while (l--)
+ if (events[l].name == eventName && events[l].f == fn) {
+ events[l].unbind();
+ events.splice(l, 1);
+ !events.length && delete this.events;
+ return this;
+ }
+ return this;
+ };
+ })(events[i]);
+ }
+
+ /*\
+ * Element.data
+ [ method ]
+ **
+ * Adds or retrieves given value asociated with given key.
+ **
+ * See also @Element.removeData
+ > Parameters
+ - key (string) key to store data
+ - value (any) #optional value to store
+ = (object) @Element
+ * or, if value is not specified:
+ = (any) value
+ > Usage
+ | for (var i = 0, i < 5, i++) {
+ | paper.circle(10 + 15 * i, 10, 10)
+ | .attr({fill: "#000"})
+ | .data("i", i)
+ | .click(function () {
+ | alert(this.data("i"));
+ | });
+ | }
+ \*/
+ elproto.data = function(key, value) {
+ var data = eldata[this.id] = eldata[this.id] || {};
+ if (arguments.length == 1) {
+ if (R.is(key, object)) {
+ for (var i in key)
+ if (key[has](i)) {
+ this.data(i, key[i]);
+ }
+ return this;
+ }
+ eve("raphael.data.get." + this.id, this, data[key], key);
+ return data[key];
+ }
+ data[key] = value;
+ eve("raphael.data.set." + this.id, this, value, key);
+ return this;
+ };
+
+ /*\
+ * Element.removeData
+ [ method ]
+ **
+ * Removes value associated with an element by given key.
+ * If key is not provided, removes all the data of the element.
+ > Parameters
+ - key (string) #optional key
+ = (object) @Element
+ \*/
+ elproto.removeData = function(key) {
+ if (key == null) {
+ eldata[this.id] = {};
+ } else {
+ eldata[this.id] && delete eldata[this.id][key];
+ }
+ return this;
+ };
+
+ /*\
+ * Element.getData
+ [ method ]
+ **
+ * Retrieves the element data
+ = (object) data
+ \*/
+ elproto.getData = function () {
+ return clone(eldata[this.id] || {});
+ };
+
+ var downables = [],
+ mouseDown = function () {
+ this.untrack = addEvent(g.doc, 'mouseup', mouseUp, this);
+ },
+ mouseUp = function () {
+ this.untrack();
+ this.untrack = null;
+ return this.fn && this.fn.apply(this.scope || this.el, arguments);
+
+ };
+ elproto.mouseup = function (fn, scope, track) {
+ if (!track) {
+ return R.mouseup.apply(this, arguments);
+ }
+ downables.push(track = {
+ el: this,
+ fn: fn,
+ scope: scope
+ });
+ track.unbind = addEvent(this.shape || this.node || g.doc,
+ 'mousedown', mouseDown, track);
+
+ return this;
+ };
+
+ elproto.unmouseup = function (fn) {
+ var i = downables.length,
+ undowned;
+ while (i--) {
+ if (downables[i].el === this && downables[i].fn === fn) {
+ undowned = downables[i];
+ undowned.unbind();
+ undowned.untrack && undowned.untrack();
+ downables.splice(i, 1);
+ }
+ }
+ return undowned ? this : R.unmouseup.apply(this, arguments);
+ };
+
+ /*\
+ * Element.hover
+ [ method ]
+ **
+ * Adds event handlers for hover for the element.
+ > Parameters
+ - f_in (function) handler for hover in
+ - f_out (function) handler for hover out
+ - icontext (object) #optional context for hover in handler
+ - ocontext (object) #optional context for hover out handler
+ = (object) @Element
+ \*/
+ elproto.hover = function(f_in, f_out, scope_in, scope_out) {
+ return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
+ };
+
+ /*\
+ * Element.unhover
+ [ method ]
+ **
+ * Removes event handlers for hover for the element.
+ > Parameters
+ - f_in (function) handler for hover in
+ - f_out (function) handler for hover out
+ = (object) @Element
+ \*/
+ elproto.unhover = function(f_in, f_out) {
+ return this.unmouseover(f_in).unmouseout(f_out);
+ };
+ var draggable = [];
+
+ /*\
+ * Element.drag
+ [ method ]
+ **
+ * Adds event handlers for drag of the element.
+ > Parameters
+ - onmove (function) handler for moving
+ - onstart (function) handler for drag start
+ - onend (function) handler for drag end
+ - mcontext (object) #optional context for moving handler
+ - scontext (object) #optional context for drag start handler
+ - econtext (object) #optional context for drag end handler
+ * Additionaly following `drag` events will be triggered: `drag.start.` on start,
+ * `drag.end.` on end and `drag.move.` on every move. When element will be dragged over another element
+ * `drag.over.` will be fired as well.
+ *
+ * Start event and start handler will be called in specified context or in context of the element with following parameters:
+ o x (number) x position of the mouse
+ o y (number) y position of the mouse
+ o event (object) DOM event object
+ * Move event and move handler will be called in specified context or in context of the element with following parameters:
+ o dx (number) shift by x from the start point
+ o dy (number) shift by y from the start point
+ o x (number) x position of the mouse
+ o y (number) y position of the mouse
+ o event (object) DOM event object
+ * End event and end handler will be called in specified context or in context of the element with following parameters:
+ o event (object) DOM event object
+ = (object) @Element
+ \*/
+ elproto.drag = function(onmove, onstart, onend, move_scope, start_scope, end_scope) {
+ function start(e) {
+ (e.originalEvent || e).preventDefault();
+ var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
+ this._drag.x = e.clientX + scrollX;
+ this._drag.y = e.clientY + scrollY;
+ this._drag.id = e.identifier;
+ !drag.length && R.mousemove(dragMove).mouseup(dragUp);
+ drag.push({
+ el: this,
+ move_scope: move_scope,
+ start_scope: start_scope,
+ end_scope: end_scope
+ });
+ onstart && eve.on("raphael.drag.start." + this.id, onstart);
+ onmove && eve.on("raphael.drag.move." + this.id, onmove);
+ onend && eve.on("raphael.drag.end." + this.id, onend);
+ eve("raphael.drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
+ }
+ this._drag = {};
+ draggable.push({
+ el: this,
+ start: start
+ });
+ this.mousedown(start);
+ return this;
+ };
+
+ /*\
+ * Element.onDragOver
+ [ method ]
+ **
+ * Shortcut for assigning event handler for `drag.over.` event, where id is id of the element (see @Element.id).
+ > Parameters
+ - f (function) handler for event, first argument would be the element you are dragging over
+ \*/
+ elproto.onDragOver = function(f) {
+ f ? eve.on("raphael.drag.over." + this.id, f) : eve.unbind("raphael.drag.over." + this.id);
+ };
+
+ /*\
+ * Element.undrag
+ [ method ]
+ **
+ * Removes all drag event handlers from given element.
+ \*/
+ elproto.undrag = function() {
+ var i = draggable.length;
+ while (i--)
+ if (draggable[i].el == this) {
+ this.unmousedown(draggable[i].start);
+ draggable.splice(i, 1);
+ eve.unbind("raphael.drag.*." + this.id);
+ }
+ !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp);
+ };
+
+ elproto.follow = function(el, callback, stalk) {
+ if (el.removed || el.constructor !== R.el.constructor) {
+ return this;
+ }
+ el.followers.push({
+ el: this,
+ stalk: (stalk = {before: 'insertBefore', after: 'insertAfter'}[stalk]),
+ cb: callback
+ });
+
+ stalk && this[stalk](el);
+ return this;
+ };
+
+ elproto.unfollow = function(el) {
+ if (el.removed || el.constructor !== R.el.constructor) {
+ return this;
+ }
+ for (var i = 0, ii = el.followers.length; i < ii; i++) {
+ if (el.followers[i].el === this) {
+ el.followers.splice(i, 1);
+ break;
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Paper.hide
+ [ method ]
+ **
+ * Hides a paper
+ **
+ > Usage
+ | paper.hide();
+ \*/
+ paperproto.hide = function () {
+ var paper = this;
+ paper.canvas.style.visibility = "hidden";
+ return paper;
+ };
+
+ /*\
+ * Paper.show
+ [ method ]
+ **
+ * Shows a hidden paper
+ **
+ > Usage
+ | paper.show();
+ \*/
+ paperproto.show = function () {
+ var paper = this;
+ paper.canvas.style.visibility = E;
+ return paper;
+ };
+
+ /*\
+ * Paper.group
+ [ method ]
+ **
+ * Creates a group
+ **
+ > Parameters
+ **
+ - id (number) id of the group
+ = (object) Raphaël element object with type “group”
+ **
+ > Usage
+ | var g = paper.group();
+ \*/
+ paperproto.group = function () { // id
+ var paper = this,
+ out,
+ args = arguments,
+ group = lastArgIfGroup(args, true);
+
+ out = R._engine.group(paper, args[0], group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.circle
+ [ method ]
+ **
+ * Draws a circle.
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the centre
+ - y (number) y coordinate of the centre
+ - r (number) radius
+ = (object) Raphaël element object with type “circle”
+ **
+ > Usage
+ | var c = paper.circle(50, 50, 40);
+ \*/
+ paperproto.circle = function () { // x, y, r
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.circle(paper, args[0] || 0, args[1] || 0,
+ args[2] || 0, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+
+ /*\
+ * Paper.rect
+ [ method ]
+ *
+ * Draws a rectangle.
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the top left corner
+ - y (number) y coordinate of the top left corner
+ - width (number) width
+ - height (number) height
+ - r (number) #optional radius for rounded corners, default is 0
+ = (object) Raphaël element object with type “rect”
+ **
+ > Usage
+ | // regular rectangle
+ | var c = paper.rect(10, 10, 50, 50);
+ | // rectangle with rounded corners
+ | var c = paper.rect(40, 40, 50, 50, 10);
+ \*/
+ paperproto.rect = function () {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.rect(paper, args[0] || 0, args[1] || 0, args[2] || 0,
+ args[3] || 0, args[4] || 0, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.ellipse
+ [ method ]
+ **
+ * Draws an ellipse.
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the centre
+ - y (number) y coordinate of the centre
+ - rx (number) horizontal radius
+ - ry (number) vertical radius
+ = (object) Raphaël element object with type “ellipse”
+ **
+ > Usage
+ | var c = paper.ellipse(50, 50, 40, 20);
+ \*/
+ paperproto.ellipse = function () {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.ellipse(this, args[0] || 0, args[1] || 0,
+ args[2] || 0, args[3] || 0, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.path
+ [ method ]
+ **
+ * Creates a path element by given path data string.
+ > Parameters
+ - pathString (string) #optional path string in SVG format.
+ * Path string consists of one-letter commands, followed by comma seprarated arguments in numercal form. Example:
+ | "M10,20L30,40"
+ * Here we can see two commands: “M”, with arguments `(10, 20)` and “L” with arguments `(30, 40)`. Upper case letter mean command is absolute, lower case—relative.
+ *
+ # Here is short list of commands available, for more details see SVG path string format .
+ # Command Name Parameters
+ # M moveto (x y)+
+ # Z closepath (none)
+ # L lineto (x y)+
+ # H horizontal lineto x+
+ # V vertical lineto y+
+ # C curveto (x1 y1 x2 y2 x y)+
+ # S smooth curveto (x2 y2 x y)+
+ # Q quadratic Bézier curveto (x1 y1 x y)+
+ # T smooth quadratic Bézier curveto (x y)+
+ # A elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
+ # R Catmull-Rom curveto *x1 y1 (x y)+
+ * * “Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier.
+ * Note: there is a special case when path consist of just three commands: “M10,10R…z”. In this case path will smoothly connects to its beginning.
+ > Usage
+ | var c = paper.path("M10 10L90 90");
+ | // draw a diagonal line:
+ | // move to 10,10, line to 90,90
+ * For example of path strings, check out these icons: http://raphaeljs.com/icons/
+ \*/
+ paperproto.path = function () {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ pathString,
+ out;
+
+ pathString = args[0];
+ pathString && !R.is(pathString, string) &&
+ !R.is(pathString[0], array) && (pathString += E);
+
+ out = R._engine.path(R.format[apply](R, arguments), paper, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.image
+ [ method ]
+ **
+ * Embeds an image into the surface.
+ **
+ > Parameters
+ **
+ - src (string) URI of the source image
+ - x (number) x coordinate position
+ - y (number) y coordinate position
+ - width (number) width of the image
+ - height (number) height of the image
+ = (object) Raphaël element object with type “image”
+ **
+ > Usage
+ | var c = paper.image("apple.png", 10, 10, 80, 80);
+ \*/
+ paperproto.image = function () {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.image(paper, args[0] || "about:blank", args[1] || 0,
+ args[2] || 0, args[3] || 0, args[4] || 0, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.text
+ [ method ]
+ **
+ * Draws a text string. If you need line breaks, put “\n” in the string.
+ **
+ > Parameters
+ **
+ - x (number) x coordinate position
+ - y (number) y coordinate position
+ - text (string) The text string to draw
+ = (object) Raphaël element object with type “text”
+ **
+ > Usage
+ | var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!");
+ \*/
+ paperproto.text = function() {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.text(paper, args[0] || 0, args[1] || 0, Str(args[2] || E),
+ group);
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.set
+ [ method ]
+ **
+ * Creates array-like object to keep and operate several elements at once.
+ * Warning: it doesn’t create any elements for itself in the page, it just groups existing elements.
+ * Sets act as pseudo elements — all methods available to an element can be used on a set.
+ = (object) array-like object that represents set of elements
+ **
+ > Usage
+ | var st = paper.set();
+ | st.push(
+ | paper.circle(10, 10, 5),
+ | paper.circle(30, 10, 5)
+ | );
+ | st.attr({fill: "red"}); // changes the fill of both circles
+ \*/
+ paperproto.set = function(itemsArray) {
+ !R.is(itemsArray, "array") && (itemsArray = arraySplice.call(arguments, 0, arguments.length));
+ var out = new Set(itemsArray);
+ this.__set__ && this.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.setStart
+ [ method ]
+ **
+ * Creates @Paper.set. All elements that will be created after calling this method and before calling
+ * @Paper.setFinish will be added to the set.
+ **
+ > Usage
+ | paper.setStart();
+ | paper.circle(10, 10, 5),
+ | paper.circle(30, 10, 5)
+ | var st = paper.setFinish();
+ | st.attr({fill: "red"}); // changes the fill of both circles
+ \*/
+ paperproto.setStart = function(set) {
+ this.__set__ = set || this.set();
+ };
+
+ /*\
+ * Paper.setFinish
+ [ method ]
+ **
+ * See @Paper.setStart. This method finishes catching and returns resulting set.
+ **
+ = (object) set
+ \*/
+ paperproto.setFinish = function(set) {
+ var out = this.__set__;
+ delete this.__set__;
+ return out;
+ };
+
+ /*\
+ * Paper.setSize
+ [ method ]
+ **
+ * If you need to change dimensions of the canvas call this method
+ **
+ > Parameters
+ **
+ - width (number) new width of the canvas
+ - height (number) new height of the canvas
+ \*/
+ paperproto.setSize = function(width, height) {
+ return R._engine.setSize.call(this, width, height);
+ };
+
+ /*\
+ * Paper.setViewBox
+ [ method ]
+ **
+ * Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by
+ * specifying new boundaries.
+ **
+ > Parameters
+ **
+ - x (number) new x position, default is `0`
+ - y (number) new y position, default is `0`
+ - w (number) new width of the canvas
+ - h (number) new height of the canvas
+ - fit (boolean) `true` if you want graphics to fit into new boundary box
+ \*/
+ paperproto.setViewBox = function(x, y, w, h, fit) {
+ return R._engine.setViewBox.call(this, x, y, w, h, fit);
+ };
+
+ /*\
+ * Paper.top
+ [ property ]
+ **
+ * Points to the topmost element on the paper
+ \*/
+ /*\
+ * Paper.bottom
+ [ property ]
+ **
+ * Points to the bottom element on the paper
+ \*/
+ paperproto.top = paperproto.bottom = null;
+
+ /*\
+ * Paper.raphael
+ [ property ]
+ **
+ * Points to the @Raphael object/function
+ \*/
+ paperproto.raphael = R;
+
+ var getOffset = function(elem) {
+ var box = elem.getBoundingClientRect(),
+ doc = elem.ownerDocument,
+ body = doc.body,
+ docElem = doc.documentElement,
+ clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop) - clientTop,
+ left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
+ return {
+ y: top,
+ x: left
+ };
+ };
+
+ /*\
+ * Paper.getElementByPoint
+ [ method ]
+ **
+ * Returns you topmost element under given point.
+ **
+ = (object) Raphaël element object
+ > Parameters
+ **
+ - x (number) x coordinate from the top left corner of the window
+ - y (number) y coordinate from the top left corner of the window
+ > Usage
+ | paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
+ \*/
+ paperproto.getElementByPoint = function(x, y) {
+ var paper = this,
+ svg = paper.canvas,
+ target = g.doc.elementFromPoint(x, y);
+ if (g.win.opera && target.tagName == "svg") {
+ var so = getOffset(svg),
+ sr = svg.createSVGRect();
+ sr.x = x - so.x;
+ sr.y = y - so.y;
+ sr.width = sr.height = 1;
+ var hits = svg.getIntersectionList(sr, null);
+ if (hits.length) {
+ target = hits[hits.length - 1];
+ }
+ }
+ if (!target) {
+ return null;
+ }
+ while (target.parentNode && target != svg.parentNode && !target.raphael) {
+ target = target.parentNode;
+ }
+ target == paper.canvas.parentNode && (target = svg);
+ target = target && target.raphael ? paper.getById(target.raphaelid) : null;
+ return target;
+ };
+
+ /*\
+ * Paper.getElementsByBBox
+ [ method ]
+ **
+ * Returns set of elements that have an intersecting bounding box
+ **
+ > Parameters
+ **
+ - bbox (object) bbox to check with
+ = (object) @Set
+ \*/
+ paperproto.getElementsByBBox = function (bbox) {
+ var set = this.set();
+ this.forEach(function (el) {
+ if (R.isBBoxIntersect(el.getBBox(), bbox)) {
+ set.push(el);
+ }
+ });
+ return set;
+ };
+
+ paperproto.getById = function(id) {
+ var bot = this.bottom;
+ while (bot) {
+ if (bot.id == id) {
+ return bot;
+ }
+ bot = bot.next;
+ }
+ return null;
+ };
+
+ /*\
+ * Paper.forEach
+ [ method ]
+ **
+ * Executes given function for each element on the paper
+ *
+ * If callback function returns `false` it will stop loop running.
+ **
+ > Parameters
+ **
+ - callback (function) function to run
+ - thisArg (object) context object for the callback
+ = (object) Paper object
+ > Usage
+ | paper.forEach(function (el) {
+ | el.attr({ stroke: "blue" });
+ | });
+ \*/
+ paperproto.forEach = function(callback, thisArg) {
+ var bot = this.bottom;
+ while (bot) {
+ if (callback.call(thisArg, bot) === false) {
+ return this;
+ }
+ bot = bot.next;
+ }
+ return this;
+ };
+
+ /*\
+ * Paper.getElementsByPoint
+ [ method ]
+ **
+ * Returns set of elements that have common point inside
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the point
+ - y (number) y coordinate of the point
+ = (object) @Set
+ \*/
+ paperproto.getElementsByPoint = function(x, y) {
+ var set = this.set();
+ this.forEach(function(el) {
+ if (el.isPointInside(x, y)) {
+ set.push(el);
+ }
+ });
+ return set;
+ };
+ function x_y() {
+ return this.x + S + this.y;
+ }
+ function x_y_w_h() {
+ return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
+ }
+
+ /*\
+ * Element.isPointInside
+ [ method ]
+ **
+ * Determine if given point is inside this element’s shape
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the point
+ - y (number) y coordinate of the point
+ = (boolean) `true` if point inside the shape
+ \*/
+ elproto.isPointInside = function(x, y) {
+ var rp = this.realPath = this.realPath || getPath[this.type](this),
+ tr;
+ return R.isPointInsidePath(((tr = this.attr('transform')) &&
+ tr.length && R.transformPath(rp, tr)) || rp, x, y);
+ };
+
+ /*\
+ * Element.getBBox
+ [ method ]
+ **
+ * Return bounding box for a given element
+ **
+ > Parameters
+ **
+ - isWithoutTransform (boolean) flag, `true` if you want to have bounding box before transformations. Default is `false`.
+ = (object) Bounding box object:
+ o {
+ o x: (number) top left corner x
+ o y: (number) top left corner y
+ o x2: (number) bottom right corner x
+ o y2: (number) bottom right corner y
+ o width: (number) width
+ o height: (number) height
+ o }
+ \*/
+ elproto.getBBox = function(isWithoutTransform) {
+ if (this.removed) {
+ return {};
+ }
+ var _ = this._;
+ if (isWithoutTransform) {
+ if (_.dirty || !_.bboxwt) {
+ this.realPath = getPath[this.type](this);
+ _.bboxwt = pathDimensions(this.realPath);
+ _.bboxwt.toString = x_y_w_h;
+ _.dirty = 0;
+ }
+ return _.bboxwt;
+ }
+ if (_.dirty || _.dirtyT || !_.bbox) {
+ if (_.dirty || !this.realPath) {
+ _.bboxwt = 0;
+ this.realPath = getPath[this.type](this);
+ }
+ _.bbox = pathDimensions(mapPath(this.realPath, this.matrix));
+ _.bbox.toString = x_y_w_h;
+ _.dirty = _.dirtyT = 0;
+ }
+ return _.bbox;
+ };
+
+ /*\
+ * Element.clone
+ [ method ]
+ **
+ = (object) clone of a given element
+ **
+ \*/
+ elproto.clone = function() {
+ if (this.removed) {
+ return null;
+ }
+ var o = this,
+ out = o.paper[o.type]().attr(o.attr());
+ o.__set__ && o.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Element.glow
+ [ method ]
+ **
+ * Return set of elements that create glow-like effect around given element. See @Paper.set.
+ *
+ * Note: Glow is not connected to the element. If you change element attributes it won’t adjust itself.
+ **
+ > Parameters
+ **
+ - glow (object) #optional parameters object with all properties optional:
+ o {
+ o width (number) size of the glow, default is `10`
+ o fill (boolean) will it be filled, default is `false`
+ o opacity (number) opacity, default is `0.5`
+ o offsetx (number) horizontal offset, default is `0`
+ o offsety (number) vertical offset, default is `0`
+ o color (string) glow colour, default is `black`
+ o }
+ = (object) @Paper.set of elements that represents glow
+ \*/
+ elproto.glow = function(glow) {
+ if (this.type == "text") {
+ return null;
+ }
+ glow = glow || {};
+ var s = {
+ width: (glow.width || 10) + (+this.attr("stroke-width") || 1),
+ fill: glow.fill || false,
+ opacity: glow.opacity || .5,
+ offsetx: glow.offsetx || 0,
+ offsety: glow.offsety || 0,
+ color: glow.color || "#000"
+ },
+ c = s.width / 2,
+ r = this.paper,
+ out = r.set(),
+ path = this.realPath || getPath[this.type](this);
+ path = this.matrix ? mapPath(path, this.matrix) : path;
+ for (var i = 1; i < c + 1; i++) {
+ out.push(r.path(path).attr({
+ stroke: s.color,
+ fill: s.fill ? s.color : "none",
+ "stroke-linejoin": "round",
+ "stroke-linecap": "round",
+ "stroke-width": +(s.width / c * i).toFixed(3),
+ opacity: +(s.opacity / c).toFixed(3)
+ }));
+ }
+ return out.insertBefore(this).translate(s.offsetx, s.offsety);
+ };
+ var curveslengths = {},
+ getPointAtSegmentLength = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
+ if (length == null) {
+ return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
+ } else {
+ return R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, getTatLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length));
+ }
+ },
+ getLengthFactory = function(istotal, subpath) {
+ return function(path, length, onlystart) {
+ path = path2curve(path);
+ var x, y, p, l, sp = "", subpaths = {}, point,
+ len = 0;
+ for (var i = 0, ii = path.length; i < ii; i++) {
+ p = path[i];
+ if (p[0] == "M") {
+ x = +p[1];
+ y = +p[2];
+ } else {
+ l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+ if (len + l > length) {
+ if (subpath && !subpaths.start) {
+ point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
+ sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];
+ if (onlystart) {
+ return sp;
+ }
+ subpaths.start = sp;
+ sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join();
+ len += l;
+ x = +p[5];
+ y = +p[6];
+ continue;
+ }
+ if (!istotal && !subpath) {
+ point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
+ return {
+ x: point.x,
+ y: point.y,
+ alpha: point.alpha
+ };
+ }
+ }
+ len += l;
+ x = +p[5];
+ y = +p[6];
+ }
+ sp += p.shift() + p;
+ }
+ subpaths.end = sp;
+ point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
+ point.alpha && (point = {
+ x: point.x,
+ y: point.y,
+ alpha: point.alpha
+ });
+ return point;
+ };
+ };
+ var getTotalLength = getLengthFactory(1),
+ getPointAtLength = getLengthFactory(),
+ getSubpathsAtLength = getLengthFactory(0, 1);
+
+ R.getTotalLength = getTotalLength;
+
+ R.getPointAtLength = getPointAtLength;
+
+ R.getSubpath = function(path, from, to) {
+ if (this.getTotalLength(path) - to < 1e-6) {
+ return getSubpathsAtLength(path, from).end;
+ }
+ var a = getSubpathsAtLength(path, to, 1);
+ return from ? getSubpathsAtLength(a, from).end : a;
+ };
+
+ /*\
+ * Raphael.getTotalLength
+ [ method ]
+ **
+ * Returns length of the given path in pixels.
+ **
+ > Parameters
+ **
+ - path (string) SVG path string.
+ **
+ = (number) length.
+ \*/
+ elproto.getTotalLength = function() {
+ if (this.type != "path") {
+ return;
+ }
+ if (this.node.getTotalLength) {
+ return this.node.getTotalLength();
+ }
+ return getTotalLength(this.attrs.path);
+ };
+
+ /*\
+ * Raphael.getPointAtLength
+ [ method ]
+ **
+ * Return coordinates of the point located at the given length on the given path.
+ **
+ > Parameters
+ **
+ - path (string) SVG path string
+ - length (number)
+ **
+ = (object) representation of the point:
+ o {
+ o x: (number) x coordinate
+ o y: (number) y coordinate
+ o alpha: (number) angle of derivative
+ o }
+ \*/
+ elproto.getPointAtLength = function(length) {
+ if (this.type != "path") {
+ return;
+ }
+ return getPointAtLength(this.attrs.path, length);
+ };
+
+ /*\
+ * Raphael.getSubpath
+ [ method ]
+ **
+ * Return subpath of a given path from given length to given length.
+ **
+ > Parameters
+ **
+ - path (string) SVG path string
+ - from (number) position of the start of the segment
+ - to (number) position of the end of the segment
+ **
+ = (string) pathstring for the segment
+ \*/
+ elproto.getSubpath = function(from, to) {
+ if (this.type != "path") {
+ return;
+ }
+ return R.getSubpath(this.attrs.path, from, to);
+ };
+
+ /*\
+ * Raphael.easing_formulas
+ [ property ]
+ **
+ * Object that contains easing formulas for animation. You could extend it with your own. By default it has following list of easing:
+ #
+ # “linear”
+ # “<” or “easeIn” or “ease-in”
+ # “>” or “easeOut” or “ease-out”
+ # “<>” or “easeInOut” or “ease-in-out”
+ # “backIn” or “back-in”
+ # “backOut” or “back-out”
+ # “elastic”
+ # “bounce”
+ #
+ # See also Easing demo .
+ \*/
+ var ef = R.easing_formulas = {
+ linear: function(n) {
+ return n;
+ },
+ "<": function(n) {
+ return pow(n, 1.7);
+ },
+ ">": function(n) {
+ return pow(n, .48);
+ },
+ "<>": function(n) {
+ var q = .48 - n / 1.04,
+ Q = mathSqrt(.1734 + q * q),
+ x = Q - q,
+ X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
+ y = -Q - q,
+ Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
+ t = X + Y + .5;
+ return (1 - t) * 3 * t * t + t * t * t;
+ },
+ backIn: function(n) {
+ var s = 1.70158;
+ return n * n * ((s + 1) * n - s);
+ },
+ backOut: function(n) {
+ n = n - 1;
+ var s = 1.70158;
+ return n * n * ((s + 1) * n + s) + 1;
+ },
+ elastic: function(n) {
+ if (n == !!n) {
+ return n;
+ }
+ return pow(2, -10 * n) * mathSin((n - .075) * (2 * PI) / .3) + 1;
+ },
+ bounce: function(n) {
+ var s = 7.5625,
+ p = 2.75,
+ l;
+ if (n < (1 / p)) {
+ l = s * n * n;
+ } else {
+ if (n < (2 / p)) {
+ n -= (1.5 / p);
+ l = s * n * n + .75;
+ } else {
+ if (n < (2.5 / p)) {
+ n -= (2.25 / p);
+ l = s * n * n + .9375;
+ } else {
+ n -= (2.625 / p);
+ l = s * n * n + .984375;
+ }
+ }
+ }
+ return l;
+ }
+ };
+ ef.easeIn = ef["ease-in"] = ef["<"];
+ ef.easeOut = ef["ease-out"] = ef[">"];
+ ef.easeInOut = ef["ease-in-out"] = ef["<>"];
+ ef["back-in"] = ef.backIn;
+ ef["back-out"] = ef.backOut;
+
+ var animationElements = [],
+ requestAnimFrame = window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback) {
+ setTimeout(callback, 16);
+ },
+ animation = function() {
+ var Now = +new Date,
+ l = 0;
+ for (; l < animationElements.length; l++) {
+ var e = animationElements[l];
+ if (e.el.removed || e.paused) {
+ continue;
+ }
+ var time = Now - e.start,
+ ms = e.ms,
+ easing = e.easing,
+ from = e.from,
+ diff = e.diff,
+ to = e.to,
+ t = e.t,
+ that = e.el,
+ set = {},
+ now,
+ init = {},
+ key;
+ if (e.initstatus) {
+ time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms;
+ e.status = e.initstatus;
+ delete e.initstatus;
+ e.stop && animationElements.splice(l--, 1);
+ } else {
+ e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top;
+ }
+ if (time < 0) {
+ continue;
+ }
+ if (time < ms) {
+ var pos = easing(time / ms);
+ for (var attr in from)
+ if (from[has](attr)) {
+ switch (availableAnimAttrs[attr]) {
+ case nu:
+ now = +from[attr] + pos * ms * diff[attr];
+ break;
+ case "colour":
+ now = "rgb(" + [
+ upto255(round(from[attr].r + pos * ms * diff[attr].r)),
+ upto255(round(from[attr].g + pos * ms * diff[attr].g)),
+ upto255(round(from[attr].b + pos * ms * diff[attr].b))
+ ].join(",") + ")";
+ break;
+ case "path":
+ now = [];
+ for (var i = 0, ii = from[attr].length; i < ii; i++) {
+ now[i] = [from[attr][i][0]];
+ for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
+ now[i][j] = (+from[attr][i][j] + pos * ms * diff[attr][i][j]).toFixed(4);
+ }
+ now[i] = now[i].join(S);
+ }
+ now = now.join(S);
+ break;
+ case "transform":
+ if (diff[attr].real) {
+ now = [];
+ for (i = 0, ii = from[attr].length; i < ii; i++) {
+ now[i] = [from[attr][i][0]];
+ for (j = 1, jj = from[attr][i].length; j < jj; j++) {
+ now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j];
+ }
+ }
+ } else {
+ var get = function(i) {
+ return +from[attr][i] + pos * ms * diff[attr][i];
+ };
+ // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]];
+ now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]];
+ }
+ break;
+ case "csv":
+ if (attr == "clip-rect") {
+ now = [];
+ i = 4;
+ while (i--) {
+ now[i] = +from[attr][i] + pos * ms * diff[attr][i];
+ }
+ }
+ break;
+ default:
+ var from2 = [][concat](from[attr]);
+ now = [];
+ i = that.ca[attr].length;
+ while (i--) {
+ now[i] = +from2[i] + pos * ms * diff[attr][i];
+ }
+ break;
+ }
+ set[attr] = now;
+ }
+ that.attr(set);
+ (function(id, that, anim) {
+ setTimeout(function() {
+ eve("raphael.anim.frame." + id, that, anim);
+ });
+ })(that.id, that, e.anim);
+ } else {
+ (function(f, el, a) {
+ setTimeout(function() {
+ eve("raphael.anim.frame." + el.id, el, a);
+ eve("raphael.anim.finish." + el.id, el, a);
+ R.is(f, "function") && f.call(el);
+ });
+ })(e.callback, that, e.anim);
+ that.attr(to);
+ animationElements.splice(l--, 1);
+ if (e.repeat > 1 && !e.next) {
+ for (key in to)
+ if (to[has](key)) {
+ init[key] = e.totalOrigin[key];
+ }
+ e.el.attr(init);
+ runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1);
+ }
+ if (e.next && !e.stop) {
+ runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat);
+ }
+ }
+ }
+ R.svg && that && that.paper && that.paper.safari();
+ animationElements.length && requestAnimFrame(animation);
+ },
+ upto255 = function(color) {
+ return color > 255 ? 255 : color < 0 ? 0 : color;
+ };
+
+ /*\
+ * Element.animateWith
+ [ method ]
+ **
+ * Acts similar to @Element.animate, but ensure that given animation runs in sync with another given element.
+ **
+ > Parameters
+ **
+ - el (object) element to sync with
+ - anim (object) animation to sync with
+ - params (object) #optional final attributes for the element, see also @Element.attr
+ - ms (number) #optional number of milliseconds for animation to run
+ - easing (string) #optional easing type. Accept on of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)`
+ - callback (function) #optional callback function. Will be called at the end of animation.
+ * or
+ - element (object) element to sync with
+ - anim (object) animation to sync with
+ - animation (object) #optional animation object, see @Raphael.animation
+ **
+ = (object) original element
+ \*/
+ elproto.animateWith = function(el, anim, params, ms, easing, callback) {
+ var element = this;
+ if (element.removed) {
+ callback && callback.call(element);
+ return element;
+ }
+ var a = params instanceof Animation ? params : R.animation(params, ms, easing, callback),
+ x, y;
+ runAnimation(a, element, a.percents[0], null, element.attr());
+ for (var i = 0, ii = animationElements.length; i < ii; i++) {
+ if (animationElements[i].anim == anim && animationElements[i].el == el) {
+ animationElements[ii - 1].start = animationElements[i].start;
+ break;
+ }
+ }
+ return element;
+ //
+ //
+ // var a = params ? R.animation(params, ms, easing, callback) : anim,
+ // status = element.status(anim);
+ // return this.animate(a).status(a, status * anim.ms / a.ms);
+ };
+ function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) {
+ var cx = 3 * p1x,
+ bx = 3 * (p2x - p1x) - cx,
+ ax = 1 - cx - bx,
+ cy = 3 * p1y,
+ by = 3 * (p2y - p1y) - cy,
+ ay = 1 - cy - by;
+ function sampleCurveX(t) {
+ return ((ax * t + bx) * t + cx) * t;
+ }
+ function solve(x, epsilon) {
+ var t = solveCurveX(x, epsilon);
+ return ((ay * t + by) * t + cy) * t;
+ }
+ function solveCurveX(x, epsilon) {
+ var t0, t1, t2, x2, d2, i;
+ for (t2 = x, i = 0; i < 8; i++) {
+ x2 = sampleCurveX(t2) - x;
+ if (abs(x2) < epsilon) {
+ return t2;
+ }
+ d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
+ if (abs(d2) < 1e-6) {
+ break;
+ }
+ t2 = t2 - x2 / d2;
+ }
+ t0 = 0;
+ t1 = 1;
+ t2 = x;
+ if (t2 < t0) {
+ return t0;
+ }
+ if (t2 > t1) {
+ return t1;
+ }
+ while (t0 < t1) {
+ x2 = sampleCurveX(t2);
+ if (abs(x2 - x) < epsilon) {
+ return t2;
+ }
+ if (x > x2) {
+ t0 = t2;
+ } else {
+ t1 = t2;
+ }
+ t2 = (t1 - t0) / 2 + t0;
+ }
+ return t2;
+ }
+ return solve(t, 1 / (200 * duration));
+ }
+ elproto.onAnimation = function(f) {
+ f ? eve.on("raphael.anim.frame." + this.id, f) : eve.unbind("raphael.anim.frame." + this.id);
+ return this;
+ };
+ function Animation(anim, ms) {
+ var percents = [],
+ newAnim = {};
+ this.ms = ms;
+ this.times = 1;
+ if (anim) {
+ for (var attr in anim)
+ if (anim[has](attr)) {
+ newAnim[toFloat(attr)] = anim[attr];
+ percents.push(toFloat(attr));
+ }
+ percents.sort(sortByNumber);
+ }
+ this.anim = newAnim;
+ this.top = percents[percents.length - 1];
+ this.percents = percents;
+ }
+
+ /*\
+ * Animation.delay
+ [ method ]
+ **
+ * Creates a copy of existing animation object with given delay.
+ **
+ > Parameters
+ **
+ - delay (number) number of ms to pass between animation start and actual animation
+ **
+ = (object) new altered Animation object
+ | var anim = Raphael.animation({cx: 10, cy: 20}, 2e3);
+ | circle1.animate(anim); // run the given animation immediately
+ | circle2.animate(anim.delay(500)); // run the given animation after 500 ms
+ \*/
+ Animation.prototype.delay = function(delay) {
+ var a = new Animation(this.anim, this.ms);
+ a.times = this.times;
+ a.del = +delay || 0;
+ return a;
+ };
+
+ /*\
+ * Animation.repeat
+ [ method ]
+ **
+ * Creates a copy of existing animation object with given repetition.
+ **
+ > Parameters
+ **
+ - repeat (number) number iterations of animation. For infinite animation pass `Infinity`
+ **
+ = (object) new altered Animation object
+ \*/
+ Animation.prototype.repeat = function(times) {
+ var a = new Animation(this.anim, this.ms);
+ a.del = this.del;
+ a.times = math.floor(mmax(times, 0)) || 1;
+ return a;
+ };
+ function runAnimation(anim, element, percent, status, totalOrigin, times) {
+ percent = toFloat(percent);
+ var params,
+ isInAnim,
+ isInAnimSet,
+ percents = [],
+ next,
+ prev,
+ timestamp,
+ ms = anim.ms,
+ from = {},
+ to = {},
+ diff = {};
+ if (status) {
+ for (i = 0, ii = animationElements.length; i < ii; i++) {
+ var e = animationElements[i];
+ if (e.el.id == element.id && e.anim == anim) {
+ if (e.percent != percent) {
+ animationElements.splice(i, 1);
+ isInAnimSet = 1;
+ } else {
+ isInAnim = e;
+ }
+ element.attr(e.totalOrigin);
+ break;
+ }
+ }
+ } else {
+ status = +to; // NaN
+ }
+ for (var i = 0, ii = anim.percents.length; i < ii; i++) {
+ if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) {
+ percent = anim.percents[i];
+ prev = anim.percents[i - 1] || 0;
+ ms = ms / anim.top * (percent - prev);
+ next = anim.percents[i + 1];
+ params = anim.anim[percent];
+ break;
+ } else if (status) {
+ element.attr(anim.anim[anim.percents[i]]);
+ }
+ }
+ if (!params) {
+ return;
+ }
+ if (!isInAnim) {
+ for (var attr in params)
+ if (params[has](attr)) {
+ if (availableAnimAttrs[has](attr) || element.ca[attr]) {
+ from[attr] = element.attr(attr);
+ (from[attr] == null) && (from[attr] = availableAttrs[attr]);
+ to[attr] = params[attr];
+ switch (availableAnimAttrs[attr]) {
+ case nu:
+ diff[attr] = (to[attr] - from[attr]) / ms;
+ break;
+ case "colour":
+ from[attr] = R.getRGB(from[attr]);
+ var toColour = R.getRGB(to[attr]);
+ diff[attr] = {
+ r: (toColour.r - from[attr].r) / ms,
+ g: (toColour.g - from[attr].g) / ms,
+ b: (toColour.b - from[attr].b) / ms
+ };
+ break;
+ case "path":
+ var pathes = path2curve(from[attr], to[attr]),
+ toPath = pathes[1];
+ from[attr] = pathes[0];
+ diff[attr] = [];
+ for (i = 0, ii = from[attr].length; i < ii; i++) {
+ diff[attr][i] = [0];
+ for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
+ diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;
+ }
+ }
+ break;
+ case "transform":
+ var _ = element._,
+ eq = equaliseTransform(_[attr], to[attr]);
+ if (eq) {
+ from[attr] = eq.from;
+ to[attr] = eq.to;
+ diff[attr] = [];
+ diff[attr].real = true;
+ for (i = 0, ii = from[attr].length; i < ii; i++) {
+ diff[attr][i] = [from[attr][i][0]];
+ for (j = 1, jj = from[attr][i].length; j < jj; j++) {
+ diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms;
+ }
+ }
+ } else {
+ var m = (element.matrix || new Matrix),
+ to2 = {
+ _: {
+ transform: _.transform
+ },
+ getBBox: function() {
+ return element.getBBox(1);
+ }
+ };
+ from[attr] = [
+ m.a,
+ m.b,
+ m.c,
+ m.d,
+ m.e,
+ m.f
+ ];
+ extractTransform(to2, to[attr]);
+ to[attr] = to2._.transform;
+ diff[attr] = [
+ (to2.matrix.a - m.a) / ms,
+ (to2.matrix.b - m.b) / ms,
+ (to2.matrix.c - m.c) / ms,
+ (to2.matrix.d - m.d) / ms,
+ (to2.matrix.e - m.e) / ms,
+ (to2.matrix.f - m.f) / ms
+ ];
+ // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
+ // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
+ // extractTransform(to2, to[attr]);
+ // diff[attr] = [
+ // (to2._.sx - _.sx) / ms,
+ // (to2._.sy - _.sy) / ms,
+ // (to2._.deg - _.deg) / ms,
+ // (to2._.dx - _.dx) / ms,
+ // (to2._.dy - _.dy) / ms
+ // ];
+ }
+ break;
+ case "csv":
+ var values = Str(params[attr])[split](separator),
+ from2 = Str(from[attr])[split](separator);
+ if (attr == "clip-rect") {
+ from[attr] = from2;
+ diff[attr] = [];
+ i = from2.length;
+ while (i--) {
+ diff[attr][i] = (values[i] - from[attr][i]) / ms;
+ }
+ }
+ to[attr] = values;
+ break;
+ default:
+ values = [][concat](params[attr]);
+ from2 = [][concat](from[attr]);
+ diff[attr] = [];
+ i = element.ca[attr].length;
+ while (i--) {
+ diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms;
+ }
+ break;
+ }
+ }
+ }
+ var easing = params.easing,
+ easyeasy = R.easing_formulas[easing];
+ if (!easyeasy) {
+ easyeasy = Str(easing).match(bezierrg);
+ if (easyeasy && easyeasy.length == 5) {
+ var curve = easyeasy;
+ easyeasy = function(t) {
+ return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms);
+ };
+ } else {
+ easyeasy = pipe;
+ }
+ }
+ timestamp = params.start || anim.start || +new Date;
+ e = {
+ anim: anim,
+ percent: percent,
+ timestamp: timestamp,
+ start: timestamp + (anim.del || 0),
+ status: 0,
+ initstatus: status || 0,
+ stop: false,
+ ms: ms,
+ easing: easyeasy,
+ from: from,
+ diff: diff,
+ to: to,
+ el: element,
+ callback: params.callback,
+ prev: prev,
+ next: next,
+ repeat: times || anim.times,
+ origin: element.attr(),
+ totalOrigin: totalOrigin
+ };
+ animationElements.push(e);
+ if (status && !isInAnim && !isInAnimSet) {
+ e.stop = true;
+ e.start = new Date - ms * status;
+ if (animationElements.length == 1) {
+ return animation();
+ }
+ }
+ if (isInAnimSet) {
+ e.start = new Date - e.ms * status;
+ }
+ animationElements.length == 1 && requestAnimFrame(animation);
+ } else {
+ isInAnim.initstatus = status;
+ isInAnim.start = new Date - isInAnim.ms * status;
+ }
+ eve("raphael.anim.start." + element.id, element, anim);
+ }
+
+ /*\
+ * Raphael.animation
+ [ method ]
+ **
+ * Creates an animation object that can be passed to the @Element.animate or @Element.animateWith methods.
+ * See also @Animation.delay and @Animation.repeat methods.
+ **
+ > Parameters
+ **
+ - params (object) final attributes for the element, see also @Element.attr
+ - ms (number) number of milliseconds for animation to run
+ - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)`
+ - callback (function) #optional callback function. Will be called at the end of animation.
+ **
+ = (object) @Animation
+ \*/
+ R.animation = function(params, ms, easing, callback) {
+ if (params instanceof Animation) {
+ return params;
+ }
+ if (R.is(easing, "function") || !easing) {
+ callback = callback || easing || null;
+ easing = null;
+ }
+ params = Object(params);
+ ms = +ms || 0;
+ var p = {},
+ json,
+ attr;
+ for (attr in params)
+ if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) {
+ json = true;
+ p[attr] = params[attr];
+ }
+ if (!json) {
+ return new Animation(params, ms);
+ } else {
+ easing && (p.easing = easing);
+ callback && (p.callback = callback);
+ return new Animation({
+ 100: p
+ }, ms);
+ }
+ };
+
+ /*\
+ * Element.animate
+ [ method ]
+ **
+ * Creates and starts animation for given element.
+ **
+ > Parameters
+ **
+ - params (object) final attributes for the element, see also @Element.attr
+ - ms (number) number of milliseconds for animation to run
+ - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)`
+ - callback (function) #optional callback function. Will be called at the end of animation.
+ * or
+ - animation (object) animation object, see @Raphael.animation
+ **
+ = (object) original element
+ \*/
+ elproto.animate = function(params, ms, easing, callback) {
+ var element = this;
+ if (element.removed) {
+ callback && callback.call(element);
+ return element;
+ }
+ var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback);
+ runAnimation(anim, element, anim.percents[0], null, element.attr());
+ return element;
+ };
+
+ /*\
+ * Element.setTime
+ [ method ]
+ **
+ * Sets the status of animation of the element in milliseconds. Similar to @Element.status method.
+ **
+ > Parameters
+ **
+ - anim (object) animation object
+ - value (number) number of milliseconds from the beginning of the animation
+ **
+ = (object) original element if `value` is specified
+ * Note, that during animation following events are triggered:
+ *
+ * On each animation frame event `anim.frame.`, on start `anim.start.` and on end `anim.finish.`.
+ \*/
+ elproto.setTime = function(anim, value) {
+ if (anim && value != null) {
+ this.status(anim, mmin(value, anim.ms) / anim.ms);
+ }
+ return this;
+ };
+
+ /*\
+ * Element.status
+ [ method ]
+ **
+ * Gets or sets the status of animation of the element.
+ **
+ > Parameters
+ **
+ - anim (object) #optional animation object
+ - value (number) #optional 0 – 1. If specified, method works like a setter and sets the status of a given animation to the value. This will cause animation to jump to the given position.
+ **
+ = (number) status
+ * or
+ = (array) status if `anim` is not specified. Array of objects in format:
+ o {
+ o anim: (object) animation object
+ o status: (number) status
+ o }
+ * or
+ = (object) original element if `value` is specified
+ \*/
+ elproto.status = function(anim, value) {
+ var out = [],
+ i = 0,
+ len,
+ e;
+ if (value != null) {
+ runAnimation(anim, this, -1, mmin(value, 1));
+ return this;
+ } else {
+ len = animationElements.length;
+ for (; i < len; i++) {
+ e = animationElements[i];
+ if (e.el.id == this.id && (!anim || e.anim == anim)) {
+ if (anim) {
+ return e.status;
+ }
+ out.push({
+ anim: e.anim,
+ status: e.status
+ });
+ }
+ }
+ if (anim) {
+ return 0;
+ }
+ return out;
+ }
+ };
+
+ /*\
+ * Element.pause
+ [ method ]
+ **
+ * Stops animation of the element with ability to resume it later on.
+ **
+ > Parameters
+ **
+ - anim (object) #optional animation object
+ **
+ = (object) original element
+ \*/
+ elproto.pause = function(anim) {
+ for (var i = 0; i < animationElements.length; i++)
+ if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+ if (eve("raphael.anim.pause." + this.id, this, animationElements[i].anim) !== false) {
+ animationElements[i].paused = true;
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Element.resume
+ [ method ]
+ **
+ * Resumes animation if it was paused with @Element.pause method.
+ **
+ > Parameters
+ **
+ - anim (object) #optional animation object
+ **
+ = (object) original element
+ \*/
+ elproto.resume = function(anim) {
+ for (var i = 0; i < animationElements.length; i++)
+ if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+ var e = animationElements[i];
+ if (eve("raphael.anim.resume." + this.id, this, e.anim) !== false) {
+ delete e.paused;
+ this.status(e.anim, e.status);
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Element.stop
+ [ method ]
+ **
+ * Stops animation of the element.
+ **
+ > Parameters
+ **
+ - anim (object) #optional animation object
+ **
+ = (object) original element
+ \*/
+ elproto.stop = function(anim) {
+ for (var i = 0; i < animationElements.length; i++)
+ if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+ if (eve("raphael.anim.stop." + this.id, this, animationElements[i].anim) !== false) {
+ animationElements.splice(i--, 1);
+ }
+ }
+ return this;
+ };
+ function stopAnimation(paper) {
+ for (var i = 0; i < animationElements.length; i++)
+ if (animationElements[i].el.paper == paper) {
+ animationElements.splice(i--, 1);
+ }
+ }
+ eve.on("raphael.remove", stopAnimation);
+ eve.on("raphael.clear", stopAnimation);
+ elproto.toString = function() {
+ return "Rapha\xebl\u2019s object";
+ };
+
+ elproto.toFront = function() {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = R._engine.getNode(o),
+ parent = o.parent,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (R._tofront(o, parent)) {
+ parent.canvas.appendChild(thisNode);
+ }
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk && follower.el[follower.stalk](o);
+ }
+ return o;
+ };
+
+ elproto.toBack = function() {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = R._engine.getNode(o),
+ parent = o.parent,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (R._toback(o, parent)) {
+ parent.canvas.insertBefore(thisNode, parent.canvas.firstChild);
+ }
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk && follower.el[follower.stalk](o);
+ }
+ return o;
+ };
+
+ elproto.insertAfter = function(element) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = R._engine.getNode(o),
+ thatNode = R._engine.getLastNode(element),
+ parentNode = element.parent.canvas,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (thatNode.nextSibling) {
+ parentNode.insertBefore(thisNode, thatNode.nextSibling);
+ }
+ else {
+ parentNode.appendChild(thisNode);
+ }
+ R._insertafter(o, element, o.parent, element.parent);
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+ return o;
+ };
+
+ elproto.insertBefore = function(element) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = R._engine.getNode(o),
+ thatNode = R._engine.getNode(element),
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ element.parent.canvas.insertBefore(thisNode, thatNode);
+ R._insertbefore(o, element, o.parent, element.parent);
+ o.parent = element.parent;
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+ return this;
+ };
+
+ elproto.appendChild = function (element) {
+ if (this.removed || this.type !== 'group') {
+ return this;
+ }
+
+ var group = this,
+ followers = group.followers,
+ follower,
+ thatNode,
+ i,
+ ii;
+
+ // If appending in same group, simply perform toFront().
+ if (element.parent === group) {
+ element.toFront();
+ return group;
+ }
+
+ thatNode = R._engine.getNode(element);
+
+ // first remove from own group
+ R._tear(element, element.parent);
+
+ group.canvas.appendChild(thatNode);
+ element.parent = group;
+
+ !group.bottom && (group.bottom = element);
+ element.prev = group.top;
+ element.next = null;
+ group.top && (group.top.next = element);
+ group.top = element;
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+
+ return group;
+ };
+
+ elproto.removeChild = function (element) {
+ if (this.removed || this.type !== 'group' || element.parent !== this) {
+ return this;
+ }
+
+ var o = this,
+ thatNode = R._engine.getNode(element),
+ paper = o.paper;
+
+ R._tear(element, o);
+ paper.canvas.appendChild(thatNode);
+
+ o.parent = paper;
+ !paper.bottom && (paper.bottom = o);
+
+ o.prev = paper.top;
+ paper.top && (paper.top.next = o);
+ paper.top = o;
+ o.next = null;
+
+ return o;
+ };
+
+ // Set
+ var Set = function(items) {
+ this.items = [];
+ this.length = 0;
+ this.type = "set";
+ if (items) {
+ for (var i = 0, ii = items.length; i < ii; i++) {
+ if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) {
+ this[this.items.length] = this.items[this.items.length] = items[i];
+ this.length++;
+ }
+ }
+ }
+ },
+ setproto = Set.prototype;
+
+ /*\
+ * Set.push
+ [ method ]
+ **
+ * Adds each argument to the current set.
+ = (object) original element
+ \*/
+ setproto.push = function() {
+ var item,
+ len;
+ for (var i = 0, ii = arguments.length; i < ii; i++) {
+ item = arguments[i];
+ if (item && (item.constructor == elproto.constructor || item.constructor == Set)) {
+ len = this.items.length;
+ this[len] = this.items[len] = item;
+ this.length++;
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Set.pop
+ [ method ]
+ **
+ * Removes last element and returns it.
+ = (object) element
+ \*/
+ setproto.pop = function() {
+ this.length && delete this[this.length--];
+ return this.items.pop();
+ };
+
+ /*\
+ * Set.forEach
+ [ method ]
+ **
+ * Executes given function for each element in the set.
+ *
+ * If function returns `false` it will stop loop running.
+ **
+ > Parameters
+ **
+ - callback (function) function to run
+ - thisArg (object) context object for the callback
+ = (object) Set object
+ \*/
+ setproto.forEach = function(callback, thisArg) {
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ if (callback.call(thisArg, this.items[i], i) === false) {
+ return this;
+ }
+ }
+ return this;
+ };
+ for (var method in elproto)
+ if (elproto[has](method)) {
+ setproto[method] = (function(methodname) {
+ return function() {
+ var arg = arguments;
+ return this.forEach(function(el) {
+ el[methodname][apply](el, arg);
+ });
+ };
+ })(method);
+ }
+ setproto.attr = function(name, value) {
+ if (name && R.is(name, array) && R.is(name[0], object)) {
+ for (var j = 0, jj = name.length; j < jj; j++) {
+ this.items[j].attr(name[j]);
+ }
+ } else {
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ this.items[i].attr(name, value);
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Set.clear
+ [ method ]
+ **
+ * Removeds all elements from the set
+ \*/
+ setproto.clear = function() {
+ while (this.length) {
+ this.pop();
+ }
+ };
+
+ /*\
+ * Set.splice
+ [ method ]
+ **
+ * Removes given element from the set
+ **
+ > Parameters
+ **
+ - index (number) position of the deletion
+ - count (number) number of element to remove
+ - insertion… (object) #optional elements to insert
+ = (object) set elements that were deleted
+ \*/
+ setproto.splice = function(index, count, insertion) {
+ index = index < 0 ? mmax(this.length + index, 0) : index;
+ count = mmax(0, mmin(this.length - index, isNaN(count) && this.length || count));
+ var tail = [],
+ todel = [],
+ args = [],
+ i;
+ for (i = 2; i < arguments.length; i++) {
+ args.push(arguments[i]);
+ }
+ for (i = 0; i < count; i++) {
+ todel.push(this[index + i]);
+ }
+ for (; i < this.length - index; i++) {
+ tail.push(this[index + i]);
+ }
+ var arglen = args.length;
+ for (i = 0; i < arglen + tail.length; i++) {
+ this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
+ }
+ i = this.items.length = this.length -= count - arglen;
+ while (this[i]) {
+ delete this[i++];
+ }
+ return new Set(todel);
+ };
+
+ /*\
+ * Set.exclude
+ [ method ]
+ **
+ * Removes given element from the set
+ **
+ > Parameters
+ **
+ - element (object) element to remove
+ = (boolean) `true` if object was found & removed from the set
+ \*/
+ setproto.exclude = function(el) {
+ for (var i = 0, ii = this.length; i < ii; i++)
+ if (this[i] == el) {
+ this.splice(i, 1);
+ return true;
+ }
+ };
+ setproto.animate = function(params, ms, easing, callback) {
+ (R.is(easing, "function") || !easing) && (callback = easing || null);
+ var len = this.items.length,
+ i = len,
+ item,
+ set = this,
+ collector;
+ if (!len) {
+ return this;
+ }
+ callback && (collector = function() {
+ !--len && callback.call(set);
+ });
+ easing = R.is(easing, string) ? easing : collector;
+ var anim = R.animation(params, ms, easing, collector);
+ item = this.items[--i].animate(anim);
+ while (i--) {
+ this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim, anim);
+ }
+ return this;
+ };
+ setproto.insertAfter = function(el) {
+ var i = this.items.length;
+ while (i--) {
+ this.items[i].insertAfter(el);
+ }
+ return this;
+ };
+ setproto.getBBox = function() {
+ var x = [],
+ y = [],
+ x2 = [],
+ y2 = [];
+ for (var i = this.items.length; i--; )
+ if (!this.items[i].removed) {
+ var box = this.items[i].getBBox();
+ x.push(box.x);
+ y.push(box.y);
+ x2.push(box.x + box.width);
+ y2.push(box.y + box.height);
+ }
+ x = mmin[apply](0, x);
+ y = mmin[apply](0, y);
+ x2 = mmax[apply](0, x2);
+ y2 = mmax[apply](0, y2);
+ return {
+ x: x,
+ y: y,
+ x2: x2,
+ y2: y2,
+ width: x2 - x,
+ height: y2 - y
+ };
+ };
+ setproto.clone = function(s) {
+ s = new Set;
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ s.push(this.items[i].clone());
+ }
+ return s;
+ };
+ setproto.toString = function() {
+ return "Rapha\xebl\u2018s set";
+ };
+
+ setproto.glow = function(glowConfig) {
+ var ret = this.paper.set();
+ this.forEach(function(shape, index){
+ var g = shape.glow(glowConfig);
+ if(g != null){
+ g.forEach(function(shape2, index2){
+ ret.push(shape2);
+ });
+ }
+ });
+ return ret;
+ };
+
+ /*\
+ * Raphael.registerFont
+ [ method ]
+ **
+ * Adds given font to the registered set of fonts for Raphaël. Should be used as an internal call from within Cufón’s font file.
+ * Returns original parameter, so it could be used with chaining.
+ # More about Cufón and how to convert your font form TTF, OTF, etc to JavaScript file.
+ **
+ > Parameters
+ **
+ - font (object) the font to register
+ = (object) the font you passed in
+ > Usage
+ | Cufon.registerFont(Raphael.registerFont({…}));
+ \*/
+ R.registerFont = function(font) {
+ if (!font.face) {
+ return font;
+ }
+ this.fonts = this.fonts || {};
+ var fontcopy = {
+ w: font.w,
+ face: {},
+ glyphs: {}
+ },
+ family = font.face["font-family"];
+ for (var prop in font.face)
+ if (font.face[has](prop)) {
+ fontcopy.face[prop] = font.face[prop];
+ }
+ if (this.fonts[family]) {
+ this.fonts[family].push(fontcopy);
+ } else {
+ this.fonts[family] = [fontcopy];
+ }
+ if (!font.svg) {
+ fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10);
+ for (var glyph in font.glyphs)
+ if (font.glyphs[has](glyph)) {
+ var path = font.glyphs[glyph];
+ fontcopy.glyphs[glyph] = {
+ w: path.w,
+ k: {},
+ d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function(command) {
+ return {
+ l: "L",
+ c: "C",
+ x: "z",
+ t: "m",
+ r: "l",
+ v: "c"
+ }
+ [command] || "M";
+ }) + "z"
+ };
+ if (path.k) {
+ for (var k in path.k)
+ if (path[has](k)) {
+ fontcopy.glyphs[glyph].k[k] = path.k[k];
+ }
+ }
+ }
+ }
+ return font;
+ };
+
+ /*\
+ * Paper.getFont
+ [ method ]
+ **
+ * Finds font object in the registered fonts by given parameters. You could specify only one word from the font name, like “Myriad” for “Myriad Pro”.
+ **
+ > Parameters
+ **
+ - family (string) font family name or any word from it
+ - weight (string) #optional font weight
+ - style (string) #optional font style
+ - stretch (string) #optional font stretch
+ = (object) the font object
+ > Usage
+ | paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30);
+ \*/
+ paperproto.getFont = function(family, weight, style, stretch) {
+ stretch = stretch || "normal";
+ style = style || "normal";
+ weight = +weight || {
+ normal: 400,
+ bold: 700,
+ lighter: 300,
+ bolder: 800
+ }
+ [weight] || 400;
+ if (!R.fonts) {
+ return;
+ }
+ var font = R.fonts[family];
+ if (!font) {
+ var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i");
+ for (var fontName in R.fonts)
+ if (R.fonts[has](fontName)) {
+ if (name.test(fontName)) {
+ font = R.fonts[fontName];
+ break;
+ }
+ }
+ }
+ var thefont;
+ if (font) {
+ for (var i = 0, ii = font.length; i < ii; i++) {
+ thefont = font[i];
+ if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) {
+ break;
+ }
+ }
+ }
+ return thefont;
+ };
+
+ /*\
+ * Paper.print
+ [ method ]
+ **
+ * Creates path that represent given text written using given font at given position with given size.
+ * Result of the method is path element that contains whole text as a separate path.
+ **
+ > Parameters
+ **
+ - x (number) x position of the text
+ - y (number) y position of the text
+ - string (string) text to print
+ - font (object) font object, see @Paper.getFont
+ - size (number) #optional size of the font, default is `16`
+ - origin (string) #optional could be `"baseline"` or `"middle"`, default is `"middle"`
+ - letter_spacing (number) #optional number in range `-1..1`, default is `0`
+ = (object) resulting path element, which consist of all letters
+ > Usage
+ | var txt = r.print(10, 50, "print", r.getFont("Museo"), 30).attr({fill: "#fff"});
+ \*/
+ paperproto.print = function(x, y, string, font, size, origin, letter_spacing) {
+ origin = origin || "middle"; // baseline|middle
+ letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1);
+ var letters = Str(string)[split](E),
+ shift = 0,
+ notfirst = 0,
+ path = E,
+ scale;
+ R.is(font, string) && (font = this.getFont(font));
+ if (font) {
+ scale = (size || 16) / font.face["units-per-em"];
+ var bb = font.face.bbox[split](separator),
+ top = +bb[0],
+ lineHeight = bb[3] - bb[1],
+ shifty = 0,
+ height = + bb[1] + (origin == "baseline" ? lineHeight + ( + font.face.descent) : lineHeight / 2);
+ for (var i = 0, ii = letters.length; i < ii; i++) {
+ if (letters[i] == "\n") {
+ shift = 0;
+ curr = 0;
+ notfirst = 0;
+ shifty += lineHeight;
+ } else {
+ var prev = notfirst && font.glyphs[letters[i - 1]] || {},
+ curr = font.glyphs[letters[i]];
+ shift += notfirst ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0;
+ notfirst = 1;
+ }
+ if (curr && curr.d) {
+ path += R.transformPath(curr.d, ["t", shift * scale, shifty * scale, "s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]);
+ }
+ }
+ }
+ return this.path(path).attr({
+ fill: "#000",
+ stroke: "none"
+ });
+ };
+
+ /*\
+ * Paper.add
+ [ method ]
+ **
+ * Imports elements in JSON array in format `{type: type, }`
+ **
+ > Parameters
+ **
+ - json (array)
+ = (object) resulting set of imported elements
+ > Usage
+ | paper.add([
+ | {
+ | type: "circle",
+ | cx: 10,
+ | cy: 10,
+ | r: 5
+ | },
+ | {
+ | type: "rect",
+ | x: 10,
+ | y: 10,
+ | width: 10,
+ | height: 10,
+ | fill: "#fc0"
+ | }
+ | ]);
+ \*/
+ paperproto.add = function(json) {
+ if (R.is(json, "array")) {
+ var res = this.set(),
+ i = 0,
+ ii = json.length,
+ j;
+ for (; i < ii; i++) {
+ j = json[i] || {};
+ elements[has](j.type) && res.push(this[j.type]().attr(j));
+ }
+ }
+ return res;
+ };
+
+ /*\
+ * Raphael.format
+ [ method ]
+ **
+ * Simple format function. Replaces construction of type “`{}`” to the corresponding argument.
+ **
+ > Parameters
+ **
+ - token (string) string to format
+ - … (string) rest of arguments will be treated as parameters for replacement
+ = (string) formated string
+ > Usage
+ | var x = 10,
+ | y = 20,
+ | width = 40,
+ | height = 50;
+ | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
+ | paper.path(Raphael.format("M{0},{1}h{2}v{3}h{4}z", x, y, width, height, -width));
+ \*/
+ R.format = function(token, params) {
+ var args = R.is(params, array) ? [0][concat](params) : arguments;
+ token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function(str, i) {
+ return args[++i] == null ? E : args[i];
+ }));
+ return token || E;
+ };
+
+ /*\
+ * Raphael.fullfill
+ [ method ]
+ **
+ * A little bit more advanced format function than @Raphael.format. Replaces construction of type “`{}`” to the corresponding argument.
+ **
+ > Parameters
+ **
+ - token (string) string to format
+ - json (object) object which properties will be used as a replacement
+ = (string) formated string
+ > Usage
+ | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
+ | paper.path(Raphael.fullfill("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
+ | x: 10,
+ | y: 20,
+ | dim: {
+ | width: 40,
+ | height: 50,
+ | "negative width": -40
+ | }
+ | }));
+ \*/
+ R.fullfill = (function() {
+ var tokenRegex = /\{([^\}]+)\}/g,
+ objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
+ replacer = function(all, key, obj) {
+ var res = obj;
+ key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
+ name = name || quotedName;
+ if (res) {
+ if (name in res) {
+ res = res[name];
+ }
+ typeof res == "function" && isFunc && (res = res());
+ }
+ });
+ res = (res == null || res == obj ? all : res) + "";
+ return res;
+ };
+ return function(str, obj) {
+ return String(str).replace(tokenRegex, function(all, key) {
+ return replacer(all, key, obj);
+ });
+ };
+ })();
+
+ /*\
+ * Raphael.ninja
+ [ method ]
+ **
+ * If you want to leave no trace of Raphaël (Well, Raphaël creates only one global variable `Raphael`, but anyway.) You can use `ninja` method.
+ * Beware, that in this case plugins could stop working, because they are depending on global variable existance.
+ **
+ = (object) Raphael object
+ > Usage
+ | (function (local_raphael) {
+ | var paper = local_raphael(10, 10, 320, 200);
+ | …
+ | })(Raphael.ninja());
+ \*/
+ R.ninja = function() {
+ oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael;
+ return R;
+ };
+
+ var crispFixer = (R.vml && 0.5 || 0);
+
+ R.crispBound = cacher(function (x, y, w, h, s) {
+ var at = {},
+ normalizer;
+
+ x = x || 0;
+ y = y || 0;
+ w = w || 0;
+ h = h || 0;
+ s = s || 0;
+ normalizer = s % 2 / 2 + crispFixer;
+
+ // normalize for crisp edges
+ at.x = round(x + normalizer) - normalizer;
+ at.y = round(y + normalizer) - normalizer;
+ at.width = round(x + w + normalizer) - normalizer - at.x;
+ at.height = round(y + h + normalizer) - normalizer - at.y;
+ at['stroke-width'] = s;
+
+ // adjust to single pixel if resultant dimension is zero.
+ (at.width === 0 && w !== 0) && (at.width = 1);
+ (at.height === 0 && h !== 0) && (at.height = 1);
+
+ return at;
+ }, R);
+
+ elproto.crisp = function () {
+ var o = this,
+ attrs = o.attrs,
+ key,
+ attr = {},
+ values = o.attr(['x', 'y', 'width', 'height', 'stroke-width']);
+
+ values = R.crispBound(values.x, values.y, values.width, values.height,
+ values['stroke-width']);
+
+ for (key in values) {
+ if (attrs[key] === values[key]) { // only set attribute if changed
+ delete values[key];
+ }
+ }
+
+ return o.attr(values);
+ };
+
+ /*\
+ * Raphael.st
+ [ property (object) ]
+ **
+ * You can add your own method to elements and sets. It is wise to add a set method for each element method
+ * you added, so you will be able to call the same method on sets too.
+ **
+ * See also @Raphael.el.
+ > Usage
+ | Raphael.el.red = function () {
+ | this.attr({fill: "#f00"});
+ | };
+ | Raphael.st.red = function () {
+ | this.forEach(function (el) {
+ | el.red();
+ | });
+ | };
+ | // then use it
+ | paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red();
+ \*/
+ R.st = setproto;
+
+ /*\
+ * Raphael.define
+ [ method ]
+ **
+ * Allows a unified definition of composite shapes and other behaviours using
+ * simple directives.
+ **
+ > Parameters
+ **
+ - definition (object) the shape definition
+ \*/
+ R.define = function (name, init, ca, fn, e) {
+ var i,
+ ii;
+
+ // multi definition
+ if (R.is(name, array)) {
+ for (i = 0, ii = name.length; i < ii; i++) {
+ R.define(name[i]);
+ }
+ return;
+ }
+ // object definition
+ else if (R.is(name, object)) {
+ R.define(name.name, name[name.name], name.ca, name.fn, name.e);
+ return;
+ }
+ // invalid or duplicate definition
+ else if (!name || R.fn[name]) {
+ return;
+ }
+
+ R.fn[name] = function () {
+ var args = arguments,
+ element = init.apply(this, args),
+ key;
+
+ if (fn && R.is(fn, object)) {
+ for (key in fn) {
+ element[key] = fn[key];
+ }
+ }
+
+ if (e && R.is(e, object)) {
+ for (key in e) {
+ element[key] && element[key](e[key]);
+ }
+ }
+
+ if (ca) {
+ if (R.is(ca, 'function')) {
+ element.ca[name] = ca;
+ }
+ else {
+ for (key in ca) {
+ element.ca[key] = ca[key];
+ }
+ }
+
+ // Check if namesake ca exists and apply it
+ if (element.ca[name]) {
+ R._lastArgIfGroup(args, true); // purge group
+ element.attr(name, arraySlice.call(args))
+ }
+ }
+
+ return element;
+ };
+
+ if (ca) { R.fn[name].ca = ca; }
+ if (fn) { R.fn[name].fn = fn; }
+ if (e) { R.fn[name].e = e; }
+
+ return R.fn[name];
+ };
+ // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
+ (function(doc, loaded, f) {
+ if (doc.readyState == null && doc.addEventListener) {
+ doc.addEventListener(loaded, f = function() {
+ doc.removeEventListener(loaded, f, false);
+ doc.readyState = "complete";
+ }, false);
+ doc.readyState = "loading";
+ }
+ function isLoaded() {
+ (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("raphael.DOMload");
+ }
+ isLoaded();
+ })(document, "DOMContentLoaded");
+
+ eve.on("raphael.DOMload", function() {
+ loaded = true;
+ });
+
+/**!
+* RedRaphael 1.0.0 - JavaScript Vector Library SVG Module
+* Copyright (c) 2012-2013 FusionCharts Technologies
+*
+* Raphael 2.1.0 - JavaScript Vector Library SVG Module
+* Copyright (c) 2008-2012 Dmitry Baranovskiy
+* Copyright © 2008-2012 Sencha Labs
+*
+* Licensed under the MIT license.
+*/
+(function(){
+ if (!R.svg) {
+ return;
+ }
+ var has = "hasOwnProperty",
+ Str = String,
+ toFloat = parseFloat,
+ toInt = parseInt,
+ math = Math,
+ mmax = math.max,
+ abs = math.abs,
+ pow = math.pow,
+ sqrt = math.sqrt,
+ separator = /[, ]+/,
+ zeroStrokeFix = !!(/AppleWebKit/.test(R._g.win.navigator.userAgent) &&
+ (!/Chrome/.test(R._g.win.navigator.userAgent) ||
+ R._g.win.navigator.appVersion.match(/Chrome\/(\d+)\./)[1] < 29)),
+ eve = R.eve,
+ E = "",
+ S = " ",
+ xlink = "http://www.w3.org/1999/xlink",
+ markers = {
+ block: "M5,0 0,2.5 5,5z",
+ classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
+ diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
+ open: "M6,1 1,3.5 6,6",
+ oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
+ },
+ markerCounter = {},
+ updateReferenceUrl = function () {
+ return R._url = R._g.win.location.href.replace(/#.*?$/, E);
+ };
+
+ R.toString = function() {
+ return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
+ };
+
+ // Automatic gradient and other reference update on state change
+ R._url = (/msie/i.test(navigator.userAgent) && !window.opera) ?
+ E : updateReferenceUrl();
+ if (R._url && R._g.win.history.pushState) {
+ R._g.win.history.pushState = (function () {
+ var fn = R._g.win.history.pushState;
+ return function () {
+ var ret = fn.apply(R._g.win.history, arguments);
+ return updateReferenceUrl(), ret;
+ };
+ }());
+ R._g.win.addEventListener("popstate", updateReferenceUrl, false);
+ }
+
+ var $ = R._createNode = function(el, attr) {
+ if (attr) {
+ if (typeof el == "string") {
+ el = $(el);
+ }
+ for (var key in attr)
+ if (attr[has](key)) {
+ if (key.substring(0, 6) == "xlink:") {
+ el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
+ } else {
+ el.setAttribute(key, Str(attr[key]));
+ }
+ }
+ } else {
+ el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
+ }
+ return el;
+ },
+ gradientUnitNames = {
+ userSpaceOnUse: 'userSpaceOnUse',
+ objectBoundingBox: 'objectBoundingBox'
+ },
+ gradientSpreadNames = {
+ pad: 'pad',
+ redlect: 'reflect',
+ repeat: 'repeat'
+ },
+ addGradientFill = function(element, gradient) {
+ var type = "linear",
+ id = element.id + gradient,
+ fx = .5, fy = .5, r, cx, cy, units, spread,
+ o = element.node,
+ SVG = element.paper,
+ s = o.style,
+ el = R._g.doc.getElementById(id);
+ if (!el && SVG.defs) {
+ gradient = Str(gradient).replace(R._radial_gradient, function(all, opts) {
+ type = "radial";
+ opts = opts && opts.split(',') || [];
+ units = opts[5];
+ spread = opts[6];
+
+ var _fx = opts[0],
+ _fy = opts[1],
+ _r = opts[2],
+ _cx = opts[3],
+ _cy = opts[4],
+ shifted = (_fx && _fy),
+ dir,
+ sqx;
+
+ if (_r) {
+ r = /\%/.test(_r) ? _r : toFloat(_r);
+ }
+
+ if (units === gradientUnitNames.userSpaceOnUse) {
+ if (shifted) {
+ fx = _fx;
+ fy = _fy;
+ }
+ if (_cx && _cy) {
+ cx = _cx;
+ cy = _cy;
+ if (!shifted) {
+ fx = cx;
+ fy = cy;
+ }
+ }
+ return E;
+ }
+
+ if (shifted) {
+ fx = toFloat(_fx);
+ fy = toFloat(_fy);
+ dir = ((fy > .5) * 2 - 1);
+ (sqx = pow(fx - .5, 2)) + pow(fy - .5, 2) > .25 &&
+ (sqx < .25) && (fy = sqrt(.25 - sqx) * dir + .5) &&
+ fy !== .5 &&
+ (fy = fy.toFixed(5) - 1e-5 * dir);
+ }
+ if (_cx && _cy) {
+ cx = toFloat(_cx);
+ cy = toFloat(_cy);
+ dir = ((cy > .5) * 2 - 1);
+
+ (sqx = pow(cx - .5, 2)) + pow(cy - .5, 2) > .25 &&
+ (sqx < .25) && (cy = sqrt(.25 - sqx) * dir + .5) &&
+ cy !== .5 &&
+ (cy = cy.toFixed(5) - 1e-5 * dir);
+
+ if (!shifted) {
+ fx = cx;
+ fy = cy;
+ }
+ }
+
+ return E;
+ });
+ gradient = gradient.split(/\s*\-\s*/);
+ if (type == "linear") {
+ var angle = gradient.shift(),
+ specs = angle.match(/\((.*)\)/),
+ vector,
+ max;
+
+ specs = specs && specs[1] && specs[1].split(/\s*\,\s*/);
+ angle = -toFloat(angle);
+ if (isNaN(angle)) {
+ return null;
+ }
+ if (specs && specs.length) {
+ if (specs[0] in gradientUnitNames) {
+ units = specs.shift();
+ (specs[0] in gradientSpreadNames) &&
+ (spread = specs.shift());
+ }
+ else {
+ specs[4] && (units = specs[4]);
+ specs[5] && (spread = specs[5]);
+ }
+
+ /* @todo apply angle rotation and validation */
+ vector = [
+ specs[0] || "0%", specs[1] || "0%",
+ specs[2] || "100%", specs[3] || "0%"
+ ];
+ }
+ else {
+ vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))];
+ max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
+ vector[2] *= max;
+ vector[3] *= max;
+ if (vector[2] < 0) {
+ vector[0] = -vector[2];
+ vector[2] = 0;
+ }
+ if (vector[3] < 0) {
+ vector[1] = -vector[3];
+ vector[3] = 0;
+ }
+ }
+ }
+ var dots = R._parseDots(gradient);
+ if (!dots) {
+ return null;
+ }
+ id = id.replace(/[\(\)\s,\xb0#]/g, "_");
+
+ if (element.gradient && id !== element.gradient.id) {
+ SVG.defs.removeChild(element.gradient);
+ delete element.gradient;
+ }
+
+ if (!element.gradient) {
+ el = $(type + "Gradient", {
+ id: id
+ });
+ element.gradient = el;
+ (units in gradientUnitNames) &&
+ el.setAttribute('gradientUnits', Str(units));
+ (spread in gradientSpreadNames) &&
+ el.setAttribute('spreadMethod', Str(spread));
+ if (type === "radial") {
+ (r !== undefined) && el.setAttribute('r', Str(r));
+
+ if (cx !== undefined && cy !== undefined) {
+ el.setAttribute('cx', Str(cx));
+ el.setAttribute('cy', Str(cy));
+ }
+ el.setAttribute('fx', Str(fx));
+ el.setAttribute('fy', Str(fy));
+ }
+ else {
+ $(el, {
+ x1: vector[0],
+ y1: vector[1],
+ x2: vector[2],
+ y2: vector[3],
+ gradientTransform: element.matrix.invert()
+ });
+ }
+ SVG.defs.appendChild(el);
+ for (var i = 0, ii = dots.length; i < ii; i++) {
+ el.appendChild($("stop", {
+ offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
+ "stop-color": dots[i].color || "#fff",
+ //add stop opacity information
+ "stop-opacity": dots[i].opacity === undefined ? 1 : dots[i].opacity
+ }));
+ }
+ }
+ }
+ $(o, {
+ fill: "url('" + R._url + "#" + id + "')",
+ opacity: 1,
+ "fill-opacity": 1
+ });
+ s.fill = E;
+ s.opacity = 1;
+ s.fillOpacity = 1;
+ return 1;
+ },
+ updatePosition = function(o) {
+ var bbox = o.getBBox(1);
+ $(o.pattern, {
+ patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"
+ });
+ },
+ addArrow = function(o, value, isEnd) {
+ if (o.type == "path") {
+ var values = Str(value).toLowerCase().split("-"),
+ p = o.paper,
+ se = isEnd ? "end" : "start",
+ node = o.node,
+ attrs = o.attrs,
+ stroke = attrs["stroke-width"],
+ i = values.length,
+ type = "classic",
+ from,
+ to,
+ dx,
+ refX,
+ attr,
+ w = 3,
+ h = 3,
+ t = 5;
+ while (i--) {
+ switch (values[i]) {
+ case "block":
+ case "classic":
+ case "oval":
+ case "diamond":
+ case "open":
+ case "none":
+ type = values[i];
+ break;
+ case "wide":
+ h = 5;
+ break;
+ case "narrow":
+ h = 2;
+ break;
+ case "long":
+ w = 5;
+ break;
+ case "short":
+ w = 2;
+ break;
+ }
+ }
+ if (type == "open") {
+ w += 2;
+ h += 2;
+ t += 2;
+ dx = 1;
+ refX = isEnd ? 4 : 1;
+ attr = {
+ fill: "none",
+ stroke: attrs.stroke
+ };
+ } else {
+ refX = dx = w / 2;
+ attr = {
+ fill: attrs.stroke,
+ stroke: "none"
+ };
+ }
+ if (o._.arrows) {
+ if (isEnd) {
+ o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
+ o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
+ } else {
+ o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
+ o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
+ }
+ } else {
+ o._.arrows = {};
+ }
+ if (type != "none") {
+ var pathId = "raphael-marker-" + type,
+ markerId = "raphael-marker-" + se + type + w + h + "-obj" + o.id;
+ if (!R._g.doc.getElementById(pathId)) {
+ p.defs.appendChild($($("path"), {
+ "stroke-linecap": "round",
+ d: markers[type],
+ id: pathId
+ }));
+ markerCounter[pathId] = 1;
+ } else {
+ markerCounter[pathId]++;
+ }
+ var marker = R._g.doc.getElementById(markerId),
+ use;
+ if (!marker) {
+ marker = $($("marker"), {
+ id: markerId,
+ markerHeight: h,
+ markerWidth: w,
+ orient: "auto",
+ refX: refX,
+ refY: h / 2
+ });
+ use = $($("use"), {
+ "xlink:href": "#" + pathId,
+ transform: (isEnd ? "rotate(180 " + w / 2 + " " + h / 2 + ") " : E) + "scale(" + w / t + "," + h / t + ")",
+ "stroke-width": (1 / ((w / t + h / t) / 2)).toFixed(4)
+ });
+ marker.appendChild(use);
+ p.defs.appendChild(marker);
+ markerCounter[markerId] = 1;
+ } else {
+ markerCounter[markerId]++;
+ use = marker.getElementsByTagName("use")[0];
+ }
+ $(use, attr);
+ var delta = dx * (type != "diamond" && type != "oval");
+ if (isEnd) {
+ from = o._.arrows.startdx * stroke || 0;
+ to = R.getTotalLength(attrs.path) - delta * stroke;
+ } else {
+ from = delta * stroke;
+ to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
+ }
+ attr = {};
+ attr["marker-" + se] = "url('" + R._url + "#" + markerId + "')";
+ if (to || from) {
+ attr.d = Raphael.getSubpath(attrs.path, from, to);
+ }
+ $(node, attr);
+ o._.arrows[se + "Path"] = pathId;
+ o._.arrows[se + "Marker"] = markerId;
+ o._.arrows[se + "dx"] = delta;
+ o._.arrows[se + "Type"] = type;
+ o._.arrows[se + "String"] = value;
+ } else {
+ if (isEnd) {
+ from = o._.arrows.startdx * stroke || 0;
+ to = R.getTotalLength(attrs.path) - from;
+ } else {
+ from = 0;
+ to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
+ }
+ o._.arrows[se + "Path"] && $(node, {
+ d: Raphael.getSubpath(attrs.path, from, to)
+ });
+ delete o._.arrows[se + "Path"];
+ delete o._.arrows[se + "Marker"];
+ delete o._.arrows[se + "dx"];
+ delete o._.arrows[se + "Type"];
+ delete o._.arrows[se + "String"];
+ }
+ for (attr in markerCounter)
+ if (markerCounter[has](attr) && !markerCounter[attr]) {
+ var item = R._g.doc.getElementById(attr);
+ item && item.parentNode.removeChild(item);
+ }
+ }
+ },
+ dasharray = {
+ "": [0],
+ "none": [0],
+ "-": [3, 1],
+ ".": [1, 1],
+ "-.": [3, 1, 1, 1],
+ "-..": [3, 1, 1, 1, 1, 1],
+ ". ": [1, 3],
+ "- ": [4, 3],
+ "--": [8, 3],
+ "- .": [4, 3, 1, 3],
+ "--.": [8, 3, 1, 3],
+ "--..": [8, 3, 1, 3, 1, 3]
+ },
+ addDashes = function(o, value, params) {
+ var predefValue = dasharray[Str(value).toLowerCase()];
+ value = predefValue || ((value !== undefined) && [].concat(value));
+ if (value) {
+ var width = o.attrs["stroke-width"] || "1",
+ butt = {
+ round: width,
+ square: width,
+ butt: 0
+ }[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
+ i,
+ l = i = value.length;
+ if (predefValue) {
+ while (i--) {
+ value[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
+ }
+ }
+ else {
+ for (i = 0; i < l; i += 2) {
+ value[i] -= butt;
+ value[i + 1] && (value[i + 1] += butt);
+ if (value[i] <= 0) {
+ value[i] = 0.1;
+ }
+ }
+ }
+ if (R.is(value, 'array')) {
+ $(o.node, {
+ "stroke-dasharray": value.join(",")
+ });
+ }
+ }
+ },
+ setFillAndStroke = R._setFillAndStroke = function(o, params) {
+ if (!o.paper.canvas) {
+ return;
+ }
+ var node = o.node,
+ attrs = o.attrs,
+ paper = o.paper,
+ s = node.style,
+ vis = s.visibility;
+
+ s.visibility = "hidden";
+ for (var att in params) {
+ if (params[has](att)) {
+ if (!R._availableAttrs[has](att)) {
+ continue;
+ }
+ var value = params[att];
+ attrs[att] = value;
+ switch (att) {
+ case "blur":
+ o.blur(value);
+ break;
+ case "href":
+ case "title":
+ case "target":
+ var pn = node.parentNode;
+ if (pn.tagName.toLowerCase() != "a") {
+ if (value == E) { break; }
+ var hl = $("a");
+ pn.insertBefore(hl, node);
+ hl.appendChild(node);
+ pn = hl;
+ }
+ if (att == "target") {
+ pn.setAttributeNS(xlink, "show", value == "blank" ? "new" : value);
+ } else {
+ pn.setAttributeNS(xlink, att, value);
+ }
+ node.titleNode = pn;
+ break;
+ case "cursor":
+ s.cursor = value;
+ break;
+ case "transform":
+ o.transform(value);
+ break;
+ case "rotation":
+ if (R.is(value, "array")) {
+ o.rotate.apply(o, value);
+ }
+ else {
+ o.rotate(value);
+ }
+ break;
+ case "arrow-start":
+ addArrow(o, value);
+ break;
+ case "arrow-end":
+ addArrow(o, value, 1);
+ break;
+ case "clip-path":
+ var pathClip = true;
+ case "clip-rect":
+ var rect = !pathClip && Str(value).split(separator);
+ o._.clipispath = !!pathClip;
+ if (pathClip || rect.length == 4) {
+ o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
+ var el = $("clipPath"),
+ rc = $(pathClip ? "path" : "rect");
+ el.id = R.createUUID();
+ $(rc, pathClip ? {
+ d: value ? attrs['clip-path'] = R._pathToAbsolute(value) : R._availableAttrs.path,
+ fill: 'none'
+ } : {
+ x: rect[0],
+ y: rect[1],
+ width: rect[2],
+ height: rect[3],
+ transform: o.matrix.invert()
+ });
+ el.appendChild(rc);
+ paper.defs.appendChild(el);
+ $(node, {
+ "clip-path": "url('" + R._url +"#" + el.id + "')"
+ });
+ o.clip = rc;
+ }
+ if (!value) {
+ var path = node.getAttribute("clip-path");
+ if (path) {
+ var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E));
+ clip && clip.parentNode.removeChild(clip);
+ $(node, {
+ "clip-path": E
+ });
+ delete o.clip;
+ }
+ }
+ break;
+ case "path":
+ if (o.type == "path") {
+ $(node, {
+ d: value ? attrs.path = R._pathToAbsolute(value) : R._availableAttrs.path
+ });
+ o._.dirty = 1;
+ if (o._.arrows) {
+ "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+ "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+ }
+ }
+ break;
+ case "width":
+ node.setAttribute(att, value);
+ o._.dirty = 1;
+ if (attrs.fx) {
+ att = "x";
+ value = attrs.x;
+ } else {
+ break;
+ }
+ case "x":
+ if (attrs.fx) {
+ value = -attrs.x - (attrs.width || 0);
+ }
+ case "rx":
+ if (att == "rx" && o.type == "rect") {
+ break;
+ }
+ case "cx":
+ node.setAttribute(att, value);
+ o.pattern && updatePosition(o);
+ o._.dirty = 1;
+ break;
+ case "height":
+ node.setAttribute(att, value);
+ o._.dirty = 1;
+ if (attrs.fy) {
+ att = "y";
+ value = attrs.y;
+ } else {
+ break;
+ }
+ case "y":
+ if (attrs.fy) {
+ value = -attrs.y - (attrs.height || 0);
+ }
+ case "ry":
+ if (att == "ry" && o.type == "rect") {
+ break;
+ }
+ case "cy":
+ node.setAttribute(att, value);
+ o.pattern && updatePosition(o);
+ o._.dirty = 1;
+ break;
+ case "r":
+ if (o.type == "rect") {
+ $(node, {
+ rx: value,
+ ry: value
+ });
+ } else {
+ node.setAttribute(att, value);
+ }
+ o._.dirty = 1;
+ break;
+ case "src":
+ if (o.type == "image") {
+ node.setAttributeNS(xlink, "href", value);
+ }
+ break;
+ case "stroke-width":
+ if (o._.sx != 1 || o._.sy != 1) {
+ value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
+ }
+ if (paper._vbSize) {
+ value *= paper._vbSize;
+ }
+ if (zeroStrokeFix && value === 0) {
+ value = 0.000001;
+ }
+ node.setAttribute(att, value);
+ if (attrs["stroke-dasharray"]) {
+ addDashes(o, attrs["stroke-dasharray"], params);
+ }
+ if (o._.arrows) {
+ "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+ "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+ }
+ break;
+ case "stroke-dasharray":
+ addDashes(o, value, params);
+ break;
+ case "fill":
+ var isURL = Str(value).match(R._ISURL);
+ if (isURL) {
+ el = $("pattern");
+ var ig = $("image");
+ el.id = R.createUUID();
+ $(el, {
+ x: 0,
+ y: 0,
+ patternUnits: "userSpaceOnUse",
+ height: 1,
+ width: 1
+ });
+ $(ig, {
+ x: 0,
+ y: 0,
+ "xlink:href": isURL[1]
+ });
+ el.appendChild(ig);
+
+ (function(el) {
+ R._preload(isURL[1], function() {
+ var w = this.offsetWidth,
+ h = this.offsetHeight;
+ $(el, {
+ width: w,
+ height: h
+ });
+ $(ig, {
+ width: w,
+ height: h
+ });
+ paper.safari();
+ });
+ })(el);
+ paper.defs.appendChild(el);
+ $(node, {
+ fill: "url('" + R._url + "#" + el.id + "')"
+ });
+ o.pattern = el;
+ o.pattern && updatePosition(o);
+ break;
+ }
+ var clr = R.getRGB(value);
+ if (!clr.error) {
+ delete params.gradient;
+ delete attrs.gradient;
+ !R.is(attrs.opacity, "undefined") &&
+ R.is(params.opacity, "undefined") &&
+ $(node, {
+ opacity: attrs.opacity
+ });
+ !R.is(attrs["fill-opacity"], "undefined") &&
+ R.is(params["fill-opacity"], "undefined") &&
+ $(node, {
+ "fill-opacity": attrs["fill-opacity"]
+ });
+ } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
+ if ("opacity" in attrs || "fill-opacity" in attrs) {
+ var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
+ if (gradient) {
+ var stops = gradient.getElementsByTagName("stop");
+ $(stops[stops.length - 1], {
+ "stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)
+ });
+ }
+ }
+ attrs.gradient = value;
+ attrs.fill = "none";
+ break;
+ }
+ if (clr[has]("opacity")) {
+ $(node, {
+ "fill-opacity": (s.fillOpacity =
+ (clr.opacity > 1 ? clr.opacity / 100 : clr.opacity))
+ });
+ o._.opacitydirty = true;
+ }
+ else if (o._.opacitydirty && R.is(attrs['fill-opacity'], "undefined") &&
+ R.is(params["fill-opacity"], "undefined")) {
+ node.removeAttribute('fill-opacity');
+ s.fillOpacity = E;
+ delete o._.opacitydirty;
+ }
+ case "stroke":
+ clr = R.getRGB(value);
+ node.setAttribute(att, clr.hex);
+ att == "stroke" && clr[has]("opacity") && $(node, {
+ "stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity
+ });
+ if (att == "stroke" && o._.arrows) {
+ "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+ "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+ }
+ break;
+ case "gradient":
+ (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
+ break;
+ case 'line-height': // do not apply
+ case 'vertical-align': // do not apply
+ break;
+ case "visibility":
+ value === 'hidden' ? o.hide() : o.show();
+ break;
+ case "opacity":
+ if (attrs.gradient && !attrs[has]("stroke-opacity")) {
+ $(node, {
+ "stroke-opacity": value > 1 ? value / 100 : value
+ });
+ }
+ // fall
+ case "fill-opacity":
+ if (attrs.gradient) {
+ gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
+ if (gradient) {
+ stops = gradient.getElementsByTagName("stop");
+ $(stops[stops.length - 1], {
+ "stop-opacity": value
+ });
+ }
+ break;
+ }
+ default:
+ att == "font-size" && (value = toInt(value, 10) + "px");
+ var cssrule = att.replace(/(\-.)/g, function(w) {
+ return w.substring(1).toUpperCase();
+ });
+ s[cssrule] = value;
+ o._.dirty = 1;
+ node.setAttribute(att, value);
+ break;
+ }
+ }
+ }
+
+ tuneText(o, params);
+ s.visibility = vis;
+ },
+ leading = 1.2,
+ tuneText = function(el, params) {
+ if (el.type != "text" || !(params[has]("text") || params[has]("font") ||
+ params[has]("font-size") || params[has]("x") || params[has]("y") ||
+ params[has]("line-height") || params[has]("vertical-align"))) {
+ return;
+ }
+ var a = el.attrs,
+ node = el.node,
+ computedStyle = node.firstChild && R._g.doc.defaultView.getComputedStyle(node.firstChild, E),
+ fontSize = computedStyle ? toFloat(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size")) : 10,
+ lineHeight = toFloat(params['line-height'] || a['line-height']) || fontSize * leading,
+ valign = a[has]("vertical-align") ? a["vertical-align"] : "middle";
+
+ if (isNaN(lineHeight)) {
+ lineHeight = fontSize * leading;
+ }
+
+ valign = valign === 'top' ? -0.5 : (valign === 'bottom' ? 0.5 : 0);
+
+ if (params[has]("text") && (params.text !== a.text || el._textdirty)) {
+ a.text = params.text;
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ var texts = Str(params.text).split(/\n| /ig),
+ tspans = [],
+ tspan;
+ for (var i = 0, ii = texts.length; i < ii; i++) {
+ tspan = $("tspan");
+ if (i) {
+ $(tspan, {
+ dy: lineHeight,
+ x: a.x
+ });
+ } else {
+ $(tspan, {
+ dy: lineHeight * texts.length * valign,
+ x: a.x
+ });
+ }
+ if (!texts[i]) { // preserve blank lines
+ tspan.setAttributeNS("http://www.w3.org/XML/1998/namespace",
+ "xml:space","preserve");
+ texts[i] = " ";
+ }
+ tspan.appendChild(R._g.doc.createTextNode(texts[i]));
+ node.appendChild(tspan);
+ tspans[i] = tspan;
+ }
+ el._textdirty = false;
+ } else {
+ tspans = node.getElementsByTagName("tspan");
+ for (i = 0, ii = tspans.length; i < ii; i++)
+ if (i) {
+ $(tspans[i], {
+ dy: lineHeight,
+ x: a.x
+ });
+ } else {
+ $(tspans[0], {
+ dy: lineHeight * tspans.length * valign,
+ x: a.x
+ });
+ }
+ }
+ $(node, {
+ x: a.x,
+ y: a.y
+ });
+ el._.dirty = 1;
+ var bb = el._getBBox(),
+ dif = a.y - (bb.y + bb.height / 2);
+
+ // If the bbox is calculated then we need to make additional adjustments,
+ // to account for the fact that the calculated bbox already has the
+ // text alignment, both horizontal and vertical, included in the calculation.
+ if (bb.isCalculated) {
+ switch (a['vertical-align']) {
+ case "top":
+ dif = bb.height * .75;
+ break;
+ case "bottom":
+ dif = - (bb.height * .25);
+ break;
+ default:
+ dif = a.y - (bb.y + bb.height * .25);
+ break;
+ };
+ }
+
+ dif && R.is(dif, "finite") && tspans[0] && $(tspans[0], {
+ dy: dif
+ });
+ },
+ Element = function(node, svg, group) {
+ var o = this,
+ parent = group || svg;
+
+ o.node = o[0] = node;
+ node.raphael = true;
+ node.raphaelid = o.id = R._oid++;
+
+ o.matrix = R.matrix();
+ o.realPath = null;
+
+ o.attrs = o.attrs || {};
+ o.styles = o.styles || {};
+ o.followers = o.followers || [];
+
+ o.paper = svg;
+ o.ca = o.customAttributes = o.customAttributes ||
+ new svg._CustomAttributes();
+
+ o._ = {
+ transform: [],
+ sx: 1,
+ sy: 1,
+ deg: 0,
+ dx: 0,
+ dy: 0,
+ dirty: 1
+ };
+
+ o.parent = parent;
+ !parent.bottom && (parent.bottom = o);
+
+ o.prev = parent.top;
+ parent.top && (parent.top.next = o);
+ parent.top = o;
+ o.next = null;
+ },
+ elproto = R.el;
+
+ Element.prototype = elproto;
+ elproto.constructor = Element;
+
+ R._engine.getNode = function (el) {
+ var node = el.node || el[0].node;
+ return node.titleNode || node;
+ };
+ R._engine.getLastNode = function (el) {
+ var node = el.node || el[el.length - 1].node;
+ return node.titleNode || node;
+ };
+
+ R._engine.path = function(pathString, SVG, group) {
+ var el = $("path");
+
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (SVG.canvas && SVG.canvas.appendChild(el));
+
+ var p = new Element(el, SVG, group);
+ p.type = "path";
+ setFillAndStroke(p, {
+ fill: "none",
+ stroke: "#000",
+ path: pathString
+ });
+ return p;
+ };
+
+ elproto.rotate = function(deg, cx, cy) {
+ var o = this,
+ bbox;
+ if (o.removed) {
+ return o;
+ }
+ deg = Str(deg).split(separator);
+ if (deg.length - 1) {
+ cx = toFloat(deg[1]);
+ cy = toFloat(deg[2]);
+ }
+ deg = toFloat(deg[0]);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ bbox = o.getBBox(1);
+ cx = bbox.x + bbox.width / 2;
+ cy = bbox.y + bbox.height / 2;
+ }
+ o.transform(o._.transform.concat([["r", deg, cx, cy]]));
+ return o;
+ };
+
+ elproto.scale = function(sx, sy, cx, cy) {
+ var o = this,
+ bbox;
+ if (o.removed) {
+ return o;
+ }
+ sx = Str(sx).split(separator);
+ if (sx.length - 1) {
+ sy = toFloat(sx[1]);
+ cx = toFloat(sx[2]);
+ cy = toFloat(sx[3]);
+ }
+ sx = toFloat(sx[0]);
+ (sy == null) && (sy = sx);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ bbox = o.getBBox(1);
+ }
+ cx = cx == null ? bbox.x + bbox.width / 2 : cx;
+ cy = cy == null ? bbox.y + bbox.height / 2 : cy;
+ o.transform(o._.transform.concat([["s", sx, sy, cx, cy]]));
+ return o;
+ };
+
+ elproto.translate = function(dx, dy) {
+ var o = this;
+ if (o.removed) {
+ return o;
+ }
+ dx = Str(dx).split(separator);
+ if (dx.length - 1) {
+ dy = toFloat(dx[1]);
+ }
+ dx = toFloat(dx[0]) || 0;
+ dy = +dy || 0;
+ o.transform(o._.transform.concat([["t", dx, dy]]));
+ return o;
+ };
+
+ elproto.transform = function(tstr) {
+ var o = this,
+ _ = o._,
+ sw;
+
+ if (tstr == null) {
+ return _.transform;
+ }
+ R._extractTransform(o, tstr);
+
+ o.clip && !_.clipispath && $(o.clip, {
+ transform: o.matrix.invert()
+ });
+ o.pattern && updatePosition(o);
+ o.node && $(o.node, {
+ transform: o.matrix
+ });
+
+ if (_.sx != 1 || _.sy != 1) {
+ sw = o.attrs[has]("stroke-width") ? o.attrs["stroke-width"] : 1;
+ o.attr({
+ "stroke-width": sw
+ });
+ }
+
+ return o;
+ };
+
+ elproto.hide = function() {
+ var o = this;
+ !o.removed && o.paper.safari(o.node.style.display = "none");
+ return o;
+ };
+
+ elproto.show = function() {
+ var o = this;
+ !o.removed && o.paper.safari(o.node.style.display = E);
+ return o;
+ };
+
+ elproto.remove = function() {
+ if (this.removed || !this.parent.canvas) {
+ return;
+ }
+
+ var o = this,
+ node = R._engine.getNode(o),
+ paper = o.paper,
+ defs = paper.defs,
+ i;
+
+
+ paper.__set__ && paper.__set__.exclude(o);
+ eve.unbind("raphael.*.*." + o.id);
+
+ if (o.gradient && defs) {
+ defs.removeChild(o.gradient);
+ }
+ while (i = o.followers.pop()) {
+ i.el.remove();
+ }
+ o.parent.canvas.removeChild(node);
+ R._tear(o, paper);
+ for (i in o) {
+ o[i] = typeof o[i] === "function" ? R._removedFactory(i) : null;
+ }
+ o.removed = true;
+ };
+ elproto._getBBox = function() {
+ var o = this,
+ node = o.node,
+ bbox = {},
+ a = o.attrs,
+ align,
+ hide;
+
+ if (node.style.display === "none") {
+ o.show();
+ hide = true;
+ }
+
+ try {
+ bbox = node.getBBox();
+
+ if (o.type == "text") {
+ // If bbox does not have x / y, which is possible in certain
+ // environments, we mathematically calculate these values by
+ // using x, y (adjusted using the values of text-anchor, and
+ // vertical-align attributes), of the element along with the
+ // width and height provided by the getBBox().
+ if (bbox.x === undefined) {
+ bbox.isCalculated = true;
+ align = a['text-anchor'];
+ bbox.x = (a.x || 0) - (bbox.width * ((align === "start") ?
+ 0 : (align === "middle") ? 0.5 : 1));
+ }
+
+ if (bbox.y === undefined) {
+ bbox.isCalculated = true;
+ align = a['vertical-align'];
+ bbox.y = (a.y || 0) - (bbox.height * ((align === "bottom") ?
+ 1 : (align === "middle") ? 0.5 : 0));
+ }
+ }
+
+ } catch (e) {
+ // Firefox 3.0.x plays badly here
+ } finally {
+ bbox = bbox || {};
+ }
+ hide && o.hide();
+ return bbox;
+ };
+
+ elproto.css = function (name, value) {
+ // do not parse css in case element is removed.
+ if (this.removed) {
+ return this;
+ }
+
+ // process as getter when a single key is sent as parameter.
+ if (value == null && R.is(name, "string")) {
+ var names = name.split(separator),
+ out = {};
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in this.styles) {
+ out[name] = this.styles[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+ // process as getter when multiple keys are pre-sent as array.
+ if (value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = this.styles(name[i]);
+ }
+ return out;
+ }
+ // convert single key-value setter into object style standard.
+ if (value != null) {
+ var params = {};
+ params[name] = value;
+ } else if (name != null && R.is(name, "object")) {
+ params = name;
+ }
+ // iterate on keys and set style or raise events.
+ var otherkey, doattrs = {};
+ for (var key in params) {
+ otherkey = key.replace(/\B([A-Z]{1})/g, "-$1").toLowerCase();
+
+ // If keys are supported via attr then use attr instead of css.
+ if (R._availableAttrs[has](otherkey) || otherkey === 'color') {
+ // Replace "color" with fill
+ (otherkey === 'color' && this.type === 'text') && (otherkey = 'fill');
+
+ doattrs[otherkey] = params[key];
+ doattrs.dirty = true;
+ continue;
+ }
+ eve("raphael.css." + otherkey + "." + this.id, this, params[key], otherkey);
+ this.node.style[otherkey] = params[key];
+ this.styles[otherkey] = params[key];
+ }
+ // run on followers
+ for (i = 0, ii = this.followers.length; i < ii; i++) {
+ this.followers[i].el.css(params);
+ }
+ // apply css via attrs
+ if (doattrs[has]("dirty")) {
+ delete doattrs.dirty;
+ this.attr(doattrs);
+ }
+ return this;
+ };
+
+ elproto.attr = function(name, value) {
+ if (this.removed) {
+ return this;
+ }
+ if (name == null) {
+ var res = {};
+ for (var a in this.attrs)
+ if (this.attrs[has](a)) {
+ res[a] = this.attrs[a];
+ }
+ res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
+ res.transform = this._.transform;
+ res.visibility = this.node.style.display === "none" ? "hidden" : "visible";
+ return res;
+ }
+ if (value == null && R.is(name, "string")) {
+ if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
+ return this.attrs.gradient;
+ }
+ if (name == "transform") {
+ return this._.transform;
+ }
+ if (name == "visibility") {
+ return this.node.style.display === "none" ? "hidden" : "visible";
+ }
+ var names = name.split(separator),
+ out = {};
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in this.attrs) {
+ out[name] = this.attrs[name];
+ } else if (R.is(this.ca[name], "function")) {
+ out[name] = this.ca[name].def;
+ } else {
+ out[name] = R._availableAttrs[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+ if (value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = this.attr(name[i]);
+ }
+ return out;
+ }
+ if (value != null) {
+ var params = {};
+ params[name] = value;
+ } else if (name != null && R.is(name, "object")) {
+ params = name;
+ }
+ for (var key in params) {
+ eve("raphael.attr." + key + "." + this.id, this, params[key], key);
+ }
+ var todel = {};
+ for (key in this.ca) {
+ if (this.ca[key] && params[has](key) && R.is(this.ca[key], "function") && !this.ca['_invoked' + key]) {
+
+ this.ca['_invoked'+key] = true; // prevent recursion
+ var par = this.ca[key].apply(this, [].concat(params[key]));
+ delete this.ca['_invoked'+key];
+
+ for (var subkey in par) {
+ if (par[has](subkey)) {
+ params[subkey] = par[subkey];
+ }
+ }
+ this.attrs[key] = params[key];
+ if (par === false) {
+ todel[key] = params[key];
+ delete params[key];
+ }
+ }
+ }
+
+ setFillAndStroke(this, params);
+
+ var follower;
+ for (i = 0, ii = this.followers.length; i < ii; i++) {
+ follower = this.followers[i];
+ (follower.cb && !follower.cb.call(follower.el, params, this)) ||
+ follower.el.attr(params);
+ }
+
+ for (subkey in todel) {
+ params[subkey] = todel[subkey];
+ }
+ return this;
+ };
+
+ elproto.blur = function(size) {
+ // Experimental. No Safari support. Use it on your own risk.
+ var t = this;
+ if (+size !== 0) {
+ var fltr = $("filter"),
+ blur = $("feGaussianBlur");
+ t.attrs.blur = size;
+ fltr.id = R.createUUID();
+ $(blur, {
+ stdDeviation: +size || 1.5
+ });
+ fltr.appendChild(blur);
+ t.paper.defs.appendChild(fltr);
+ t._blur = fltr;
+ $(t.node, {
+ filter: "url('" + R._url + "#" + fltr.id + "')"
+ });
+ } else {
+ if (t._blur) {
+ t._blur.parentNode.removeChild(t._blur);
+ delete t._blur;
+ delete t.attrs.blur;
+ }
+ t.node.removeAttribute("filter");
+ }
+ };
+
+ elproto.on = function(eventType, handler) {
+ if (this.removed) {
+ return this;
+ }
+
+ var fn = handler;
+ if (R.supportsTouch) {
+ eventType = R._touchMap[eventType] ||
+ (eventType === 'click' && 'touchstart') || eventType;
+ fn = function(e) {
+ e.preventDefault();
+ handler();
+ };
+ }
+ this.node['on'+ eventType] = fn;
+ return this;
+ };
+
+
+ R._engine.group = function(svg, id, group) {
+ var el = $("g");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var g = new Element(el, svg, group);
+ g.type = "group";
+ g.canvas = g.node;
+ g.top = null;
+ g.bottom = null;
+ id && el.setAttribute('class', ['red', id, g.id].join('-'));
+
+ return g;
+ };
+
+ R._engine.circle = function(svg, x, y, r, group) {
+ var el = $("circle");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ cx: x,
+ cy: y,
+ r: r,
+ fill: "none",
+ stroke: "#000"
+ };
+ res.type = "circle";
+ $(el, res.attrs);
+ return res;
+ };
+ R._engine.rect = function(svg, x, y, w, h, r, group) {
+ var el = $("rect");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ x: x,
+ y: y,
+ width: w,
+ height: h,
+ r: r || 0,
+ rx: r || 0,
+ ry: r || 0,
+ fill: "none",
+ stroke: "#000"
+ };
+ res.type = "rect";
+ $(el, res.attrs);
+ return res;
+ };
+ R._engine.ellipse = function(svg, x, y, rx, ry, group) {
+ var el = $("ellipse");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ cx: x,
+ cy: y,
+ rx: rx,
+ ry: ry,
+ fill: "none",
+ stroke: "#000"
+ };
+ res.type = "ellipse";
+ $(el, res.attrs);
+ return res;
+ };
+ R._engine.image = function(svg, src, x, y, w, h, group) {
+ var el = $("image");
+ $(el, {
+ x: x,
+ y: y,
+ width: w,
+ height: h,
+ preserveAspectRatio: "none"
+ });
+ el.setAttributeNS(xlink, "href", src);
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ x: x,
+ y: y,
+ width: w,
+ height: h,
+ src: src
+ };
+ res.type = "image";
+ return res;
+ };
+ R._engine.text = function(svg, x, y, text, group) {
+ var el = $("text");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ x: x,
+ y: y,
+ "text-anchor": "middle",
+ "vertical-align": "middle",
+ text: text,
+ //font: R._availableAttrs.font,
+ stroke: "none",
+ fill: "#000"
+ };
+ res.type = "text";
+ res._textdirty = true;
+ setFillAndStroke(res, res.attrs);
+ return res;
+ };
+ /* @diffend */
+
+ R._engine.setSize = function(width, height) {
+ this.width = width || this.width;
+ this.height = height || this.height;
+ this.canvas.setAttribute("width", this.width);
+ this.canvas.setAttribute("height", this.height);
+ if (this._viewBox) {
+ this.setViewBox.apply(this, this._viewBox);
+ }
+ return this;
+ };
+ R._engine.create = function() {
+ var con = R._getContainer.apply(0, arguments),
+ container = con && con.container,
+ x = con.x,
+ y = con.y,
+ width = con.width,
+ height = con.height;
+ if (!container) {
+ throw new Error("SVG container not found.");
+ }
+ var cnvs = $("svg"),
+ css = "overflow:hidden;-webkit-tap-highlight-color:rgba(0,0,0,0);"+
+ "-webkit-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;"+
+ "-ms-user-select:none;user-select:none;-o-user-select:none;cursor:default;",
+ isFloating;
+ x = x || 0;
+ y = y || 0;
+ width = width || 512;
+ height = height || 342;
+ $(cnvs, {
+ height: height,
+ version: 1.1,
+ width: width,
+ xmlns: "http://www.w3.org/2000/svg"
+ });
+ if (container == 1) {
+ cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
+ R._g.doc.body.appendChild(cnvs);
+ isFloating = 1;
+ } else {
+ cnvs.style.cssText = css + "position:relative";
+ if (container.firstChild) {
+ container.insertBefore(cnvs, container.firstChild);
+ } else {
+ container.appendChild(cnvs);
+ }
+ }
+ container = new R._Paper;
+ container.width = width;
+ container.height = height;
+ container.canvas = cnvs;
+ container.clear();
+ container._left = container._top = 0;
+ isFloating && (container.renderfix = function() {
+ });
+ container.renderfix();
+ return container;
+ };
+ R._engine.setViewBox = function(x, y, w, h, fit) {
+ eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]);
+ var size = mmax(w / this.width, h / this.height),
+ top = this.top,
+ aspectRatio = fit ? "meet" : "xMinYMin",
+ vb,
+ sw;
+ if (x == null) {
+ if (this._vbSize) {
+ size = 1;
+ }
+ delete this._vbSize;
+ vb = "0 0 " + this.width + S + this.height;
+ } else {
+ this._vbSize = size;
+ vb = x + S + y + S + w + S + h;
+ }
+ $(this.canvas, {
+ viewBox: vb,
+ preserveAspectRatio: aspectRatio
+ });
+ while (size && top) {
+ sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
+ top.attr({
+ "stroke-width": sw
+ });
+ top._.dirty = 1;
+ top._.dirtyT = 1;
+ top = top.prev;
+ }
+ this._viewBox = [x, y, w, h, !!fit];
+ return this;
+ };
+
+ R.prototype.renderfix = function() {
+ var cnvs = this.canvas,
+ s = cnvs.style,
+ pos;
+ try {
+ pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix();
+ } catch (e) {
+ pos = cnvs.createSVGMatrix();
+ }
+ var left = -pos.e % 1,
+ top = - pos.f % 1;
+ if (left || top) {
+ if (left) {
+ this._left = (this._left + left) % 1;
+ s.left = this._left + "px";
+ }
+ if (top) {
+ this._top = (this._top + top) % 1;
+ s.top = this._top + "px";
+ }
+ }
+ };
+
+ R.prototype.clear = function() {
+ eve("raphael.clear", this);
+ var c = this.canvas;
+ while (c.firstChild) {
+ c.removeChild(c.firstChild);
+ }
+ this.bottom = this.top = null;
+ (this.desc = $("desc")).appendChild(R._g.doc.createTextNode(R.is(R.desc, "string") && R.desc ||
+ "Created with Red Rapha\xebl " + R.version));
+ c.appendChild(this.desc);
+ c.appendChild(this.defs = $("defs"));
+ };
+
+ R.prototype.remove = function() {
+ eve("raphael.remove", this);
+ this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
+ for (var i in this) {
+ this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+ }
+ this.removed = true;
+ };
+ var setproto = R.st;
+ for (var method in elproto)
+ if (elproto[has](method) && !setproto[has](method)) {
+ setproto[method] = (function(methodname) {
+ return function() {
+ var arg = arguments;
+ return this.forEach(function(el) {
+ el[methodname].apply(el, arg);
+ });
+ };
+ })(method);
+ }
+})();
+
+/**!
+* RedRaphael 1.0.0 - JavaScript Vector Library VML Module
+* Copyright (c) 2012-2013 FusionCharts Technologies
+*
+* Raphael 2.1.0 - JavaScript Vector Library VML Module
+* Copyright (c) 2008-2012 Dmitry Baranovskiy
+* Copyright © 2008-2012 Sencha Labs
+*
+* Licensed under the MIT license.
+*/
+
+(function(){
+ if (!R.vml) {
+ return;
+ }
+ var has = "hasOwnProperty",
+ Str = String,
+ toFloat = parseFloat,
+ math = Math,
+ round = math.round,
+ mmax = math.max,
+ mmin = math.min,
+ sqrt = math.sqrt,
+ abs = math.abs,
+ fillString = "fill",
+ separator = /[, ]+/,
+ eve = R.eve,
+ ms = " progid:DXImageTransform.Microsoft",
+ S = " ",
+ E = "",
+ map = {
+ M: "m",
+ L: "l",
+ C: "c",
+ Z: "x",
+ m: "t",
+ l: "r",
+ c: "v",
+ z: "x"
+ },
+ bites = /([clmz]),?([^clmz]*)/gi,
+ blurregexp = / progid:\S+Blur\([^\)]+\)/g,
+ val = /-?[^,\s-]+/g,
+ cssDot = "position:absolute;left:0;top:0;width:1px;height:1px",
+ zoom = 21600,
+ pathTypes = {
+ path: 1,
+ rect: 1,
+ image: 1
+ },
+ ovalTypes = {
+ circle: 1,
+ ellipse: 1
+ },
+ path2vml = function(path) {
+ var total = /[ahqstv]/ig,
+ command = R._pathToAbsolute;
+ Str(path).match(total) && (command = R._path2curve);
+ total = /[clmz]/g;
+ if (command == R._pathToAbsolute && !Str(path).match(total)) {
+ var res = Str(path).replace(bites, function(all, command, args) {
+ var vals = [],
+ isMove = command.toLowerCase() == "m",
+ res = map[command];
+ args.replace(val, function(value) {
+ if (isMove && vals.length == 2) {
+ res += vals + map[command == "m" ? "l" : "L"];
+ vals = [];
+ }
+ vals.push(round(value * zoom));
+ });
+ return res + vals;
+ });
+
+ return res || 'm0,0';
+ }
+ var pa = command(path), p, r;
+ res = [];
+ for (var i = 0, ii = pa.length; i < ii; i++) {
+ p = pa[i];
+ r = pa[i][0].toLowerCase();
+ r == "z" && (r = "x");
+ for (var j = 1, jj = p.length; j < jj; j++) {
+ r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
+ }
+ res.push(r);
+ }
+ return res.length ? res.join(S) : 'm0,0';
+ },
+ compensation = function(deg, dx, dy) {
+ var m = R.matrix();
+ m.rotate(-deg, .5, .5);
+ return {
+ dx: m.x(dx, dy),
+ dy: m.y(dx, dy)
+ };
+ },
+ setCoords = function(p, sx, sy, dx, dy, deg) {
+ var _ = p._,
+ m = p.matrix,
+ fillpos = _.fillpos,
+ o = p.node,
+ s = o.style,
+ y = 1,
+ flip = "",
+ dxdy,
+ kx = zoom / sx,
+ ky = zoom / sy;
+ s.visibility = "hidden";
+ if (!sx || !sy) {
+ return;
+ }
+ o.coordsize = abs(kx) + S + abs(ky);
+ s.rotation = deg * (sx * sy < 0 ? -1 : 1);
+ if (deg) {
+ var c = compensation(deg, dx, dy);
+ dx = c.dx;
+ dy = c.dy;
+ }
+ sx < 0 && (flip += "x");
+ sy < 0 && (flip += " y") && (y = -1);
+ s.flip = flip;
+ o.coordorigin = (dx * -kx) + S + (dy * -ky);
+ if (fillpos || _.fillsize) {
+ var fill = o.getElementsByTagName(fillString);
+ fill = fill && fill[0];
+ o.removeChild(fill);
+ if (fillpos) {
+ c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1]));
+ fill.position = c.dx * y + S + c.dy * y;
+ }
+ if (_.fillsize) {
+ fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy);
+ }
+ o.appendChild(fill);
+ }
+ s.visibility = "visible";
+ };
+ R._url = E;
+ R.toString = function() {
+ return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
+ };
+ var addArrow = function(o, value, isEnd) {
+ var values = Str(value).toLowerCase().split("-"),
+ se = isEnd ? "end" : "start",
+ i = values.length,
+ type = "classic",
+ w = "medium",
+ h = "medium";
+ while (i--) {
+ switch (values[i]) {
+ case "block":
+ case "classic":
+ case "oval":
+ case "diamond":
+ case "open":
+ case "none":
+ type = values[i];
+ break;
+ case "wide":
+ case "narrow":
+ h = values[i];
+ break;
+ case "long":
+ case "short":
+ w = values[i];
+ break;
+ }
+ }
+ var stroke = o.node.getElementsByTagName("stroke")[0];
+ stroke[se + "arrow"] = type;
+ stroke[se + "arrowlength"] = w;
+ stroke[se + "arrowwidth"] = h;
+ },
+ setFillAndStroke = R._setFillAndStroke = function(o, params) {
+ if (!o.paper.canvas) return;
+ // o.paper.canvas.style.display = "none";
+ o.attrs = o.attrs || {};
+ var node = o.node,
+ a = o.attrs,
+ s = node.style,
+ xy,
+ newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r),
+ isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry),
+ isGroup = o.type === 'group',
+ res = o;
+
+
+ for (var par in params)
+ if (params[has](par)) {
+ a[par] = params[par];
+ }
+ if (newpath) {
+ a.path = R._getPath[o.type](o);
+ o._.dirty = 1;
+ }
+ params.href && (node.href = params.href);
+ params.title && (node.title = params.title);
+ params.target && (node.target = params.target);
+ params.cursor && (s.cursor = params.cursor);
+ "blur" in params && o.blur(params.blur);
+ if (params.path && o.type == "path" || newpath) {
+ node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path);
+ if (o.type == "image") {
+ o._.fillpos = [a.x, a.y];
+ o._.fillsize = [a.width, a.height];
+ setCoords(o, 1, 1, 0, 0, 0);
+ }
+ }
+ "transform" in params && o.transform(params.transform);
+ if ("rotation" in params) {
+ var rotation = params.rotation;
+ if (R.is(rotation, "array")) {
+ o.rotate.apply(o, rotation);
+ }
+ else {
+ o.rotate(rotation);
+ }
+ }
+ if ("visibility" in params) {
+ params.visibility === 'hidden' ? o.hide() : o.show();
+ }
+ if (isOval) {
+ var cx = +a.cx,
+ cy = +a.cy,
+ rx = +a.rx || +a.r || 0,
+ ry = + a.ry || + a.r || 0;
+ node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom));
+ }
+ if ("clip-rect" in params) {
+ var rect = Str(params["clip-rect"]).split(separator);
+
+ if (rect.length == 4) {
+ rect[0] = +rect[0];
+ rect[1] = +rect[1];
+ rect[2] = +rect[2] + rect[0];
+ rect[3] = +rect[3] + rect[1];
+
+ /* @todo create separate element for group clip-rect to
+ * avoid unclipping issue */
+ var div = isGroup ? node : (node.clipRect ||
+ R._g.doc.createElement("div")),
+ offset,
+ dstyle = div.style;
+
+ if (isGroup) {
+ o.clip = rect.slice(); // copy param
+ offset = o.matrix.offset();
+ offset = [toFloat(offset[0]), toFloat(offset[1])];
+ // invert matrix calculation
+ rect[0] -= offset[0];
+ rect[1] -= offset[1];
+ rect[2] -= offset[0];
+ rect[3] -= offset[1];
+ // Fix for bug in ie clip-auto when height/width is not defined
+ /* @todo set dynamic w/h based on clip bounds or find
+ * another workaround fix */
+ dstyle.width = "10800px";
+ dstyle.height = "10800px";
+ }
+ else if (!node.clipRect) {
+ dstyle.top = "0";
+ dstyle.left = "0";
+ dstyle.width = o.paper.width + "px";
+ dstyle.height = o.paper.height + "px";
+ node.parentNode.insertBefore(div, node);
+ div.appendChild(node);
+ node.clipRect = div;
+ }
+ dstyle.position = "absolute";
+ dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
+ }
+ if (!params["clip-rect"]) {
+ if (isGroup && o.clip) {
+ node.style.clip = "rect(auto auto auto auto)";
+ delete o.clip;
+ }
+ else if (node.clipRect) {
+ node.clipRect.style.clip = "rect(auto auto auto auto)";
+ }
+ }
+ }
+ if (o.textpath) {
+ var textpathStyle = o.textpath.style;
+ params.font && (textpathStyle.font = params.font);
+ params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"');
+ params["font-size"] && (textpathStyle.fontSize = params["font-size"]);
+ params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]);
+ params["font-style"] && (textpathStyle.fontStyle = params["font-style"]);
+ }
+ if ("arrow-start" in params) {
+ addArrow(res, params["arrow-start"]);
+ }
+ if ("arrow-end" in params) {
+ addArrow(res, params["arrow-end"], 1);
+ }
+ if (params.opacity != null ||
+ params["stroke-width"] != null ||
+ params.fill != null ||
+ params.src != null ||
+ params.stroke != null ||
+ params["stroke-width"] != null ||
+ params["stroke-opacity"] != null ||
+ params["fill-opacity"] != null ||
+ params["stroke-dasharray"] != null ||
+ params["stroke-miterlimit"] != null ||
+ params["stroke-linejoin"] != null ||
+ params["stroke-linecap"] != null) {
+ var fill = node.getElementsByTagName(fillString),
+ newfill = false,
+ fillOpacity = -1;
+ fill = fill && fill[0];
+ !fill && (newfill = fill = createNode(fillString));
+ if (o.type == "image" && params.src) {
+ fill.src = params.src;
+ }
+ params.fill && (fill.on = true);
+ if (fill.on == null || params.fill == "none" || params.fill === null) {
+ fill.on = false;
+ }
+ if (fill.on && params.fill) {
+ var isURL = Str(params.fill).match(R._ISURL);
+ if (isURL) {
+ fill.parentNode == node && node.removeChild(fill);
+ fill.rotate = true;
+ fill.src = isURL[1];
+ fill.type = "tile";
+ var bbox = o.getBBox(1);
+ fill.position = bbox.x + S + bbox.y;
+ o._.fillpos = [bbox.x, bbox.y];
+
+ R._preload(isURL[1], function() {
+ o._.fillsize = [this.offsetWidth, this.offsetHeight];
+ });
+ } else {
+ var color = R.getRGB(params.fill);
+ fill.color = color.hex;
+ fill.src = E;
+ fill.type = "solid";
+ if (color.error && (res.type in {
+ circle: 1,
+ ellipse: 1
+ } || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) {
+ a.fill = "none";
+ a.gradient = params.fill;
+ fill.rotate = false;
+ }
+ else if ("opacity" in color && !("fill-opacity" in params)) {
+ fillOpacity = color.opacity;
+ }
+ }
+ }
+ if (fillOpacity !== -1 || "fill-opacity" in params || "opacity" in params) {
+ var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+fillOpacity + 1 || 2) - 1);
+ opacity = mmin(mmax(opacity, 0), 1);
+ fill.opacity = opacity;
+ if (fill.src) {
+ fill.color = "none";
+ }
+ }
+ node.appendChild(fill);
+ var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
+ newstroke = false;
+ !stroke && (newstroke = stroke = createNode("stroke"));
+ if ((params.stroke && params.stroke != "none") ||
+ params["stroke-width"] ||
+ params["stroke-opacity"] != null ||
+ params["stroke-dasharray"] ||
+ params["stroke-miterlimit"] ||
+ params["stroke-linejoin"] ||
+ params["stroke-linecap"]) {
+ stroke.on = true;
+ }
+ (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
+ var strokeColor = R.getRGB(('stroke' in params) ? params.stroke : a.stroke);
+ stroke.on && params.stroke && (stroke.color = strokeColor.hex);
+ opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.opacity + 1 || 2) - 1);
+ var width = (toFloat(params["stroke-width"]) || 1) * .75;
+ opacity = mmin(mmax(opacity, 0), 1);
+ params["stroke-width"] == null && (width = a["stroke-width"]);
+ params["stroke-width"] && (stroke.weight = width);
+ width && width < 1 && (opacity *= width) && (stroke.weight = 1);
+ stroke.opacity = opacity;
+
+ params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"]) || newstroke && (newstroke.joinstyle = 'miter');
+ stroke.miterlimit = params["stroke-miterlimit"] || 8;
+ params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
+ if (params["stroke-dasharray"]) {
+ var dasharray = {
+ "-": "shortdash",
+ ".": "shortdot",
+ "-.": "shortdashdot",
+ "-..": "shortdashdotdot",
+ ". ": "dot",
+ "- ": "dash",
+ "--": "longdash",
+ "- .": "dashdot",
+ "--.": "longdashdot",
+ "--..": "longdashdotdot"
+ };
+ stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] :
+ ((params["stroke-dasharray"].join && params["stroke-dasharray"].join(' ')) || E);
+ }
+ newstroke && node.appendChild(stroke);
+ }
+ if (res.type == "text") {
+ res.paper.canvas.style.display = E;
+ var span = res.paper.span,
+ m = 100,
+ fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/),
+ lineHeight = a['line-height'] && (a['line-height']+E).match(/\d+(?:\.\d*)?(?=px)/);
+ s = span.style;
+ a.font && (s.font = a.font);
+ a["font-family"] && (s.fontFamily = a["font-family"]);
+ a["font-weight"] && (s.fontWeight = a["font-weight"]);
+ a["font-style"] && (s.fontStyle = a["font-style"]);
+ fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10;
+ s.fontSize = fontSize * m + "px";
+ lineHeight = toFloat(a["line-height"] || lineHeight && lineHeight[0]) || 12;
+ a["line-height"] && (s.lineHeight = lineHeight * m + 'px');
+ res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/"));
+ var brect = span.getBoundingClientRect();
+ res.W = a.w = (brect.right - brect.left) / m;
+ res.H = a.h = (brect.bottom - brect.top) / m;
+ // res.paper.canvas.style.display = "none";
+ res.X = a.x;
+ res.Y = a.y;
+ var leading = lineHeight - fontSize;
+ switch(a["vertical-align"]) {
+ case "top":
+ res.bby = res.H / 2; // + leading;
+ break;
+ case "bottom":
+ res.bby = -res.H / 2; // - leading;
+ break;
+ default:
+ res.bby = 0;
+ }
+
+ ("x" in params || "y" in params || res.bby !== undefined) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round((a.y + (res.bby || 0)) * zoom), round(a.x * zoom) + 1));
+ var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size", "line-height"];
+ for (var d = 0, dd = dirtyattrs.length; d < dd; d++)
+ if (dirtyattrs[d] in params) {
+ res._.dirty = 1;
+ break;
+ }
+
+ // text-anchor emulation
+ switch (a["text-anchor"]) {
+ case "start":
+ res.textpath.style["v-text-align"] = "left";
+ res.bbx = res.W / 2;
+ break;
+ case "end":
+ res.textpath.style["v-text-align"] = "right";
+ res.bbx = -res.W / 2;
+ break;
+ default:
+ res.textpath.style["v-text-align"] = "center";
+ res.bbx = 0;
+ break;
+ }
+ res.textpath.style["v-text-kern"] = true;
+ }
+ // res.paper.canvas.style.display = E;
+ },
+ addGradientFill = function(o, gradient, fill) {
+ o.attrs = o.attrs || {};
+ var attrs = o.attrs,
+ pow = Math.pow,
+ opacity,
+ oindex,
+ type = "linear",
+ fxfy = ".5 .5";
+ o.attrs.gradient = gradient;
+ gradient = Str(gradient).replace(R._radial_gradient, function(all, opts) {
+ type = "radial";
+ opts = opts && opts.split(',') || [];
+
+ // fx,fy of vml is cx,cy of svg
+ var cx = opts[0],
+ cy = opts[1],
+ r = opts[2],
+ fx = opts[3],
+ fy = opts[4],
+ units = opts[5];
+ if (fx && fy) {
+ fx = toFloat(fx);
+ fy = toFloat(fy);
+ pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
+ fxfy = fx + S + fy;
+ }
+ return E;
+ });
+ gradient = gradient.split(/\s*\-\s*/);
+ if (type == "linear") {
+ var angle = gradient.shift();
+ angle = -toFloat(angle);
+ if (isNaN(angle)) {
+ return null;
+ }
+ }
+ var dots = R._parseDots(gradient);
+ if (!dots) {
+ return null;
+ }
+ o = o.shape || o.node;
+ if (dots.length) {
+ o.removeChild(fill);
+ fill.on = true;
+ fill.method = "none";
+ fill.color = dots[0].color;
+ fill.color2 = dots[dots.length - 1].color;
+ //For VML use first and last available alpha
+ var clrs = [],
+ opacity1 = 1,
+ opacity2 = dots[0].opacity === undefined ? 1 : dots[0].opacity;
+ for (var i = 0, ii = dots.length; i < ii; i++) {
+ dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color);
+ if (dots[i].opacity !== undefined) {
+ opacity1 = dots[i].opacity;//update with latest avaible opacity
+ }
+ }
+ fill.colors = clrs.length ? clrs.join() : "0% " + fill.color;
+ //set opacity1 & opacity2
+ fill.opacity = opacity1;
+ fill['o:opacity2'] = opacity2;
+ if (type == "radial") {
+ fill.type = "gradientTitle";
+ fill.focus = "100%";
+ fill.focussize = "0 0";
+ fill.focusposition = fxfy;
+ fill.angle = 0;
+ } else {
+ // fill.rotate= true;
+ fill.type = "gradient";
+ fill.angle = (270 - angle) % 360;
+ }
+ o.appendChild(fill);
+ }
+ return 1;
+ },
+ Element = function(node, vml, group) {
+ var o = this,
+ parent = group || vml;
+
+ o.node = o[0] = node;
+ node.raphael = true;
+ node.raphaelid = o.id = R._oid++;
+
+ o.X = 0;
+ o.Y = 0;
+
+ o.attrs = o.attrs || {};
+ o.styles = o.styles || {};
+ o.followers = o.followers || [];
+
+ o.paper = vml;
+ o.ca = o.customAttributes = o.customAttributes ||
+ new vml._CustomAttributes();
+
+ o.matrix = R.matrix();
+ o._ = {
+ transform: [],
+ sx: 1,
+ sy: 1,
+ dx: 0,
+ dy: 0,
+ deg: 0,
+ dirty: 1,
+ dirtyT: 1
+ };
+
+ o.parent = parent;
+ !parent.bottom && (parent.bottom = o);
+
+ o.prev = parent.top;
+ parent.top && (parent.top.next = o);
+ parent.top = o;
+ o.next = null;
+ };
+ var elproto = R.el;
+
+ Element.prototype = elproto;
+ elproto.constructor = Element;
+
+ elproto.transform = function(tstr) {
+ if (tstr == null) {
+ return this._.transform;
+ }
+ var vbs = this.paper._viewBoxShift,
+ vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
+ oldt;
+
+ if (vbs) {
+ oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E);
+ }
+
+ R._extractTransform(this, vbt + tstr);
+
+ var matrix = this.matrix.clone(),
+ skew = this.skew,
+ o = this.node,
+ split,
+ isGrad = ~Str(this.attrs.fill).indexOf("-"),
+ isPatt = !Str(this.attrs.fill).indexOf("url(");
+ matrix.translate(-.5, -.5);
+ if (isPatt || isGrad || this.type == "image") {
+ skew.matrix = "1 0 0 1";
+ skew.offset = "0 0";
+ split = matrix.split();
+ if ((isGrad && split.noRotation) || !split.isSimple) {
+ o.style.filter = matrix.toFilter();
+ var bb = this.getBBox(),
+ bbt = this.getBBox(1),
+ xget = bb.x2 && bbt.x2 && 'x2' || 'x',
+ yget = bb.y2 && bbt.y2 && 'y2' || 'y',
+ dx = bb[xget] - bbt[xget],
+ dy = bb[yget] - bbt[yget];
+ o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
+ setCoords(this, 1, 1, dx, dy, 0);
+ } else {
+ o.style.filter = E;
+ setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
+ }
+ } else {
+ o.style.filter = E;
+ skew.matrix = Str(matrix);
+ skew.offset = matrix.offset();
+ }
+ oldt && (this._.transform = oldt);
+
+ return this;
+ };
+ elproto.rotate = function(deg, cx, cy) {
+ if (this.removed) {
+ return this;
+ }
+ if (deg == null) {
+ return;
+ }
+ deg = Str(deg).split(separator);
+ if (deg.length - 1) {
+ cx = toFloat(deg[1]);
+ cy = toFloat(deg[2]);
+ }
+ deg = toFloat(deg[0]);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ var bbox = this.getBBox(1);
+ cx = bbox.x + bbox.width / 2;
+ cy = bbox.y + bbox.height / 2;
+ }
+ this._.dirtyT = 1;
+ this.transform(this._.transform.concat([["r", deg, cx, cy]]));
+ return this;
+ };
+ elproto.translate = function(dx, dy) {
+ if (this.removed) {
+ return this;
+ }
+ dx = Str(dx).split(separator);
+ if (dx.length - 1) {
+ dy = toFloat(dx[1]);
+ }
+ dx = toFloat(dx[0]) || 0;
+ dy = +dy || 0;
+ if (this._.bbox) {
+ this._.bbox.x += dx;
+ this._.bbox.y += dy;
+ }
+ this.transform(this._.transform.concat([["t", dx, dy]]));
+ return this;
+ };
+ elproto.scale = function(sx, sy, cx, cy) {
+ if (this.removed) {
+ return this;
+ }
+ sx = Str(sx).split(separator);
+ if (sx.length - 1) {
+ sy = toFloat(sx[1]);
+ cx = toFloat(sx[2]);
+ cy = toFloat(sx[3]);
+ isNaN(cx) && (cx = null);
+ isNaN(cy) && (cy = null);
+ }
+ sx = toFloat(sx[0]);
+ (sy == null) && (sy = sx);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ var bbox = this.getBBox(1);
+ }
+ cx = cx == null ? bbox.x + bbox.width / 2 : cx;
+ cy = cy == null ? bbox.y + bbox.height / 2 : cy;
+
+ this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
+ this._.dirtyT = 1;
+ return this;
+ };
+ elproto.hide = function(soft) {
+ var o = this;
+ !o.removed && (o.node.style.display = "none");
+ return o;
+ };
+
+ elproto.show = function(soft) {
+ var o = this;
+ !o.removed && (o.node.style.display = E);
+ return o;
+ };
+ elproto._getBBox = function() {
+ if (this.removed) {
+ return {};
+ }
+ return {
+ x: this.X + (this.bbx || 0) - this.W / 2,
+ y: this.Y + (this.bby || 0) - this.H / 2,
+ width: this.W,
+ height: this.H
+ };
+ };
+ elproto.remove = function() {
+ if (this.removed || !this.parent.canvas) {
+ return;
+ }
+ var i,
+ thisNode = R._engine.getNode(this);
+ this.paper.__set__ && this.paper.__set__.exclude(this);
+ eve.unbind("raphael.*.*." + this.id);
+ while (i = this.followers.pop()) {
+ i.el.remove();
+ }
+ this.shape && this.shape.parentNode.removeChild(this.shape);
+ thisNode.parentNode.removeChild(thisNode);
+ R._tear(this, this.paper);
+ for (var i in this) {
+ this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+ }
+ this.removed = true;
+ };
+ elproto.css = function (name, value) {
+ // do not parse css in case element is removed.
+ if (this.removed) {
+ return this;
+ }
+
+ // process as getter when a single key is sent as parameter.
+ if (value == null && R.is(name, "string")) {
+ var names = name.split(separator),
+ out = {};
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in this.styles) {
+ out[name] = this.styles[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+ // process as getter when multiple keys are pre-sent as array.
+ if (value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = this.styles(name[i]);
+ }
+ return out;
+ }
+ // convert single key-value setter into object style standard.
+ if (value != null) {
+ var params = {};
+ params[name] = value;
+ } else if (name != null && R.is(name, "object")) {
+ params = name;
+ }
+ // iterate on keys and set style or raise events.
+ var otherkey, doattrs = {};
+ for (var key in params) {
+ otherkey = key.replace(/\B([A-Z]{1})/g, "-$1").toLowerCase();
+ // Replace "color" with fill
+ (otherkey === 'color' && this.type === 'text') && (otherkey = 'fill');
+ // If keys are supported via attr then use attr instead of css.
+ if (R._availableAttrs[has](otherkey)) {
+ doattrs[otherkey] = params[key];
+ doattrs.dirty = true;
+ continue;
+ }
+ eve("raphael.css." + otherkey + "." + this.id, this, params[key], otherkey);
+ (params[key] != undefined) && (this.node.style[otherkey] = params[key]);
+ this.styles[otherkey] = params[key];
+ }
+
+ for (i = 0, ii = this.followers.length; i < ii; i++) {
+ this.followers[i].el.css(params);
+ }
+
+ // apply css via attrs
+ if (doattrs[has]("dirty")) {
+ delete doattrs.dirty;
+ this.attr(doattrs);
+ }
+
+ return this;
+ };
+ elproto.attr = function(name, value) {
+ if (this.removed) {
+ return this;
+ }
+ if (name == null) {
+ var res = {};
+ for (var a in this.attrs)
+ if (this.attrs[has](a)) {
+ res[a] = this.attrs[a];
+ }
+ res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
+ res.transform = this._.transform;
+ res.visibility = this.node.style.display === "none" ? "hidden" : "visible";
+ return res;
+ }
+ if (value == null && R.is(name, "string")) {
+ if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
+ return this.attrs.gradient;
+ }
+ if (name == "visibility") {
+ return this.node.style.display === "none" ? "hidden" : "visible";
+ }
+ var names = name.split(separator),
+ out = {};
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in this.attrs) {
+ out[name] = this.attrs[name];
+ } else if (R.is(this.ca[name], "function")) {
+ out[name] = this.ca[name].def;
+ } else {
+ out[name] = R._availableAttrs[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+ if (this.attrs && value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = this.attr(name[i]);
+ }
+ return out;
+ }
+ var params;
+ if (value != null) {
+ params = {};
+ params[name] = value;
+ }
+ value == null && R.is(name, "object") && (params = name);
+ for (var key in params) {
+ eve("raphael.attr." + key + "." + this.id, this, params[key], key);
+ }
+ if (params) {
+ var todel = {};
+ for (key in this.ca)
+ if (this.ca[key] && params[has](key) && R.is(this.ca[key], "function") && !this.ca['_invoked' + key]) {
+ this.ca['_invoked' + key] = true; // prevent recursion
+ var par = this.ca[key].apply(this, [].concat(params[key]));
+ delete this.ca['_invoked' + key];
+
+ for (var subkey in par) {
+ if (par[has](subkey)) {
+ params[subkey] = par[subkey];
+ }
+ }
+ this.attrs[key] = params[key];
+ if (par === false) {
+ todel[key] = params[key];
+ delete params[key];
+ }
+ }
+ // this.paper.canvas.style.display = "none";
+ if ('text' in params && this.type == "text") {
+ this.textpath.string = params.text.replace(/ /ig, '\n');
+ }
+ setFillAndStroke(this, params);
+ var follower;
+ for (i = 0, ii = this.followers.length; i < ii; i++) {
+ follower = this.followers[i];
+ (follower.cb && !follower.cb.call(follower.el, params, this)) ||
+ follower.el.attr(params);
+ }
+ for (var subkey in todel) {
+ params[subkey] = todel[subkey];
+ }
+ // this.paper.canvas.style.display = E;
+ }
+ return this;
+ };
+
+ elproto.blur = function(size) {
+ var s = this.node.runtimeStyle,
+ f = s.filter;
+ f = f.replace(blurregexp, E);
+ if (+size !== 0) {
+ this.attrs.blur = size;
+ s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")";
+ s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5));
+ } else {
+ s.filter = f;
+ s.margin = 0;
+ delete this.attrs.blur;
+ }
+ return this;
+ };
+
+ elproto.on = function(eventType, handler) {
+ if (this.removed) {
+ return this;
+ }
+
+ this.node['on'+ eventType] = function() {
+ var evt = R._g.win.event;
+ evt.target = evt.srcElement;
+ handler(evt);
+ };
+ return this;
+ };
+
+ R._engine.getNode = function (el) {
+ var node = el.node || el[0].node;
+ return node.clipRect || node;
+ };
+ R._engine.getLastNode = function (el) {
+ var node = el.node || el[el.length - 1].node;
+ return node.clipRect || node;
+ };
+
+ R._engine.group = function(vml, id, group) {
+ var el = R._g.doc.createElement("div"),
+ p = new Element(el, vml, group);
+
+ el.style.cssText = cssDot;
+
+ id && (el.className = ['red', id, p.id].join('-'));
+ (group || vml).canvas.appendChild(el);
+
+ p.type = 'group';
+ p.canvas = p.node;
+ p.transform = R._engine.group.transform;
+ p.top = null;
+ p.bottom = null;
+
+ return p;
+ };
+
+ R._engine.group.transform = function(tstr) {
+ if (tstr == null) {
+ return this._.transform;
+ }
+
+ var o = this,
+ s = o.node.style,
+ c = o.clip,
+ vbs = o.paper._viewBoxShift,
+ vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
+ oldt,
+ matrix,
+ offset,
+ tx,
+ ty;
+
+ if (vbs) {
+ oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, o._.transform || E);
+ }
+ R._extractTransform(o, vbt + tstr);
+ matrix = o.matrix;
+ offset = matrix.offset();
+ tx = toFloat(offset[0]) || 0;
+ ty = toFloat(offset[1]) || 0;
+
+ s.left = tx + "px";
+ s.top = ty + "px";
+ s.zoom = (o._.tzoom = matrix.get(0)) + E;
+
+ /* @todo try perform relative group transform, thus avoiding
+ * transform on clipping */
+ c && (s.clip = R.format("rect({1}px {2}px {3}px {0}px)", [
+ c[0] - tx, c[1] - ty, c[2] - tx, c[3] - ty
+ ]));
+
+ return o;
+ };
+
+ R._engine.path = function(pathString, vml, group) {
+ var el = createNode("shape");
+ el.style.cssText = cssDot;
+ el.coordsize = zoom + S + zoom;
+ el.coordorigin = vml.coordorigin;
+ var p = new Element(el, vml, group),
+ attr = {
+ fill: "none",
+ stroke: "#000"
+ };
+
+ pathString && (attr.path = pathString);
+ p.type = "path";
+ p.path = [];
+ p.Path = E;
+ setFillAndStroke(p, attr);
+ (group || vml).canvas.appendChild(el);
+
+ var skew = createNode("skew");
+ skew.on = true;
+ el.appendChild(skew);
+ p.skew = skew;
+ return p;
+ };
+
+ R._engine.rect = function(vml, x, y, w, h, r, group) {
+ var path = R._rectPath(x, y, w, h, r),
+ res = vml.path(path, group),
+ a = res.attrs;
+ res.X = a.x = x;
+ res.Y = a.y = y;
+ res.W = a.width = w;
+ res.H = a.height = h;
+ a.r = r;
+ a.path = path;
+ res.type = "rect";
+ return res;
+ };
+ R._engine.ellipse = function(vml, x, y, rx, ry, group) {
+ var res = vml.path(undefined, group);
+ res.X = x - rx;
+ res.Y = y - ry;
+ res.W = rx * 2;
+ res.H = ry * 2;
+ res.type = "ellipse";
+ setFillAndStroke(res, {
+ cx: x,
+ cy: y,
+ rx: rx,
+ ry: ry
+ });
+ return res;
+ };
+ R._engine.circle = function(vml, x, y, r, group) {
+ var res = vml.path(undefined, group);
+ res.X = x - r;
+ res.Y = y - r;
+ res.W = res.H = r * 2;
+ res.type = "circle";
+ setFillAndStroke(res, {
+ cx: x,
+ cy: y,
+ r: r
+ });
+ return res;
+ };
+ R._engine.image = function(vml, src, x, y, w, h, group) {
+ var path = R._rectPath(x, y, w, h),
+ res = vml.path(path, group).attr({
+ stroke: "none"
+ }),
+ a = res.attrs,
+ node = res.node,
+ fill = node.getElementsByTagName(fillString)[0];
+ a.src = src;
+ res.X = a.x = x;
+ res.Y = a.y = y;
+ res.W = a.width = w;
+ res.H = a.height = h;
+ a.path = path;
+ res.type = "image";
+ fill.parentNode == node && node.removeChild(fill);
+ fill.rotate = true;
+ fill.src = src;
+ fill.type = "tile";
+ res._.fillpos = [x, y];
+ res._.fillsize = [w, h];
+ node.appendChild(fill);
+ setCoords(res, 1, 1, 0, 0, 0);
+ return res;
+ };
+ R._engine.text = function(vml, x, y, text, group) {
+ var el = createNode("shape"),
+ path = createNode("path"),
+ o = createNode("textpath");
+ x = x || 0;
+ y = y || 0;
+ text = text;
+ path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1);
+ path.textpathok = true;
+ o.string = Str(text).replace(/ /ig, '\n');
+ o.on = true;
+ el.style.cssText = cssDot;
+ el.coordsize = zoom + S + zoom;
+ el.coordorigin = "0 0";
+ var p = new Element(el, vml, group),
+ attr = {
+ fill: "#000",
+ stroke: "none",
+ text: text
+ };
+
+ p.shape = el;
+ p.path = path;
+ p.textpath = o;
+ p.type = "text";
+ p.attrs.text = Str(text || E);
+ p.attrs.x = x;
+ p.attrs.y = y;
+ p.attrs.w = 1;
+ p.attrs.h = 1;
+ setFillAndStroke(p, attr);
+ el.appendChild(o);
+ el.appendChild(path);
+ (group || vml).canvas.appendChild(el);
+
+ var skew = createNode("skew");
+ skew.on = true;
+ el.appendChild(skew);
+ p.skew = skew;
+ return p;
+ };
+
+ R._engine.setSize = function(width, height) {
+ var cs = this.canvas.style;
+ this.width = width;
+ this.height = height;
+ width == +width && (width += "px");
+ height == +height && (height += "px");
+ cs.width = width;
+ cs.height = height;
+ cs.clip = "rect(0 " + width + " " + height + " 0)";
+ if (this._viewBox) {
+ R._engine.setViewBox.apply(this, this._viewBox);
+ }
+ return this;
+ };
+ R._engine.setViewBox = function(x, y, w, h, fit) {
+ eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]);
+ var width = this.width,
+ height = this.height,
+ size = 1 / mmax(w / width, h / height),
+ H, W;
+ if (fit) {
+ H = height / h;
+ W = width / w;
+ if (w * H < width) {
+ x -= (width - w * H) / 2 / H;
+ }
+ if (h * W < height) {
+ y -= (height - h * W) / 2 / W;
+ }
+ }
+ this._viewBox = [x, y, w, h, !!fit];
+ this._viewBoxShift = {
+ dx: -x,
+ dy: -y,
+ scale: size
+ };
+ this.forEach(function(el) {
+ el.transform("...");
+ });
+ return this;
+ };
+ var createNode;
+ R._engine.initWin = function(win) {
+ var doc = win.document;
+ doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
+ try {
+ !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
+ createNode = R._createNode = function(tagName, attrs) {
+ var el = doc.createElement(''),
+ prop;
+ for (prop in attrs) {
+ el[prop] = Str(attrs[prop]);
+ }
+ return el;
+ };
+ } catch (e) {
+ createNode = R._createNode = function(tagName, attrs) {
+ var el = doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'),
+ prop;
+ for (prop in attrs) {
+ el[prop] = Str(attrs[prop]);
+ }
+ return el;
+ };
+ }
+ };
+ R._engine.initWin(R._g.win);
+ R._engine.create = function() {
+ var con = R._getContainer.apply(0, arguments),
+ container = con.container,
+ height = con.height,
+ s,
+ width = con.width,
+ x = con.x,
+ y = con.y;
+ if (!container) {
+ throw new Error("VML container not found.");
+ }
+ var res = new R._Paper,
+ c = res.canvas = R._g.doc.createElement("div"),
+ cs = c.style;
+ x = x || 0;
+ y = y || 0;
+ width = width || 512;
+ height = height || 342;
+ res.width = width;
+ res.height = height;
+ width == +width && (width += "px");
+ height == +height && (height += "px");
+ res.coordsize = zoom * 1e3 + S + zoom * 1e3;
+ res.coordorigin = "0 0";
+ res.span = R._g.doc.createElement("span");
+ res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;";
+ c.appendChild(res.span);
+ cs.cssText = R.format("top:0;left:0;width:{0};height:{1};display:inline-block;cursor:default;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden", width, height);
+ if (container == 1) {
+ R._g.doc.body.appendChild(c);
+ cs.left = x + "px";
+ cs.top = y + "px";
+ cs.position = "absolute";
+ } else {
+ if (container.firstChild) {
+ container.insertBefore(c, container.firstChild);
+ } else {
+ container.appendChild(c);
+ }
+ }
+ res.renderfix = function() {
+ };
+ return res;
+ };
+ R.prototype.clear = function() {
+ eve("raphael.clear", this);
+ this.canvas.innerHTML = E;
+ this.span = R._g.doc.createElement("span");
+ this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
+ this.canvas.appendChild(this.span);
+ this.bottom = this.top = null;
+ };
+ R.prototype.remove = function() {
+ eve("raphael.remove", this);
+ this.canvas.parentNode.removeChild(this.canvas);
+ for (var i in this) {
+ this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+ }
+ return true;
+ };
+
+ var setproto = R.st;
+ for (var method in elproto)
+ if (elproto[has](method) && !setproto[has](method)) {
+ setproto[method] = (function(methodname) {
+ return function() {
+ var arg = arguments;
+ return this.forEach(function(el) {
+ el[methodname].apply(el, arg);
+ });
+ };
+ })(method);
+ }
+})();
+
+/*jslint forin: true, regexp: true, todo: true, white: false, browser: true,
+ sloppy: true, white: true, eqeq: false, newcap: true, nomen: true */
+
+/*global FusionCharts */
+
+/**
+ * Raphael Canvas Extension
+ */
+
+(function(){
+ if (!R.canvas) {
+ return;
+ }
+ var win = R._g.win,
+ doc = R._g.doc,
+ g = R._g,
+
+ STRING = 'string',
+ PX = 'px',
+
+ separator = /[, ]+/,
+
+ Str = win.String,
+ toInt = win.parseInt,
+ toFloat = win.parseFloat,
+
+ math = win.Math,
+ mmax = math.max,
+ mmin = math.min,
+ pi = math.PI,
+ mathFloor = math.floor,
+
+ eve = R.eve,
+ paperproto = R.fn,
+ elproto = R.el,
+ setproto = R.st,
+
+ clone = R.clone,
+ deg2rad = pi / 180,
+ rad2deg = 180 / pi,
+
+ DEFAULT_FILL = "#fff",
+ DEFAULT_STROKE = "#000",
+ has = "hasOwnProperty",
+ S = " ",
+ /* @todo: detect touch */
+ supportsTouch = (('ontouchstart' in win) || (navigator.msMaxTouchPoints > 0)),
+ events = ("click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel").split(S),
+ noHandle = false,
+
+ $,
+ FauxNode,
+ Element,
+ draggable = [],
+ drag = [],
+ dragMove = function(e) {
+ var x = e.clientX,
+ y = e.clientY,
+ scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
+ dragi,
+ j = drag.length;
+ while (j--) {
+ dragi = drag[j];
+ if (supportsTouch) {
+ var i = e.touches.length,
+ touch;
+ while (i--) {
+ touch = e.touches[i];
+ if (touch.identifier == dragi.el._drag.id) {
+ x = touch.clientX;
+ y = touch.clientY;
+ (e.originalEvent ? e.originalEvent : e).preventDefault();
+ break;
+ }
+ }
+ } else {
+ e.preventDefault();
+ }
+
+ //var node = dragi.el.node;
+ //o,
+ //next = node.nextSibling,
+ //parent = node.parentNode,
+ //display = node.style.display;
+
+ /* @todo: implement raphael.drag.over */
+
+ //g.win.opera && parent.removeChild(node);
+ //node.style.display = "none";
+ //o = dragi.el.paper.getElementByPoint(x, y);
+ //node.style.display = display;
+ //g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
+ //o && eve("raphael.drag.over." + dragi.el.id, dragi.el, o);
+ x += scrollX;
+ y += scrollY;
+ eve("raphael.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
+ }
+ },
+ dragUp = function(e) {
+ R.unmousemove(dragMove).unmouseup(dragUp);
+ var i = drag.length,
+ dragi;
+ while (i--) {
+ dragi = drag[i];
+ dragi.el._drag = {};
+ eve("raphael.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
+ }
+ drag = [];
+ };
+
+
+ if (!R.canvas) {
+ return;
+ }
+
+ $ = R._createNode = function(el, attr) {
+ if (attr) {
+ if (typeof el === STRING) {
+ el = $(el);
+ }
+ for (var key in attr)
+ if (attr.hasOwnProperty(key)) {
+ el.setAttribute(key, Str(attr[key]));
+ }
+ } else {
+ el = doc.createElement(el);
+ }
+ return el;
+ };
+
+ R._getConnectedNodes = function (node) {
+ return {
+ above: [],
+ below: []
+ };
+ };
+
+ R._getTargetNode = function (coords) {
+ var x = coords[0],
+ y = coords[1];
+
+
+ };
+
+ R._containerEventHandler = function (event) {
+ event = event || win.event;
+
+ if (noHandle) {
+ return;
+ }
+
+ /* @todo: do not use offsetX and offsetY */
+ var x = event.offsetX,//mathFloor(event.pageX || (event.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft) || 0),
+ y = event.offsetY,//mathFloor(event.pageY || (event.clientY + doc.body.scrollTop + doc.documentElement.scrollTop) || 0),
+ type = event.type,
+ node = R._getTargetNode([x, y]);
+
+ //console.log(type + ":: x: " + x + " y: " + y);
+
+ /*
+ if (typeof node.listeners[type] === 'function') {
+ node.listeners[type].call(node, e);
+ }*/
+
+ };
+
+
+
+
+
+ FauxNode = function (parent) {
+ this.type = "basic";
+
+ this.owner = parent;
+
+ // Element reference needed to get attrs so that there is no need to
+ // maintain a redundant copy.
+ this._rElement = null;
+
+ // False if this element does not need mouse interactivity.
+ this.mouseInteractions = false;
+ this.matrix = null;
+
+ // An outline path that will be the outline of the shape or in case of
+ // text the rect that bounds the text.
+ this.outlinePath = null;
+
+ this.conf = {};
+ };
+
+ FauxNode.prototype = {
+
+ constructor: FauxNode,
+
+ /**
+ * This method does the complete rendering of the element, including
+ * (re)setting the bbox and image map.
+ *
+ * @returns {_L10.FauxNode.prototype}
+ */
+ render: function () {
+
+ var o = this;
+
+ o.draw();
+ o.setBBox();
+
+ return o;
+ },
+
+ /**
+ * Applies the transforms and clipping to the context and draws the
+ * element.
+ *
+ * @returns {undefined}
+ */
+ draw: function () {
+ var o = this,
+ ctx = o.context,
+ el = o._rElement,
+ m = el.matrix,
+ isClipped = o.isClipped,
+ attrs = o.validateAttrs(),
+ cr,
+ end;
+
+
+ // After the validation the attributes need to be set to the element
+ // as validateAttrs works on a copy of the attrs object.
+ el.attrs = attrs;
+
+ ctx.save();
+
+ ctx.fillStyle = attrs.fill;
+ ctx.strokeStyle = attrs.stroke;
+ ctx.lineWidth = attrs['stroke-width'];
+
+ // Applying the clip before the context is transformed as is the case
+ // in case of SVG.
+ if (cr = attrs['clip-rect']) {
+ cr = cr.split(" ");
+ ctx.rect(cr[0], cr[1], cr[2], cr[3]);
+ ctx.clip();
+ isClipped = o.isClipped = true;
+ }
+
+ o.applyTransform(m);
+
+ o.paint();
+
+ ctx.restore();
+ },
+
+ /**
+ * Parse the attributes provided to paint the element shape using the
+ * canvas context.
+ *
+ * Overridden by individual derived FauxNodes
+ */
+ paint: function () {
+ },
+
+ /**
+ * The redraw of the FauxNodes is to be handled by the CanvasObjectModel
+ * instance as it involves redrawing all the elements corresponsing to
+ * that canvas in the proper order.
+ */
+ redraw: function () {
+ this.COMInstance.redraw(this);
+ },
+
+ /**
+ * Clears the rectangle corresponding to the bounding box of the node.
+ */
+ clear: function () {
+ var o = this,
+ ctx = o.context,
+ bbox = o._bbox;
+
+ /* @todo: while clearing the stroke-width also needs to be accounted for. */
+ if (bbox) {
+ ctx.clearRect(bbox.x, bbox.y, bbox.width, bbox.height);
+ }
+ },
+
+ /**
+ * Creates the area node in the image map so that mouse interactivity
+ * can be emulated using it.
+ */
+ addMouseInteractivity: function () {
+ var o = this,
+ attrs = o._rElement.attrs,
+ bbox = o._bbox,
+ map = o.owner.wrapper._map,
+ shape = (o.type === 'circle') ? 'circle' : 'rect',
+ coords = (shape === 'circle') ? [attrs.cx, attrs.cy, attrs.r].join(",")
+ : [bbox.x, bbox.y, bbox.x2, bbox.y2].join(","),
+ area,
+ end;
+
+ area = $('area', {shape: shape, coords: coords});
+ if (map.firstChild) {
+ map.insertBefore(area, map.firstChild);
+ }
+ else {
+ map.appendChild(area);
+ }
+
+ /* @todo: should be put this check here */
+ o._mouseArea = area;
+
+ // Needed for paths.
+ o.eventListeners = {};
+ },
+
+
+ /**
+ * Update the coords of the area node (image map) corresponding to the FauxNode
+ * after it has been modified by changing attributes.
+ */
+ updateMapAreaCoords: function () {
+ var o = this,
+ oArea = o._mouseArea,
+ bbox = o._bbox;
+
+ if (oArea) {
+ //o.context.strokeRect(bbox.x, bbox.y, bbox.width, bbox.height);
+ if (o instanceof CircleFauxNode) {
+ var r = bbox.width / 2;
+ oArea.setAttribute('coords',
+ [bbox.x + r, bbox.y + r, r].join(","));
+ }
+ else {
+ oArea.setAttribute('coords',
+ [bbox.x, bbox.y, bbox.x2, bbox.y2].join(","));
+ }
+ }
+ },
+
+ /**
+ * Applies the transform given the transformation matrix to the context.
+ *
+ * @param {type} matrix
+ * @param {type} bbox
+ * @param {type} dontsetbbox
+ *
+ * @returns {_L10.FauxNode.prototype.transformBBox.tbox}
+ */
+ applyTransform: function (m) {
+ var o = this,
+ ctx = o.context,
+ split;
+
+ if (m) {
+ split = m.split();
+ ctx.translate(split.dx, split.dy);
+ !split.noRotation && ctx.rotate(deg2rad * split.rotate);
+ ctx.scale(split.scalex, split.scaley);
+ }
+ },
+
+ /**
+ *
+ */
+ setBBox: function () {
+ var o = this,
+ el = o._rElement,
+ m = el.matrix,
+ parent = o.owner,
+ pm = parent.getTransformMatrix && parent.getTransformMatrix();
+
+ if (pm) {
+ pm = pm.clone();
+ pm.add(m);
+ m = pm;
+ }
+
+ if (o.outlinePath) {
+ o._bbox = R.pathBBox(R.transformPath(o.outlinePath, m.toTransformString()).toString());
+ }
+ else {
+ o.setShapeBBox(m);
+ }
+
+ o._mouseArea && o.updateMapAreaCoords();
+ },
+
+ getBBox: function () {
+ return this._bbox;
+ },
+
+ drawPath: function (path) {
+ var o = this,
+ ctx = o.context,
+ len = (path && path.length) || 0,
+ pp = PathParser,
+ i = 0,
+ command,
+ x,
+ y,
+ end;
+
+ // The PathParser object has been borrowed from canvg. All 3rd party attributions implied.
+ pp.reset();
+ pp.setTokens(path);
+
+ //var bb = new BoundingBox();
+ if (ctx != null) {
+ ctx.beginPath();
+ }
+
+ while (!pp.isEnd()) {
+ pp.nextCommand();
+ switch (pp.command) {
+ case 'M':
+ case 'm':
+ var p = pp.getAsCurrentPoint();
+ pp.addMarker(p);
+ //bb.addPoint(p.x, p.y);
+ if (ctx != null) {
+ ctx.moveTo(p.x, p.y);
+ }
+ pp.start = pp.current;
+ while (!pp.isCommandOrEnd()) {
+ var p = pp.getAsCurrentPoint();
+ pp.addMarker(p, pp.start);
+ //bb.addPoint(p.x, p.y);
+ if (ctx != null) {
+ ctx.lineTo(p.x, p.y);
+ }
+ }
+ break;
+ case 'L':
+ case 'l':
+ while (!pp.isCommandOrEnd()) {
+ var c = pp.current;
+ var p = pp.getAsCurrentPoint();
+ pp.addMarker(p, c);
+ //bb.addPoint(p.x, p.y);
+ if (ctx != null) {
+ ctx.lineTo(p.x, p.y);
+ }
+ }
+ break;
+ case 'H':
+ case 'h':
+ while (!pp.isCommandOrEnd()) {
+ var newP = new Point((pp.isRelativeCommand() ? pp.current.x : 0) + pp.getScalar(), pp.current.y);
+ pp.addMarker(newP, pp.current);
+ pp.current = newP;
+ //bb.addPoint(pp.current.x, pp.current.y);
+ if (ctx != null) {
+ ctx.lineTo(pp.current.x, pp.current.y);
+ }
+ }
+ break;
+ case 'V':
+ case 'v':
+ while (!pp.isCommandOrEnd()) {
+ var newP = new Point(pp.current.x, (pp.isRelativeCommand() ? pp.current.y : 0) + pp.getScalar());
+ pp.addMarker(newP, pp.current);
+ pp.current = newP;
+ //bb.addPoint(pp.current.x, pp.current.y);
+ if (ctx != null) {
+ ctx.lineTo(pp.current.x, pp.current.y);
+ }
+ }
+ break;
+ case 'C':
+ case 'c':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var p1 = pp.getPoint();
+ var cntrl = pp.getAsControlPoint();
+ var cp = pp.getAsCurrentPoint();
+ pp.addMarker(cp, cntrl, p1);
+ //bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ if (ctx != null) {
+ ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ }
+ }
+ break;
+ case 'S':
+ case 's':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var p1 = pp.getReflectedControlPoint();
+ var cntrl = pp.getAsControlPoint();
+ var cp = pp.getAsCurrentPoint();
+ pp.addMarker(cp, cntrl, p1);
+ //bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ if (ctx != null) {
+ ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ }
+ }
+ break;
+ case 'Q':
+ case 'q':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var cntrl = pp.getAsControlPoint();
+ var cp = pp.getAsCurrentPoint();
+ pp.addMarker(cp, cntrl, cntrl);
+ //bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
+ }
+ break;
+ case 'T':
+ case 't':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var cntrl = pp.getReflectedControlPoint();
+ pp.control = cntrl;
+ var cp = pp.getAsCurrentPoint();
+ pp.addMarker(cp, cntrl, cntrl);
+ //bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
+ }
+ break;
+ case 'A':
+ case 'a':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var rx = pp.getScalar();
+ var ry = pp.getScalar();
+ var xAxisRotation = pp.getScalar() * (Math.PI / 180.0);
+ var largeArcFlag = pp.getScalar();
+ var sweepFlag = pp.getScalar();
+ var cp = pp.getAsCurrentPoint();
+
+ // Conversion from endpoint to center parameterization
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+ // x1', y1'
+ var currp = new Point(
+ Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0,
+ -Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0
+ );
+ // adjust radii
+ var l = Math.pow(currp.x,2)/Math.pow(rx,2)+Math.pow(currp.y,2)/Math.pow(ry,2);
+ if (l > 1) {
+ rx *= Math.sqrt(l);
+ ry *= Math.sqrt(l);
+ }
+ // cx', cy'
+ var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt(
+ ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) /
+ (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2))
+ );
+ if (isNaN(s)) s = 0;
+ var cpp = new Point(s * rx * currp.y / ry, s * -ry * currp.x / rx);
+ // cx, cy
+ var centp = new Point(
+ (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y,
+ (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y
+ );
+ // vector magnitude
+ var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); }
+ // ratio between two vectors
+ var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) }
+ // angle between two vectors
+ var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); }
+ // initial angle
+ var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]);
+ // angle delta
+ var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry];
+ var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry];
+ var ad = a(u, v);
+ if (r(u,v) <= -1) ad = Math.PI;
+ if (r(u,v) >= 1) ad = 0;
+
+ // for markers
+ var dir = 1 - sweepFlag ? 1.0 : -1.0;
+ var ah = a1 + dir * (ad / 2.0);
+ var halfWay = new Point(
+ centp.x + rx * Math.cos(ah),
+ centp.y + ry * Math.sin(ah)
+ );
+ pp.addMarkerAngle(halfWay, ah - dir * Math.PI / 2);
+ pp.addMarkerAngle(cp, ah - dir * Math.PI);
+
+ //bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better
+ if (ctx != null) {
+ var r = rx > ry ? rx : ry;
+ var sx = rx > ry ? 1 : rx / ry;
+ var sy = rx > ry ? ry / rx : 1;
+
+ ctx.translate(centp.x, centp.y);
+ ctx.rotate(xAxisRotation);
+ ctx.scale(sx, sy);
+ ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag);
+ ctx.scale(1/sx, 1/sy);
+ ctx.rotate(-xAxisRotation);
+ ctx.translate(-centp.x, -centp.y);
+ }
+ }
+ break;
+ case 'Z':
+ case 'z':
+ if (ctx != null) ctx.closePath();
+ pp.current = pp.start;
+ }
+ }
+
+ o.outlinePath = path;
+
+ return o;
+ },
+
+ /**
+ * Methods to add and remove event listeners emulating the DOM of
+ * standard browsers (and also the non-standard one).
+ */
+ addEventListener: function () {
+ var o = this,
+ args = arguments,
+ eventName = args && args[0],
+ handler = args && args[1],
+ area,
+ checkPathHandler,
+ end;
+
+ if (!o._mouseArea) {
+ o.addMouseInteractivity();
+ }
+
+ area = o._mouseArea;
+
+ if (typeof eventName === 'string' && typeof handler === 'function') {
+ /*
+ * If the shape has an associated path then we need to check if
+ * the mouse is within the co-ordinates of the path.
+ */
+ if (o._path) {
+
+ /*
+ * If the event being listened to is mouseover, mouseout or
+ * mousemove then the mouse position has to be constantly
+ * monitored and the event handler called explicitly when
+ * appropriate.
+ */
+ if (eventName === 'mouseover' || eventName === 'mouseout' || eventName === 'mousemove') {
+
+ if (!o._mousemoveAdded) {
+ var startListening = (function (node) {
+
+ var isInside = false,
+ isOutside = true,
+ transition = false;
+
+ return function (event) {
+ /* @todo: replace layerX and layerY with
+ * standard ways of determining mouse position.
+ */
+ var x = event.layerX,
+ y = event.layerY;
+
+ transition = false;
+ /*
+ * Check if the current position of the mouse
+ * pointer lies within the path or not.
+ */
+ if (R.isPointInsidePath(node._transformPath, x, y)) {
+ /*
+ * @todo: fix isPointInsidePath to return the
+ * proper result when the mouse pointer is on
+ * the same horizontal/vertical lines as one
+ * of the vertices of the path.
+ */
+ isInside = true;
+ if (isOutside) {
+ isOutside = false;
+ transition = true;
+ }
+ }
+ else {
+ isOutside = true;
+ if (isInside) {
+ isInside = false;
+ transition = true;
+ }
+ }
+
+ // Based on the state of the flags, fire the
+ // appropriate event handlers.
+ if (isOutside && transition && node.eventListeners['mouseout']) {
+ node.eventListeners['mouseout'].apply(this, arguments);
+ }
+ if (isInside) {
+ if (transition && node.eventListeners['mouseover']) {
+ node.eventListeners['mouseover'].apply(this, arguments);
+ }
+ if (node.eventListeners['mousemove']) {
+ node.eventListeners['mousemove'].apply(this, arguments);
+ }
+ }
+ };
+ })(o);
+
+ area.addEventListener('mousemove', startListening, false);
+ o._mousemoveAdded = true;
+ }
+
+ o.eventListeners[eventName] = handler;
+ }
+ else {
+ var checkPathHandler = (function (node, handler) {
+ return function (event) {
+ if (R.isPointInsidePath(node._path, event.layerX, event.layerY)) {
+ handler.apply(this, arguments);
+ }
+ };
+ }(o, handler));
+
+ area.addEventListener(eventName, checkPathHandler, false);
+ }
+ }
+ else {
+ area.addEventListener(eventName, handler, false);
+ }
+ }
+ },
+
+ removeEventListener: function () {
+ var o = this,
+ args = arguments,
+ eventName = args && args[0],
+ handler = args && args[1],
+ area,
+ end;
+
+ if (!o._mouseArea) {
+ return;
+ }
+ area = o._mouseArea;
+
+ if (typeof eventName === 'string' && typeof handler === 'function') {
+ area.removeEventListener(eventName, handler);
+ }
+ },
+
+ attachEvent: function () {
+ },
+
+ detachEvent: function () {
+ },
+
+ validateAttrs: function (attrs) {
+
+ var o = this,
+ elAttrs = clone(o._rElement.attrs),
+ attr,
+ val;
+
+ if (attrs === null) {
+ if (o._isValid) {
+ return elAttrs;
+ }
+ else {
+ o._isValid = true;
+ }
+ }
+
+ attrs = attrs || elAttrs;
+
+ for (attr in attrs) {
+ val = attrs[attr];
+
+ switch (attr) {
+
+ default:
+ continue;
+ }
+ }
+
+ return attrs;
+ },
+
+ attrs: function () {
+ }
+ };
+
+
+
+
+ var NodeListItem = function (node) {
+ this.node = node;
+ this.next = null;
+ this.prev = null;
+ },
+
+ NodeList = function () {
+ this.top = null;
+ this.bottom = null;
+ };
+
+ NodeList.prototype = {
+
+ constructor: NodeList,
+
+ add: function (node) {
+
+ node = new NodeListItem(node);
+
+ if (!this.bottom) {
+ this.bottom = node;
+ }
+ if (this.top) {
+ this.top.next = node;
+ }
+ node.next = null;
+ node.prev = this.top;
+
+ this.top = node;
+ },
+
+ addList: function (list) {
+ if (!this.bottom) {
+ this.bottom = list.bottom;
+ }
+
+ if (this.top) {
+ this.top.next = list.bottom;
+ list.bottom.prev = this.top;
+ }
+
+ this.top = list.top;
+ },
+
+ toFront: function (node) {
+ if (this.top === node) {
+ return false;
+ }
+
+ if (this.bottom === node) {
+ this.bottom = node.next;
+ }
+
+ //var map = node.node.canvas._map,
+ // area = node.node._mouseArea;
+
+ node.prev && (node.prev.next = node.next);
+ node.next && (node.next.prev = node.prev);
+
+ this.top.next = node;
+ node.prev = this.top;
+ node.next = null;
+
+ this.top = node;
+
+ /*if (map.firstChild) {
+ map.insertBefore(area, map.firstChild);
+ }
+ else {
+ map.appendChild(area);
+ }
+
+ node.redraw();*/
+ },
+
+ toBack: function (node) {
+ if (this.bottom === node) {
+ return false;
+ }
+
+ if (this.top === node) {
+ this.top = node.prev;
+ }
+
+ //var map = node.canvas._map,
+ // area = node._mouseArea;
+
+ node.prev && (node.prev.next = node.next);
+ node.next && (node.next.prev = node.prev);
+
+ this.bottom.prev = node;
+ node.prev = null;
+ node.next = this.bottom;
+
+ this.bottom = node;
+
+ /*map.appendChild(area);
+
+ node.redraw();*/
+ },
+
+ insertBefore: function () {
+ },
+
+ insertAfter: function () {
+ },
+
+ each: function (fn, args) {
+ var item = this.bottom;
+
+ while (item) {
+ fn.apply(item.node, args);
+ item = item.next;
+ }
+ },
+
+ iterate: function (fn, args) {
+ var item = this.bottom,
+ retVal = true;
+
+ while (item) {
+ retVal = fn.apply(item.node, args);
+
+ if (retVal === false) {
+ break;
+ }
+
+ item = item.next;
+ }
+ },
+
+ dispose: function () {
+
+ this.each(function () {
+ this.node.dispose && this.node.dispose();
+ });
+
+ this.top = null;
+ this.bottom = null;
+ },
+ };
+
+ /**
+ *
+ ncowner, a NodeCollection that corresponds to the collection of which
+ the layer neing created is a part
+
+ above, a NodeCollection iterator, that indicated the collection the layer has to be rendered. If
+ not provided then this is the first layer of ncowner.
+ */
+ var CanvasLayer = function (ncowner, canvas) {
+ this.items = new NodeList();
+
+ this.owner = ncowner;
+ //this.above = above;
+ this.element = null;
+
+ if (canvas) {
+ this.element = canvas;
+ }
+ else {
+ this.init();
+ }
+ };
+
+ CanvasLayer.prototype = {
+ constructor: CanvasLayer,
+
+ appendChild: function () {
+ var o = this,
+ ownerWrapper = o.owner.wrapper,
+ ele = this.element;
+
+ if (ownerWrapper._image) {
+ ownerWrapper.insertBefore(ele, ownerWrapper._image);
+ }
+ else {
+ ownerWrapper.appendChild(ele);
+ }
+ },
+
+ insertBefore: function () {
+
+ },
+
+ insertAfter: function () {
+
+ },
+
+ init: function () {
+ this.element = $("canvas");
+ // CHECKPOINT: width and height in %?
+ $(this.element, {
+ width: this.owner.wrapper.offsetWidth,
+ height: this.owner.wrapper.offsetHeight
+ });
+
+ this.element.style.cssText = "position:absolute;left:0;top:0;";
+
+ this.appendChild();
+ },
+
+ getCanvas: function () {
+ return this.element;
+ },
+
+ getContext: function () {
+ return this.element.getContext('2d');
+ },
+
+ addToLayer: function (node) {
+ this.items.add(node);
+ },
+
+ mergeWithLayerOnTop: function (layerObj) {
+ this.items.addList(layerObj.items);
+ layerObj.dispose(true);
+ },
+
+ mergeWithLayerOnBottom: function (layerObj) {
+ layerObj.items.addList(this.items);
+ this.items = layerObj.items;
+ layerObj.dispose(true);
+ },
+
+ dispose: function (softDispose) {
+
+ if (!softDispose) {
+ this.items.each(function () {
+ this.dispose();
+ });
+ }
+
+ this.items = null;
+ this.owner = null;
+
+ this.element.parentNode.removeChild(this.element);
+ this.element = null;
+ }
+ };
+
+ var NodeCollection = function (parent, wrapper, canvas) {
+
+ this.nodeItems = new NodeList();
+ this.collectionItems = new NodeList();
+ this.layerItems = new NodeList();
+
+ this.owner = this.parent = parent;
+ this.layerOnTop = null;
+
+ this.currentLayer = null;
+ this.baseLayer = null;
+
+ if (wrapper) {
+ this.wrapper = wrapper;
+ this.currentLayer = this.baseLayer = new CanvasLayer(this, canvas);
+ }
+ else {
+ this.init();
+ }
+ };
+
+ NodeCollection.prototype = {
+ constructor: NodeCollection,
+
+ init: function () {
+
+ var o = this,
+ parent = o.parent,
+ imageMap = parent.wrapper._image,
+ wrapper = $("div");
+
+ // Hacky but need a refernce to the image map to addEventListeners.
+ wrapper.style.cssText = "width:100%;height:100%;position:absolute;left:0;top:0;";
+
+ wrapper._map = parent.wrapper._map;
+
+ if (imageMap) {
+ parent.wrapper.insertBefore(wrapper, imageMap);
+ }
+ else {
+ parent.wrapper.appendChild(wrapper);
+ }
+
+ o.wrapper = wrapper;
+ o.currentLayer = o.baseLayer = new CanvasLayer(o);
+ },
+
+ getCurrentContext: function () {
+ return this.currentLayer.getContext();
+ },
+
+ setLayerOnTop: function (layerObj) {
+ this.layerOnTop = layerObj;
+ },
+
+ getCurrentCanvas: function () {
+ return this.currentLayer.getCanvas();
+ },
+
+ addNode: function (node) {
+ this.nodeItems.add(node);
+
+ if (node.type === "group") {
+ this.addCollection(node);
+ }
+ else {
+ this.currentLayer.addToLayer(node);
+ }
+ },
+
+ addCollection: function (collectionNode) {
+
+ collectionNode = collectionNode || new NodeCollection(this);
+
+ this.collectionItems.add(collectionNode);
+ this.currentLayer = new CanvasLayer(this);
+ this.layerItems.add(this.currentLayer);
+ collectionNode.setLayerOnTop(this.currentLayer);
+ },
+
+ dispose: function () {
+ this.nodeItems.dispose();
+ this.collectionItems.dispose();
+ this.layerItems.dispose();
+ this.owner = this.parent = null;
+
+ this.ownerLayer = null;
+ this.currentLayer = null;
+ this.baseLayer = null;
+ }
+ };
+
+ /**
+ * The CanvasObjectModel will be a layer of abstraction above the individual
+ * FauxNodes created to emulate the DOM in case of canvas rendering.
+ * The engine will be the point of contact for Raphael._engine that will be
+ * the direct consumer of the FauxNodes.
+ */
+ var CanvasObjectModel = function (cnvs, wrpr, width, height) {
+
+ var com = this,
+ root = new NodeCollection(null, wrpr, cnvs);
+
+ //root.set
+
+ com.width = width;
+ com.height = height;
+
+ com.createNode = function (type, parent) {
+
+ parent = parent || root;
+
+ var node,
+ nodeItems = parent.nodeItems,
+ layer = parent.currentLayer,
+ canvasEle = layer.getCanvas();
+
+ switch (type) {
+ case 'rect':
+ node = new RectFauxNode(parent);
+ break;
+
+ case 'circle':
+ node = new CircleFauxNode(parent);
+ break;
+
+ case 'path':
+ node = new PathFauxNode(parent);
+ break;
+
+ case 'text':
+ node = new TextFauxNode(parent);
+ break;
+
+ case 'group':
+ node = new GroupFauxNode(parent);
+ parent.addCollection(node);
+ break;
+
+ default:
+ node = new FauxNode(canvasEle);
+ }
+
+ node.COMInstance = this;
+ nodeItems.add(node);
+ layer.addToLayer(node);
+
+ return node;
+ };
+
+ /**
+ * This method is needed to redraw a node. Redraw is to be handled at the
+ * COM level as redrawing one node needs all the (connected) nodes to be
+ * redrawn in the right order.
+ *
+ * @param {type} node The node that needs to be redrawn.
+ *
+ * @returns {undefined}
+ */
+ com.redraw = function (node) {
+
+ // Check if node is a group or a shape.
+ var nodeList,
+ childNode,
+ layer;
+
+ if (node.type === "group") {
+ nodeList = node.nodeItems;
+ node.render();
+ }
+ else {
+
+ layer = node.layer;
+ nodeList = layer.items;
+ childNode = nodeList.bottom;
+
+ // Clear the canvas.
+ layer.element.width = layer.element.width;
+
+ while (childNode) {
+ fNode = childNode.node;
+ (fNode.type !== "group") && fNode.render();
+ childNode = childNode.next;
+ }
+
+ }
+
+ };
+
+ com.insertBefore = function (node) {
+
+ };
+
+ com.insertAfter = function (node) {
+
+ };
+
+ com.removeNode = function (node) {
+
+ };
+
+ com.refreshNode = function (node) {
+
+ };
+
+ com.refreshAll = function () {
+
+ };
+ };
+
+
+
+ Point = function(x, y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ Point.prototype.angleTo = function(p) {
+ return Math.atan2(p.y - this.y, p.x - this.x);
+ }
+
+ Point.prototype.applyTransform = function(v) {
+ var xp = this.x * v[0] + this.y * v[2] + v[4];
+ var yp = this.x * v[1] + this.y * v[3] + v[5];
+ this.x = xp;
+ this.y = yp;
+ }
+
+ PathParser = new (function() {
+
+ this.tokens = null;
+
+ this.setTokens = function (d) {
+ if (typeof d === 'string') {
+ this.tokens = d.split(' ');
+ }
+ else {
+ this.tokens = d;
+ }
+ };
+
+ this.reset = function() {
+ this.i = -1;
+ this.command = '';
+ this.previousCommand = '';
+ this.start = new Point(0, 0);
+ this.control = new Point(0, 0);
+ this.current = new Point(0, 0);
+ this.points = [];
+ this.angles = [];
+ };
+
+ this.isEnd = function() {
+ return this.i >= this.tokens.length - 1;
+ }
+
+ this.isCommandOrEnd = function() {
+ if (this.isEnd()) {
+ return true;
+ }
+
+ return this.tokens[this.i + 1].toString().match(/^[A-Za-z]$/) != null;
+ }
+
+ this.isRelativeCommand = function() {
+ switch(this.command)
+ {
+ case 'm':
+ case 'l':
+ case 'h':
+ case 'v':
+ case 'c':
+ case 's':
+ case 'q':
+ case 't':
+ case 'a':
+ case 'z':
+ return true;
+ break;
+ }
+ return false;
+ }
+
+ this.getToken = function() {
+ this.i++;
+ return this.tokens[this.i];
+ }
+
+ this.getScalar = function() {
+ return parseFloat(this.getToken());
+ }
+
+ this.nextCommand = function() {
+ this.previousCommand = this.command;
+ this.command = this.getToken();
+ }
+
+ this.getPoint = function() {
+ var p = new Point(this.getScalar(), this.getScalar());
+ return this.makeAbsolute(p);
+ }
+
+ this.getAsControlPoint = function() {
+ var p = this.getPoint();
+ this.control = p;
+ return p;
+ }
+
+ this.getAsCurrentPoint = function() {
+ var p = this.getPoint();
+ this.current = p;
+ return p;
+ }
+
+ this.getReflectedControlPoint = function() {
+ if (this.previousCommand.toLowerCase() != 'c' &&
+ this.previousCommand.toLowerCase() != 's' &&
+ this.previousCommand.toLowerCase() != 'q' &&
+ this.previousCommand.toLowerCase() != 't' ){
+ return this.current;
+ }
+
+ // reflect point
+ var p = new Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y);
+ return p;
+ }
+
+ this.makeAbsolute = function(p) {
+ if (this.isRelativeCommand()) {
+ p.x += this.current.x;
+ p.y += this.current.y;
+ }
+ return p;
+ }
+
+ this.addMarker = function(p, from, priorTo) {
+ // if the last angle isn't filled in because we didn't have this point yet ...
+ if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) {
+ this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo);
+ }
+ this.addMarkerAngle(p, from == null ? null : from.angleTo(p));
+ }
+
+ this.addMarkerAngle = function(p, a) {
+ this.points.push(p);
+ this.angles.push(a);
+ }
+
+ this.getMarkerPoints = function() {
+ return this.points;
+ }
+
+ this.getMarkerAngles = function() {
+ for (var i=0; i maxR) {
+ attrs.r = maxR;
+ }
+
+ if (val < 0) {
+ attrs.r = 0;
+ }
+ break;
+
+ case "width":
+ case "height":
+ if (val < 0) {
+ attrs[attr] = 0;
+ };
+ break;
+
+ default:
+ continue;
+ }
+ }
+
+ return attrs;
+ },
+
+ setShapeBBox: function (m) {
+ var o = this,
+ el = o._rElement,
+ attrs = el.attrs,
+ sX = m.get(0),
+ sY = m.get(3),
+ tX = m.get(4),
+ tY = m.get(5),
+ strokeW = attrs['stroke-width'];
+
+ o._bbox = {
+ x: ((attrs.x * sX) + tX) - strokeW,
+ y: ((attrs.y * sY) + tY) - strokeW,
+ width: (attrs.width * sX) + (2 * strokeW),
+ height: (attrs.height * sY) + (2 * strokeW),
+ };
+
+ o._bbox.x2 = o._bbox.x + o._bbox.width;
+ o._bbox.y2 = o._bbox.y + o._bbox.height;
+
+ o.X = o._bbox.x;
+ o.Y = o._bbox.y;
+ o.W = o._bbox.width;
+ o.H = o._bbox.height;
+ }
+ });
+
+ var CircleFauxNode = function (parentObj) {
+ this.type = "circle";
+ this._isValid = false;
+
+ this.parent = this.owner = parentObj;
+ this.context = parentObj.getCurrentContext();
+ this.layer = parentObj.currentLayer;
+ },
+
+ PathFauxNode = function (parentObj) {
+ this.type = "path";
+ this._isValid = false;
+
+ this.parent = this.owner = parentObj;
+ this.context = parentObj.getCurrentContext();
+ this.layer = parentObj.currentLayer;
+ },
+
+ TextFauxNode = function (parentObj) {
+ this.type = "text";
+ this._isValid = false;
+
+ this.parent = this.owner = parentObj;
+ this.context = parentObj.getCurrentContext();
+ this.layer = parentObj.currentLayer;
+ },
+
+ GroupFauxNode = function (parent, width, height) {
+
+ this.type = "group";
+
+ this.nodeItems = new NodeList();
+ this.collectionItems = new NodeList();
+ this.layerItems = new NodeList();
+
+ this.owner = this.parent = parent;
+ this.layerOnTop = parent.currentLayer;
+
+ this.currentLayer = null;
+ this.baseLayer = null;
+
+ this.init();
+ };
+
+ CircleFauxNode.prototype = R.extend(new FauxNode(), {
+
+ constructor: CircleFauxNode,
+
+ paint: function () {
+ var o = this,
+ ctx = o.context,
+ attrs = o.validateAttrs(),
+ x = attrs.cx,
+ y = attrs.cy,
+ r = attrs.r,
+ /* @todo: provide support for rx, ry */
+ rx = r || attrs.rx,
+ ry = r || attrs.ry;
+
+ if (attrs.r) {
+
+ o.drawPath(["M", x + r, y, "A", rx, ry, 0, 1, 0, x - r, y, "A", rx, ry, 0, 1, 0, x + r, y, "Z"]);
+
+ if (attrs['stroke-width']) {
+ var strokeAlpha = attrs['stroke-opacity'] === undefined ? attrs['opacity'] : attrs['stroke-opacity'];
+ if (strokeAlpha !== undefined) {
+ ctx.globalAlpha = strokeAlpha;
+ }
+ ctx.stroke();
+ }
+ var fillAlpha = attrs['fill-opacity'] === undefined ? attrs['opacity'] : attrs['fill-opacity'];
+ if (fillAlpha !== undefined) {
+ ctx.globalAlpha = fillAlpha;
+ }
+ ctx.fill();
+ }
+
+ return;
+ },
+
+ setShapeBBox: function (m) {
+ var o = this,
+ el = o._rElement,
+ attrs = el.attrs,
+ sX = m.get(0),
+ sY = m.get(3),
+ tX = m.get(4),
+ tY = m.get(5),
+ strokeW = attrs['stroke-width'];
+
+ o._bbox = {
+ x: tX + ((attrs.cx - attrs.r) * sX) - strokeW,
+ y: tY + ((attrs.cy - attrs.r) * sY) - strokeW,
+ width: 2 * (strokeW + (attrs.r * sX)),
+ height: 2 * ((attrs.r * sY) + strokeW)
+ };
+
+ o._bbox.x2 = o._bbox.x + o._bbox.width;
+ o._bbox.y2 = o._bbox.y + o._bbox.height;
+
+ o.X = o._bbox.x;
+ o.Y = o._bbox.y;
+ o.W = o._bbox.width;
+ o.H = o._bbox.height;
+ }
+ });
+
+ PathFauxNode.prototype = R.extend(new FauxNode(), {
+
+ constructor: PathFauxNode,
+
+ paint: function () {
+ var o = this,
+ el = o._rElement,
+ attrs = el.attrs,
+ path = el.attr('path'),
+ m = el.matrix,
+ ctx = o.context;
+
+ // 1. Get the path from the path attribute
+ // 2. Accept paths in different array formats.
+ // 3. Optimize as this can potentially be a huge pain-point.
+ // 4. Draw path mapping M,L,H,V etc to canvas APIs
+ o.drawPath(path);
+ o._transformPath = R.transformPath(path, m.toTransformString());
+
+ var strokeAlpha = attrs['stroke-opacity'] === undefined ? attrs['opacity'] : attrs['stroke-opacity'];
+ if (strokeAlpha !== undefined) {
+ ctx.globalAlpha = strokeAlpha;
+ }
+ ctx.stroke();
+ var fillAlpha = attrs['fill-opacity'] === undefined ? attrs['opacity'] : attrs['fill-opacity'];
+ if (fillAlpha !== undefined) {
+ ctx.globalAlpha = fillAlpha;
+ }
+ ctx.fill();
+
+ return;
+ }
+ });
+
+ TextFauxNode.prototype = R.extend(new FauxNode(), {
+
+ constructor: TextFauxNode,
+
+ paint: function () {
+ var o = this,
+ el = o._rElement,
+ attrs = el.attr(),
+ text = attrs['text'],
+ stroke = attrs['stroke'],
+ valign = attrs['vertical-align'],
+ halign = attrs['text-anchor'],
+ x = attrs['x'],
+ y = attrs['y'],
+ m = el.matrix,
+ ctx = o.context,
+ path;
+
+ // apply the font styles, if any
+
+ // find the dimensions of the text using the given styles.
+ // All the dimensions should be present in the attrs user provided OR default.
+ var fontSize = attrs['font-size'] || 10,
+ lineHeight = attrs['line-height'] || toInt(fontSize, 10) * 1.2,
+ fontArr = ["normal", fontSize, attrs['font']];
+
+ // draw the text.
+ ctx.fillStyle = stroke;
+ ctx.font = fontArr.join(" ");
+
+ if (text) {
+ var texts = Str(text).split(/\n| /ig),
+ totalHeight = texts.length * lineHeight,
+ totalWidth = -Infinity,
+ startX = Infinity,
+ startY,
+ width,
+ textX,
+ textY;
+
+ if (valign === "top") {
+ startY = y + lineHeight;
+ }
+ else if (valign === "middle") {
+ startY = y - (totalHeight / 2) + (lineHeight / 2);
+ }
+ else { // valign is bottom.
+ startY = y - totalHeight + lineHeight;
+ }
+
+ for (var i = 0, ii = texts.length; i < ii; i += 1) {
+
+ text = texts[i];
+ textY = startY + (lineHeight * i);
+ width = ctx.measureText(text).width;
+
+ if (halign === "start") {
+ textX = x;
+ }
+ else if (halign === "middle") {
+ textX = x - (width / 2);
+ }
+ else {
+ textX = x - width;
+ }
+
+ totalWidth = mmax(totalWidth, width);
+ startX = mmin(startX, textX);
+
+ ctx.fillText(text, textX, textY);
+ }
+
+ el._textdirty = false;
+ }
+
+ o.outlinePath = [
+ "M",
+ startX,
+ startY - (lineHeight / 1.4),
+ "H",
+ startX + totalWidth,
+ "V",
+ startY - lineHeight + totalHeight,
+ "H",
+ startX,
+ "V",
+ startY - (lineHeight / 1.4)
+ ];
+
+ return;
+ }
+ });
+
+ GroupFauxNode.prototype = R.extend(R.extend(new FauxNode, NodeCollection.prototype), {
+
+ constructor: GroupFauxNode,
+
+ draw: function () {
+
+ // Clear the group canvas first.
+ this.layerItems.each(function () {
+ this.element.width = this.element.width;
+ });
+
+ FauxNode.prototype.draw.apply(this, arguments);
+ },
+
+ /**
+ * This method does the complete rendering of the element, including
+ * (re)setting the bbox and image map.
+ *
+ * @returns {_L10.FauxNode.prototype}
+ */
+ render: function () {
+
+ var o = this;
+
+ o.draw();
+ o.setBBox();
+
+ return o;
+ },
+
+ paint: function () {
+ var o = this,
+ list = o.nodeList,
+ el = o._rElement,
+ canvas = o.canvas,
+ attrs = el.attrs,
+ childNode = list.bottom;
+
+ /* @todo: Clean this up */
+ if (attrs.opacity !== undefined) {
+ this.layerItems.each(function () {
+ this.getContext().globalAlpha = attrs.opacity;
+ });
+ }
+
+ while (childNode) {
+ childNode.render();
+ childNode = childNode.next;
+ }
+ },
+
+ setBBox: function () {
+
+ },
+
+ addMouseInteractivity: function () {
+ },
+
+ applyTransform: function (m) {
+ var o = this,
+ parent = o.parent,
+ parentMatrix = parent.getTransformMatrix && parent.getTransformMatrix();
+
+ // Parent is a group element with a transformation applied to it.
+ if (parentMatrix) {
+ o.matrixApplied = parentMatrix.clone();
+ o.matrixApplied.add(m.a, m.b, m.c, m.d, m.e, m.f);
+ }
+ else {
+ o.matrixApplied = m;
+ }
+
+ this.layerItems.each(function () {
+ FauxNode.prototype.applyTransform.apply(this, [o.matrixApplied]);
+ })
+ },
+
+ getTransformMatrix: function () {
+ return this.matrixApplied;
+ }
+ });
+
+ Element = function (node, paper, group) {
+ var o = this,
+ parent = group || paper;
+
+ o.node = o[0] = node;
+ node.raphael = true;
+ node.raphaelid = o.id = R._oid++;
+ node._rElement = o;
+
+ o.X = 0;
+ o.Y = 0;
+
+ o.attrs = o.attrs || {};
+ o.styles = o.styles || {};
+ o.followers = o.followers || [];
+
+ o.paper = paper;
+ o.com = parent.com;
+
+ o.ca = o.customAttributes = o.customAttributes ||
+ new paper._CustomAttributes();
+
+ o.matrix = R.matrix();
+ o._ = {
+ transform: [],
+ sx: 1,
+ sy: 1,
+ dx: 0,
+ dy: 0,
+ deg: 0
+ };
+
+ o.parent = parent;
+ !parent.bottom && (parent.bottom = o);
+
+ o.prev = parent.top || null;
+ parent.top && (parent.top.next = o);
+ parent.top = o;
+ o.next = null;
+ };
+
+ Element.prototype = elproto;
+ elproto.constructor = Element;
+
+ var
+ repaint = function (el, finalAttrs, positionChanged, dimensionChanged) {
+
+ var node = getNode(el),
+ preC = R._getConnectedNodes(node),
+ attrs = el.attrs,
+ elAbove = preC.above,
+ elBelow = preC.below,
+ len,
+ attr,
+ i;
+
+ for (attr in finalAttrs) {
+ attrs[attr] = finalAttrs[attr];
+ }
+
+ node.redraw();
+ },
+
+ setFillAndStroke = function (el, params) {
+
+ var attrs = el.attrs,
+ node = el.node,
+ finalAttrs = {},
+ att,
+ val,
+ needsRepaint = false,
+ positionChanged = false,
+ dimensionChanged = false,
+ i;
+
+ for (att in params) {
+ if (params[has](att)) {
+ if (!R._availableAttrs[has](att)) {
+ continue;
+ }
+ val = params[att];
+
+ switch (att) {
+
+ case 'fill-opacity':
+ case 'opacity':
+ case 'stroke-opcaity':
+ case 'stroke':
+ case 'fill':
+ finalAttrs[att] = val;
+ needsRepaint = true;
+ break;
+
+ case 'stroke-width':
+ case "cx":
+ case "cy":
+ case "x":
+ case "y":
+ finalAttrs[att] = val;
+ positionChanged = true;
+ break;
+
+ case "width":
+ case "height":
+ finalAttrs[att] = val;
+ dimensionChanged = true;
+ break;
+
+ case "clip-rect":
+ finalAttrs[att] = val;
+ needsRepaint = true;
+ break;
+
+ case "font-size":
+ case "font":
+ case "vertical-align":
+ case "text-anchor":
+ finalAttrs[att] = val;
+ needsRepaint = true;
+
+ default:
+ continue;
+ }
+ }
+ }
+
+ tuneText(el, params, finalAttrs);
+
+ finalAttrs = node.validateAttrs(finalAttrs);
+
+ if (needsRepaint || positionChanged || dimensionChanged) {
+ repaint(el, finalAttrs, positionChanged, dimensionChanged);
+ }
+ },
+
+ leading = 1.2,
+
+ tuneText = function(el, params, finalAttrs) {
+ if (el.type != "text" || !(params[has]("text") || params[has]("font") ||
+ params[has]("font-size") || params[has]("x") || params[has]("y") ||
+ params[has]("line-height") || params[has]("vertical-align"))) {
+ return;
+ }
+
+ var a = el.attr(),
+ fontSize = params['font-size'] || a['font-size'] || 10,
+ lineHeight = toFloat(params['line-height'] || a['line-height']) || toInt(fontSize, 10) * leading,
+ valign = params["vertical-align"] || a["vertical-align"] || "middle";
+
+ if (isNaN(lineHeight)) {
+ lineHeight = fontSize * leading;
+ }
+
+ finalAttrs['font-size'] = toInt(fontSize, 10) + "px";
+ finalAttrs['font'] = params['font'] || a['font'] || 'Verdana';
+ finalAttrs['vertical-align'] = valign;
+ finalAttrs['x'] = params['x'] || a['x'] || 0;
+ finalAttrs['y'] = params['y'] || a['y'] || 0;
+ finalAttrs['line-height'] = toInt(lineHeight, 10);
+ finalAttrs['text-anchor'] = params['text-anchor'] || a['text-anchor'] || 'middle';
+ };
+
+ R._engine.initWin = function (win) {
+ win = win;
+ doc = win.document;
+ };
+
+ R._engine.setSize = function (w, h) {
+ var paper = this,
+ cs = paper.canvas.style;
+
+ cs.width = (paper.width = (+w || paper.width)) + PX;
+ cs.height = (paper.height = (+h || paper.height)) + PX;
+ /* @todo call setViewBox from setSize() */
+ return paper;
+ };
+ /* @todo implement setViewBox() */
+ R._engine.create = function () {
+ var con = R._getContainer.apply(0, arguments) || {},
+ container = con.container,
+ x = con.x,
+ y = con.y,
+ width = con.width,
+ height = con.height,
+ //handler = R._containerEventHandler,
+ wrapper,
+ cssText,
+ image,
+ mmap,
+ i,
+ paper,
+ canvas;
+
+ if (!container) {
+ throw new Error("Canvas container not found.");
+ }
+
+ paper = new R._Paper();
+ paper.canvas = wrapper = $("div");
+
+ x = (x || 0);
+ y = (y || 0);
+ paper.width = width = (width || 512);
+ paper.height = height = (height || 342);
+ paper.left = paper.top = 0;
+
+ if (container == 1) {
+ wrapper.style.cssText = cssText +
+ R.format(";width:100%;height:100%;position:absolute;left:{0}px;top:{1}px;", [x, y]);
+ doc.body.appendChild(wrapper);
+ }
+ else {
+ wrapper.style.cssText = cssText + ";width:100%;height:100%;position:absolute";
+ if (container.firstChild) {
+ container.insertBefore(wrapper, container.firstChild);
+ }
+ else {
+ container.appendChild(wrapper);
+ }
+ }
+
+ cssText = "overflow:hidden;-webkit-tap-highlight-color:rgba(0,0,0,0);" +
+ "-webkit-user-select:none;-moz-user-select:-moz-none;" +
+ "-khtml-user-select:none;-ms-user-select:none;user-select:none;" +
+ "-o-user-select:none;cursor:default;" +
+ R.format("width:{0}px;height:{1}px;", [width, height]);
+
+ // Create the canvas element and set it to occupy full space. Retain a
+ // reference to its context.
+ canvas = $("canvas");
+ canvas.style.cssText = "position:absolute;left:0;top:0";
+ canvas.setAttribute('width', paper.width);
+ canvas.setAttribute('height', paper.height);
+
+ paper.com = new CanvasObjectModel(canvas, wrapper, paper.width, paper.height);
+
+ wrapper.appendChild(canvas);
+
+ image = $("img");
+
+ // Easter egg idea! :)
+ image.src = "image1.png";
+
+ image.style.cssText = "opacity: 0;z-index: 100;background: transparent;position: absolute;left: 0;top: 0;width: "+width+"px;height: "+height+"px";
+ wrapper.appendChild(image);
+
+ mmap = $("map");
+
+ mmap.setAttribute("name", "mousemap");
+ mmap.setAttribute("id", "mousemap"); // Needed for FF.
+
+ wrapper.appendChild(mmap);
+
+ image.setAttribute("usemap","#mousemap");
+ wrapper._image = image;
+ wrapper._map = mmap;
+
+ return paper;
+ };
+
+ var getNode = R._engine.getNode = function (el) {
+ return el.node || el[0].node;
+ };
+
+ R._engine.getLastNode = function (el) {
+ return el.node || el[el.length - 1].node;
+ };
+
+ R._engine.rect = function(paper, x, y, w, h, r, group) {
+
+ var node = paper.com.createNode('rect', group && group.node),
+ el = new Element(node, paper, group),
+ attrs = el.attrs;
+
+ attrs.x = x;
+ attrs.y = y;
+ attrs.width = w;
+ attrs.height = h;
+ attrs.fill = "#fff";
+ attrs.stroke = "#000";
+ attrs['stroke-width'] = 1;
+ attrs.r = r || 0;
+ attrs.rx = r || 0;
+ attrs.ry = r || 0;
+
+ el.type = "rect";
+
+ node.render();
+ return el;
+ };
+
+ R._engine.circle = function(paper, x, y, r, group) {
+ var node = paper.com.createNode('circle', group && group.node),
+ el = new Element(node, paper, group),
+ attrs = el.attrs;
+
+ attrs.cx = x;
+ attrs.cy = y;
+ attrs.r = r;
+ attrs.fill = 'none';
+ attrs.stroke = '#000';
+ attrs['stroke-width'] = 1;
+
+ el.type = "circle";
+
+ node.render();
+ return el;
+ };
+
+ R._engine.ellipse = function(paper, x, y, rx, ry, group) {
+ var node = new FauxNode(),
+ el = new Element(node, paper, group);
+
+ el.type = "ellipse";
+ return el;
+ };
+
+ R._engine.image = function(paper, src, x, y, w, h, group) {
+ var node = new FauxNode(),
+ el = new Element(node, paper, group);
+
+ el.type = "image";
+ return el;
+ };
+
+ R._engine.text = function(paper, x, y, text, group) {
+ var node = paper.com.createNode('text', group && group.node),
+ el = new Element(node, paper, group),
+ attrs = el.attrs;
+
+ attrs.x = x;
+ attrs.y = y;
+ attrs.text = text;
+ attrs.fill = 'none';
+ attrs.stroke = '#000';
+ attrs.font = 'Verdana';
+ attrs['font-size'] = '12px';
+ attrs['vertical-align'] = 'middle';
+ attrs['text-anchor'] = 'middle'
+
+ el.type = "text";
+ node.render();
+ return el;
+ };
+
+ R._engine.path = function(pathString, paper, group) {
+ var node = paper.com.createNode('path', group && group.node),
+ el = new Element(node, paper, group),
+ attrs = el.attrs;
+
+ attrs.path = pathString;
+ attrs.fill = "#fff";
+ attrs.stroke = "#000";
+ attrs['stroke-width'] = 1;
+
+ el.type = "path";
+
+ node.render();
+
+ return el;
+ };
+
+ R._engine.group = function (paper, id, group) {
+
+ var node = paper.com.createNode('group', group && group.node),
+ el = new Element(node, paper, group),
+ wrapper = node.wrapper;
+
+ id && wrapper.setAttribute('class', ['red', id].join('-'));
+
+ el.canvas = wrapper;
+
+ //(group && group.canvas.appendChild(wrapper)) || paper.canvas.appendChild(wrapper);
+
+ el.type = "group";
+ return el;
+ };
+
+ elproto._getBBox = function() {
+ if (this.removed) {
+ return {};
+ }
+
+ return {
+ x: this.X + (this.bbx || 0) - this.W / 2,
+ y: this.Y + (this.bby || 0) - this.H / 2,
+ width: this.W,
+ height: this.H
+ };
+ };
+
+ /***** ELEMENT REORDERING / RESTRUCTING *****/
+
+ elproto.toFront = function() {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = o.node,
+ parent = o.parent,
+ parentNode = thisNode.owner,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (R._tofront(o, parent)) {
+ if (elproto.type === "group") {
+ parent.canvas.appendChild(thisNode);
+ }
+ else {
+ parentNode.nodeList.tofront(thisNode);
+ }
+ }
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk && follower.el[follower.stalk](o);
+ }
+
+ return o;
+ };
+
+ elproto.toBack = function() {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = o.node,
+ parent = o.parent,
+ parentNode = thisNode.owner,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (R._toback(o, parent)) {
+ if (elproto.type === "group") {
+ parent.canvas.appendChild(thisNode);
+ }
+ else {
+ parentNode.nodeList.toback(thisNode);
+ }
+ }
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk && follower.el[follower.stalk](o);
+ }
+
+
+ return o;
+ };
+
+ elproto.insertAfter = function(element) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = o.node,
+ thatNode = element.node,
+ parentNode = thatNode.owner,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (thatNode.next) {
+ parentNode.nodeList.insertBefore(thisNode, thatNode.next);
+ }
+ else {
+ parentNode.appendChild(thisNode);
+ }
+
+ R._insertafter(o, element, o.parent, element.parent);
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+
+ return o;
+ };
+
+ elproto.insertBefore = function(element) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = o.node,
+ thatNode = element.node,
+ parentNode = thatNode.owner,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (thatNode) {
+ parentNode.nodeList.insertBefore(thisNode, thatNode);
+ }
+ else {
+ parentNode.appendChild(thisNode);
+ }
+
+ R._insertafter(o, element, o.parent, element.parent);
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+
+ return o;
+ };
+
+ elproto.appendChild = function(element) {
+ return this;
+ };
+
+ elproto.removeChild = function(element) {
+ return this;
+ };
+
+ /***** ELEMENT REORDERING / RESTRUCTING *****/
+
+
+
+ elproto.attr = function(name, value) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+
+ attrs = o.attrs,
+ ca = o.ca,
+ names,
+ params,
+ par,
+
+ res,
+ key,
+ out,
+
+ subkey,
+ delkeys,
+
+ follower,
+ ii,
+ i;
+
+ // fetch a copy of all attributes
+ if (name == null) {
+ res = {};
+ for (key in attrs) if (attrs.hasOwnProperty(key)) {
+ res[key] = attrs[key];
+ }
+ res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
+ res.transform = o._.transform;
+ /* @todo res.visibility = o.node.style.display === "none" ? "hidden" : "visible"; */
+ return res;
+ }
+
+ // fetch a single value
+ if (value == null && R.is(name, "string")) {
+ if (name == "fill" && attrs.fill == "none" && attrs.gradient) {
+ return attrs.gradient;
+ }
+ if (name == "transform") {
+ return o._.transform;
+ }
+ /* @todo if (name == "visibility") {
+ return this.node.style.display === "none" ? "hidden" : "visible";
+ }*/
+
+ names = name.split(separator),
+ out = {};
+
+ for (i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in attrs) {
+ out[name] = attrs[name];
+ }
+ else if (R.is(ca[name], "function")) {
+ out[name] = ca[name].def;
+ } else {
+ out[name] = R._availableAttrs[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+
+ // fetch specific attributes
+ if (value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = o.attr(name[i]);
+ }
+ return out;
+ }
+
+ // prepare setter params
+ if (value != null) {
+ params = {};
+ params[name] = value;
+ }
+ else if (name != null && R.is(name, "object")) {
+ params = name;
+ }
+
+ for (key in params) {
+ eve("raphael.attr." + key + "." + o.id, o, params[key], key);
+ }
+
+ delkeys = {};
+ for (key in ca) {
+
+ if (ca[key] && params.hasOwnProperty(key) &&
+ R.is(ca[key], "function") && !ca['_invoked' + key]) {
+
+ ca['_invoked'+key] = true; // prevent recursion
+ par = ca[key].apply(o, [].concat(params[key]));
+ delete ca['_invoked'+key];
+
+ for (subkey in par) {
+ if (par.hasOwnProperty(subkey)) {
+ params[subkey] = par[subkey];
+ }
+ }
+ attrs[key] = params[key];
+ if (par === false) {
+ delkeys[key] = params[key];
+ delete params[key];
+ }
+ }
+ }
+
+ setFillAndStroke(this, params);
+
+ for (i = 0, ii = o.followers.length; i < ii; i++) {
+ follower = o.followers[i];
+ (follower.cb && !follower.cb.call(follower.el, params, o)) ||
+ follower.el.attr(params);
+ }
+
+ for (subkey in delkeys) {
+ params[subkey] = delkeys[subkey];
+ }
+ return this;
+ };
+
+ elproto.css = function (name, value) {
+ return this;
+ };
+
+
+
+
+ /**************** Drag *********************/
+ elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
+
+ function start(e) {
+ (e.originalEvent || e).preventDefault();
+ var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
+ this._drag.x = e.clientX + scrollX;
+ this._drag.y = e.clientY + scrollY;
+ this._drag.id = e.identifier;
+ !drag.length && R.mousemove(dragMove).mouseup(dragUp);
+ drag.push({
+ el: this,
+ move_scope: move_scope,
+ start_scope: start_scope,
+ end_scope: end_scope
+ });
+ onstart && eve.on("raphael.drag.start." + this.id, onstart);
+ onmove && eve.on("raphael.drag.move." + this.id, onmove);
+ onend && eve.on("raphael.drag.end." + this.id, onend);
+ eve("raphael.drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
+ }
+ this._drag = {};
+ draggable.push({
+ el: this,
+ start: start
+ });
+ this.mousedown(start);
+ return this;
+ }
+
+ elproto.undrag = function() {
+ var i = draggable.length;
+ while (i--)
+ if (draggable[i].el == this) {
+ this.unmousedown(draggable[i].start);
+ draggable.splice(i, 1);
+ eve.unbind("raphael.drag.*." + this.id);
+ }
+ !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp);
+ };
+
+
+ /***************** Drag *****************/
+ /************ TRANSFORMATIONS *************/
+
+
+
+ elproto.rotate = function(deg, cx, cy) {
+
+ var o = this,
+ bbox;
+ if (o.removed) {
+ return o;
+ }
+ deg = Str(deg).split(separator);
+ if (deg.length - 1) {
+ cx = toFloat(deg[1]);
+ cy = toFloat(deg[2]);
+ }
+ deg = toFloat(deg[0]);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ bbox = o.getBBox(1);
+ cx = bbox.x + bbox.width / 2;
+ cy = bbox.y + bbox.height / 2;
+ }
+ o.transform(o._.transform.concat([["r", deg, cx, cy]]));
+ return o;
+ };
+
+ elproto.scale = function(sx, sy, cx, cy) {
+ var o = this,
+ bbox;
+ if (o.removed) {
+ return o;
+ }
+ sx = Str(sx).split(separator);
+ if (sx.length - 1) {
+ sy = toFloat(sx[1]);
+ cx = toFloat(sx[2]);
+ cy = toFloat(sx[3]);
+ }
+ sx = toFloat(sx[0]);
+ (sy == null) && (sy = sx);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ bbox = o.getBBox(1);
+ }
+ cx = cx == null ? bbox.x + bbox.width / 2 : cx;
+ cy = cy == null ? bbox.y + bbox.height / 2 : cy;
+ o.transform(o._.transform.concat([["s", sx, sy, cx, cy]]));
+
+ return o;
+ };
+
+ elproto.translate = function(dx, dy) {
+ var o = this;
+ if (o.removed) {
+ return o;
+ }
+ dx = Str(dx).split(separator);
+ if (dx.length - 1) {
+ dy = toFloat(dx[1]);
+ }
+ dx = toFloat(dx[0]) || 0;
+ dy = +dy || 0;
+ o.transform(o._.transform.concat([["t", dx, dy]]));
+
+ return o;
+ };
+
+ elproto.transform = function(tstr) {
+
+ var o = this,
+ _ = o._,
+ sw;
+
+ if (tstr === null) {
+ return _.transform;
+ }
+
+ R._extractTransform(o, tstr);
+
+ /* @todo: what changes to be made here in the context of canvas */
+ /*o.clip && !_.clipispath && $(o.clip, {
+ transform: o.matrix.invert()
+ });
+ o.pattern && updatePosition(o); */
+ if (_.sx != 1 || _.sy != 1) {
+ sw = o.attrs[has]("stroke-width") ? o.attrs["stroke-width"] : 1;
+ o.attr({
+ "stroke-width": sw
+ });
+ }
+
+ o.node && o.node.redraw();
+
+ return o;
+ };
+
+ /************ TRANSFORMATIONS *************/
+
+
+ elproto.hide = function() {
+ return this;
+ };
+
+ elproto.show = function() {
+ return this;
+ };
+
+ elproto.blur = function(size) {
+ return this;
+ };
+
+ elproto.on = function(eventType, handler) {
+ var el = this,
+ listeners = el.listeners;
+
+ if (!listeners) {
+ listeners = el.listeners = {};
+ }
+
+ if (!listeners[eventType]) {
+ listeners[eventType] = [];
+ }
+
+ listeners[eventType].push(handler);
+ };
+
+ elproto.remove = function() {
+ return this;
+ };
+
+
+
+
+ paperproto.clear = function () {
+ eve("raphael.clear", this);
+ return this;
+ };
+
+ paperproto.remove = function () {
+ if (this.removed) {
+ return;
+ }
+
+ var paper = this,
+ canvas = paper.canvas,
+ pn = canvas.parentNode,
+ i;
+
+ eve("raphael.remove", paper);
+ pn.removeChild(canvas);
+
+ for (i in paper) {
+ paper[i] = typeof paper[i] == "function" ? R._removedFactory(i) : null;
+ }
+
+ this.removed = true;
+ };
+
+ R.toString = function () {
+ return "Your browser supports canvas.\nYou are running RedRaphael " +
+ R.version;
+ };
+
+ for (var method in elproto) {
+ if (elproto.hasOwnProperty(method) &&
+ !setproto.hasOwnProperty(method)) {
+ setproto[method] = (function (methodname) {
+ return function () {
+ var arg = arguments;
+ return this.forEach(function (el) {
+ el[methodname].apply(el, arg);
+ });
+ };
+ })(method);
+ }
+ };
+
+})();
+
+
+
+ // EXPOSE
+ // SVG and VML are appended just before the EXPOSE line
+ // Even with AMD, Raphael should be defined globally
+ oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
+
+ return R;
+}));
\ No newline at end of file
diff --git a/source/Gruntfile.js b/source/Gruntfile.js
new file mode 100644
index 0000000..804f984
--- /dev/null
+++ b/source/Gruntfile.js
@@ -0,0 +1,109 @@
+
+"use strict";
+
+module.exports = function(grunt) {
+ var pkg = grunt.file.readJSON('package.json');
+
+ // Project configuration.
+ grunt.initConfig({
+ // Metadata.
+ pkg: pkg,
+ banner: grunt.file.read("copy.js").replace(/@VERSION/, pkg.version).replace(/@RVERSION/, pkg.rversion),
+ // Task configuration.
+ uglify: {
+ options: {
+ banner: "<%= banner %>"
+ },
+ dist: {
+ src: "<%= build.dist.dest %>",
+ dest: "package/<%= pkg.filename %>-min.js"
+ }
+ },
+ build: {
+ options: {
+ banner: "<%= banner %>"
+ },
+ dist: {
+ dest: "package/raphael.js",
+ src: [
+ "source/eve/eve.js",
+ "source/raphael.core.js",
+ "source/raphael.svg.js",
+ "source/raphael.vml.js",
+ "source/raphael.canvas.js"
+ ]
+ }
+ },
+ jasmine: {
+ pivotal: {
+ src: 'package/raphael-min.js',
+ options: {
+ specs: 'tests/*Spec.js',
+ helpers: 'tests/*Helper.js'
+ }
+ }
+ }
+ });
+
+
+ // These plugins provide necessary tasks.
+ grunt.loadNpmTasks("grunt-contrib-uglify");
+ grunt.loadNpmTasks("grunt-contrib-jasmine");
+
+ // Special concat/build task to handle RedRaphael's build requirements
+ grunt.registerMultiTask(
+ "build",
+ "Concatenate source, remove individual closures, embed version",
+ function() {
+ var data = this.data,
+ name = data.dest,
+ src = data.src,
+ options = this.options({
+ banner: ""
+ }),
+ // Start with banner
+ compiled = options.banner,
+ svgorvmlRegex = /\.(svg|vml|canvas)\.js/,
+ closureRegex = /window\.Raphael.*\(R\)\s*\{/,
+ closureEndRegex = /\}\(window\.Raphael\);\s*$/,
+ exposeRegex = /(\r?\n\s*\/\/\s*EXPOSE(?:\r|\n|.)*\}\)\);)/;
+
+ // Concatenate src
+ src.forEach(function(path) {
+ var source = grunt.file.read(path);
+ var match = svgorvmlRegex.exec(path);
+
+ // If either SVG or VML,
+ // remove the closure and add an early return if not required
+ if (match) {
+ source = "\n\n" +
+ source.replace(closureRegex,
+ "(function(){\n" +
+ " if (!R." + match[1] + ") {\n" +
+ " return;\n" +
+ " }"
+ )
+ .replace( closureEndRegex, "})();" );
+
+ // Add source before EXPOSE line
+ compiled.replace(exposeRegex, function () {
+ // Using this method instead of the raphael way as it makes it difficult to
+ // to have the string '$1' in the target file like raphael.svg.js.
+ var text = arguments[3],
+ index = arguments[2];
+
+ compiled = (text.slice(0, index) + source + text.slice(index));
+ });
+
+ } else {
+ compiled += source;
+ }
+ });
+
+ grunt.file.write( name, compiled );
+ }
+ );
+
+ // Default task.
+ grunt.registerTask("default", ["build", "uglify", "jasmine"]);
+};
\ No newline at end of file
diff --git a/source/copy.js b/source/copy.js
new file mode 100644
index 0000000..456357a
--- /dev/null
+++ b/source/copy.js
@@ -0,0 +1,10 @@
+/**!
+ * RedRaphael @VERSION - JavaScript Vector Library
+ * Copyright (c) 2012-2013 FusionCharts Technologies
+ *
+ * Raphael @RVERSION
+ * Copyright (c) 2008-2012 Dmitry Baranovskiy
+ * Copyright © 2008-2012 Sencha Labs
+ *
+ * Licensed under the MIT license.
+ */
diff --git a/source/eve/LICENSE b/source/eve/LICENSE
new file mode 100644
index 0000000..86a96fa
--- /dev/null
+++ b/source/eve/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2013 Adobe Systems Incorporated
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/source/eve/README.md b/source/eve/README.md
new file mode 100644
index 0000000..c129612
--- /dev/null
+++ b/source/eve/README.md
@@ -0,0 +1,7 @@
+# Eve
+
+Tiny event helping JavaScript library.
+
+MIT Licence
+
+For use case look at e.html
diff --git a/source/eve/component.json b/source/eve/component.json
new file mode 100644
index 0000000..651815f
--- /dev/null
+++ b/source/eve/component.json
@@ -0,0 +1,13 @@
+{
+ "name": "eve",
+ "repo": "DmitryBaranovskiy/eve",
+ "description": "Custom Events",
+ "version": "0.4.1",
+ "keywords": ["events"],
+ "dependencies": {},
+ "development": {},
+ "main": "eve.js",
+ "scripts": [
+ "eve.js"
+ ]
+}
\ No newline at end of file
diff --git a/source/eve/e.html b/source/eve/e.html
new file mode 100644
index 0000000..6687278
--- /dev/null
+++ b/source/eve/e.html
@@ -0,0 +1,66 @@
+
+
+
+ Eve Use Case
+
+
+
+
+
diff --git a/source/eve/eve.js b/source/eve/eve.js
new file mode 100644
index 0000000..23f71b9
--- /dev/null
+++ b/source/eve/eve.js
@@ -0,0 +1,371 @@
+// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ┌────────────────────────────────────────────────────────────┐ \\
+// │ Eve 0.4.2 - JavaScript Events Library │ \\
+// ├────────────────────────────────────────────────────────────┤ \\
+// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
+// └────────────────────────────────────────────────────────────┘ \\
+
+(function (glob) {
+ var version = "0.4.2",
+ has = "hasOwnProperty",
+ separator = /[\.\/]/,
+ wildcard = "*",
+ fun = function () {},
+ numsort = function (a, b) {
+ return a - b;
+ },
+ current_event,
+ stop,
+ events = {n: {}},
+ /*\
+ * eve
+ [ method ]
+
+ * Fires event with given `name`, given scope and other parameters.
+
+ > Arguments
+
+ - name (string) name of the *event*, dot (`.`) or slash (`/`) separated
+ - scope (object) context for the event handlers
+ - varargs (...) the rest of arguments will be sent to event handlers
+
+ = (object) array of returned values from the listeners
+ \*/
+ eve = function (name, scope) {
+ name = String(name);
+ var e = events,
+ oldstop = stop,
+ args = Array.prototype.slice.call(arguments, 2),
+ listeners = eve.listeners(name),
+ z = 0,
+ f = false,
+ l,
+ indexed = [],
+ queue = {},
+ out = [],
+ ce = current_event,
+ errors = [];
+ current_event = name;
+ stop = 0;
+ for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
+ indexed.push(listeners[i].zIndex);
+ if (listeners[i].zIndex < 0) {
+ queue[listeners[i].zIndex] = listeners[i];
+ }
+ }
+ indexed.sort(numsort);
+ while (indexed[z] < 0) {
+ l = queue[indexed[z++]];
+ out.push(l.apply(scope, args));
+ if (stop) {
+ stop = oldstop;
+ return out;
+ }
+ }
+ for (i = 0; i < ii; i++) {
+ l = listeners[i];
+ if ("zIndex" in l) {
+ if (l.zIndex == indexed[z]) {
+ out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ do {
+ z++;
+ l = queue[indexed[z]];
+ l && out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ } while (l)
+ } else {
+ queue[l.zIndex] = l;
+ }
+ } else {
+ out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ }
+ }
+ stop = oldstop;
+ current_event = ce;
+ return out.length ? out : null;
+ };
+ // Undocumented. Debug only.
+ eve._events = events;
+ /*\
+ * eve.listeners
+ [ method ]
+
+ * Internal method which gives you array of all event handlers that will be triggered by the given `name`.
+
+ > Arguments
+
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated
+
+ = (array) array of event handlers
+ \*/
+ eve.listeners = function (name) {
+ var names = name.split(separator),
+ e = events,
+ item,
+ items,
+ k,
+ i,
+ ii,
+ j,
+ jj,
+ nes,
+ es = [e],
+ out = [];
+ for (i = 0, ii = names.length; i < ii; i++) {
+ nes = [];
+ for (j = 0, jj = es.length; j < jj; j++) {
+ e = es[j].n;
+ items = [e[names[i]], e[wildcard]];
+ k = 2;
+ while (k--) {
+ item = items[k];
+ if (item) {
+ nes.push(item);
+ out = out.concat(item.f || []);
+ }
+ }
+ }
+ es = nes;
+ }
+ return out;
+ };
+
+ /*\
+ * eve.on
+ [ method ]
+ **
+ * Binds given event handler with a given name. You can use wildcards “`*`” for the names:
+ | eve.on("*.under.*", f);
+ | eve("mouse.under.floor"); // triggers f
+ * Use @eve to trigger the listener.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ **
+ = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
+ > Example:
+ | eve.on("mouse", eatIt)(2);
+ | eve.on("mouse", scream);
+ | eve.on("mouse", catchIt)(1);
+ * This will ensure that `catchIt()` function will be called before `eatIt()`.
+ *
+ * If you want to put your handler before non-indexed handlers, specify a negative value.
+ * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
+ \*/
+ eve.on = function (name, f) {
+ name = String(name);
+ if (typeof f != "function") {
+ return function () {};
+ }
+ var names = name.split(separator),
+ e = events;
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ e = e.n;
+ e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}});
+ }
+ e.f = e.f || [];
+ for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
+ return fun;
+ }
+ e.f.push(f);
+ return function (zIndex) {
+ if (+zIndex == +zIndex) {
+ f.zIndex = +zIndex;
+ }
+ };
+ };
+ /*\
+ * eve.f
+ [ method ]
+ **
+ * Returns function that will fire given event with optional arguments.
+ * Arguments that will be passed to the result function will be also
+ * concated to the list of final arguments.
+ | el.onclick = eve.f("click", 1, 2);
+ | eve.on("click", function (a, b, c) {
+ | console.log(a, b, c); // 1, 2, [event object]
+ | });
+ > Arguments
+ - event (string) event name
+ - varargs (…) and any other arguments
+ = (function) possible event handler function
+ \*/
+ eve.f = function (event) {
+ var attrs = [].slice.call(arguments, 1);
+ return function () {
+ eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0)));
+ };
+ };
+ /*\
+ * eve.stop
+ [ method ]
+ **
+ * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
+ \*/
+ eve.stop = function () {
+ stop = 1;
+ };
+ /*\
+ * eve.nt
+ [ method ]
+ **
+ * Could be used inside event handler to figure out actual name of the event.
+ **
+ > Arguments
+ **
+ - subname (string) #optional subname of the event
+ **
+ = (string) name of the event, if `subname` is not specified
+ * or
+ = (boolean) `true`, if current event’s name contains `subname`
+ \*/
+ eve.nt = function (subname) {
+ if (subname) {
+ return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
+ }
+ return current_event;
+ };
+ /*\
+ * eve.nts
+ [ method ]
+ **
+ * Could be used inside event handler to figure out actual name of the event.
+ **
+ **
+ = (array) names of the event
+ \*/
+ eve.nts = function () {
+ return current_event.split(separator);
+ };
+ /*\
+ * eve.off
+ [ method ]
+ **
+ * Removes given function from the list of event listeners assigned to given name.
+ * If no arguments specified all the events will be cleared.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ \*/
+ /*\
+ * eve.unbind
+ [ method ]
+ **
+ * See @eve.off
+ \*/
+ eve.off = eve.unbind = function (name, f) {
+ if (!name) {
+ eve._events = events = {n: {}};
+ return;
+ }
+ var names = name.split(separator),
+ e,
+ key,
+ splice,
+ i, ii, j, jj,
+ cur = [events];
+ for (i = 0, ii = names.length; i < ii; i++) {
+ for (j = 0; j < cur.length; j += splice.length - 2) {
+ splice = [j, 1];
+ e = cur[j].n;
+ if (names[i] != wildcard) {
+ if (e[names[i]]) {
+ splice.push(e[names[i]]);
+ }
+ } else {
+ for (key in e) if (e[has](key)) {
+ splice.push(e[key]);
+ }
+ }
+ cur.splice.apply(cur, splice);
+ }
+ }
+ for (i = 0, ii = cur.length; i < ii; i++) {
+ e = cur[i];
+ while (e.n) {
+ if (f) {
+ if (e.f) {
+ for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) {
+ e.f.splice(j, 1);
+ break;
+ }
+ !e.f.length && delete e.f;
+ }
+ for (key in e.n) if (e.n[has](key) && e.n[key].f) {
+ var funcs = e.n[key].f;
+ for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) {
+ funcs.splice(j, 1);
+ break;
+ }
+ !funcs.length && delete e.n[key].f;
+ }
+ } else {
+ delete e.f;
+ for (key in e.n) if (e.n[has](key) && e.n[key].f) {
+ delete e.n[key].f;
+ }
+ }
+ e = e.n;
+ }
+ }
+ };
+ /*\
+ * eve.once
+ [ method ]
+ **
+ * Binds given event handler with a given name to only run once then unbind itself.
+ | eve.once("login", f);
+ | eve("login"); // triggers f
+ | eve("login"); // no listeners
+ * Use @eve to trigger the listener.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ **
+ = (function) same return function as @eve.on
+ \*/
+ eve.once = function (name, f) {
+ var f2 = function () {
+ eve.unbind(name, f2);
+ return f.apply(this, arguments);
+ };
+ return eve.on(name, f2);
+ };
+ /*\
+ * eve.version
+ [ property (string) ]
+ **
+ * Current version of the library.
+ \*/
+ eve.version = version;
+ eve.toString = function () {
+ return "You are running Eve " + version;
+ };
+ (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define != "undefined" ? (define("eve", [], function() { return eve; })) : (glob.eve = eve));
+})(this);
diff --git a/source/eve/package.json b/source/eve/package.json
new file mode 100644
index 0000000..8fb1bb9
--- /dev/null
+++ b/source/eve/package.json
@@ -0,0 +1,18 @@
+{
+ "name" : "eve",
+
+ "author" : {
+ "name" : "Dmitry Baranovskiy",
+ "email" : "dmitry@baranovskiy.com",
+ "url" : "http://dmitry.baranovskiy.com"
+ },
+ "description" : "Simple custom events",
+ "version" : "0.4.1",
+
+ "main" : "./eve.js",
+
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:adobe/eve.git"
+ }
+}
diff --git a/source/make b/source/make
new file mode 100755
index 0000000..8c20e5f
--- /dev/null
+++ b/source/make
@@ -0,0 +1,59 @@
+#!/usr/bin/env node
+var ujs = require('uglify-js'),
+ fs = require('fs'),
+
+ noticeText = function() {
+/**!
+ * RedRaphael 1.0.0 - JavaScript Vector Library
+ * Copyright (c) 2012-2013 FusionCharts Technologies
+ *
+ * Raphael 2.1.0
+ * Copyright (c) 2008-2012 Dmitry Baranovskiy
+ * Copyright © 2008-2012 Sencha Labs
+ *
+ * Licensed under the MIT license.
+ */
+ }.toString().slice(14,-3),
+
+ input = {
+ core : 'raphael.core.js',
+ svg : 'raphael.svg.js',
+ vml : 'raphael.vml.js',
+ canvas: 'raphael.canvas.js',
+ eve : 'eve/eve.js'
+ },
+ outPath = "../package/",
+ output = {
+ 'raphael-min.js' : ['eve', 'core', 'svg', 'vml', 'canvas'],
+ 'raphael.js' : ['eve', 'core', 'svg', 'vml', 'canvas']
+ };
+
+for (var file in input) {
+ input[file] = fs.readFileSync(input[file], 'utf8');
+}
+for (file in output) {
+ var out = '';
+ if (file.indexOf('min') !== -1) {
+ console.log('Compressing ' + file);
+ for (var i = 0, l = output[file].length; i < l; i++) {
+ var o = ujs.minify(input[output[file][i]], {
+ fromString : true
+ });
+ out += o.code;
+ }
+ } else {
+ console.log('Concatinating ' + file);
+ for (i = 0, l = output[file].length; i < l; i++) {
+ out += input[output[file][i]] + '\n';
+ }
+ }
+ (function(f, code){
+ fs.writeFile(f, noticeText + '\n' + code, function(err) {
+ if (err) {
+ console.log(err);
+ } else {
+ console.log('Saved to \033[32m' + f + '\033[0m\n');
+ }
+ });
+ })(outPath + file, out);
+}
diff --git a/source/raphael.canvas.js b/source/raphael.canvas.js
new file mode 100644
index 0000000..0a0fc8c
--- /dev/null
+++ b/source/raphael.canvas.js
@@ -0,0 +1,2734 @@
+/*jslint forin: true, regexp: true, todo: true, white: false, browser: true,
+ sloppy: true, white: true, eqeq: false, newcap: true, nomen: true */
+
+/*global FusionCharts */
+
+/**
+ * Raphael Canvas Extension
+ */
+
+window.Raphael && window.Raphael.canvas && function (R) {
+ var win = R._g.win,
+ doc = R._g.doc,
+ g = R._g,
+
+ STRING = 'string',
+ PX = 'px',
+
+ separator = /[, ]+/,
+
+ Str = win.String,
+ toInt = win.parseInt,
+ toFloat = win.parseFloat,
+
+ math = win.Math,
+ mmax = math.max,
+ mmin = math.min,
+ pi = math.PI,
+ mathFloor = math.floor,
+
+ eve = R.eve,
+ paperproto = R.fn,
+ elproto = R.el,
+ setproto = R.st,
+
+ clone = R.clone,
+ deg2rad = pi / 180,
+ rad2deg = 180 / pi,
+
+ DEFAULT_FILL = "#fff",
+ DEFAULT_STROKE = "#000",
+ has = "hasOwnProperty",
+ S = " ",
+ /* @todo: detect touch */
+ supportsTouch = (('ontouchstart' in win) || (navigator.msMaxTouchPoints > 0)),
+ events = ("click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel").split(S),
+ noHandle = false,
+
+ $,
+ FauxNode,
+ Element,
+ draggable = [],
+ drag = [],
+ dragMove = function(e) {
+ var x = e.clientX,
+ y = e.clientY,
+ scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
+ dragi,
+ j = drag.length;
+ while (j--) {
+ dragi = drag[j];
+ if (supportsTouch) {
+ var i = e.touches.length,
+ touch;
+ while (i--) {
+ touch = e.touches[i];
+ if (touch.identifier == dragi.el._drag.id) {
+ x = touch.clientX;
+ y = touch.clientY;
+ (e.originalEvent ? e.originalEvent : e).preventDefault();
+ break;
+ }
+ }
+ } else {
+ e.preventDefault();
+ }
+
+ //var node = dragi.el.node;
+ //o,
+ //next = node.nextSibling,
+ //parent = node.parentNode,
+ //display = node.style.display;
+
+ /* @todo: implement raphael.drag.over */
+
+ //g.win.opera && parent.removeChild(node);
+ //node.style.display = "none";
+ //o = dragi.el.paper.getElementByPoint(x, y);
+ //node.style.display = display;
+ //g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
+ //o && eve("raphael.drag.over." + dragi.el.id, dragi.el, o);
+ x += scrollX;
+ y += scrollY;
+ eve("raphael.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
+ }
+ },
+ dragUp = function(e) {
+ R.unmousemove(dragMove).unmouseup(dragUp);
+ var i = drag.length,
+ dragi;
+ while (i--) {
+ dragi = drag[i];
+ dragi.el._drag = {};
+ eve("raphael.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
+ }
+ drag = [];
+ };
+
+
+ if (!R.canvas) {
+ return;
+ }
+
+ $ = R._createNode = function(el, attr) {
+ if (attr) {
+ if (typeof el === STRING) {
+ el = $(el);
+ }
+ for (var key in attr)
+ if (attr.hasOwnProperty(key)) {
+ el.setAttribute(key, Str(attr[key]));
+ }
+ } else {
+ el = doc.createElement(el);
+ }
+ return el;
+ };
+
+ R._getConnectedNodes = function (node) {
+ return {
+ above: [],
+ below: []
+ };
+ };
+
+ R._getTargetNode = function (coords) {
+ var x = coords[0],
+ y = coords[1];
+
+
+ };
+
+ R._containerEventHandler = function (event) {
+ event = event || win.event;
+
+ if (noHandle) {
+ return;
+ }
+
+ /* @todo: do not use offsetX and offsetY */
+ var x = event.offsetX,//mathFloor(event.pageX || (event.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft) || 0),
+ y = event.offsetY,//mathFloor(event.pageY || (event.clientY + doc.body.scrollTop + doc.documentElement.scrollTop) || 0),
+ type = event.type,
+ node = R._getTargetNode([x, y]);
+
+ //console.log(type + ":: x: " + x + " y: " + y);
+
+ /*
+ if (typeof node.listeners[type] === 'function') {
+ node.listeners[type].call(node, e);
+ }*/
+
+ };
+
+
+
+
+
+ FauxNode = function (parent) {
+ this.type = "basic";
+
+ this.owner = parent;
+
+ // Element reference needed to get attrs so that there is no need to
+ // maintain a redundant copy.
+ this._rElement = null;
+
+ // False if this element does not need mouse interactivity.
+ this.mouseInteractions = false;
+ this.matrix = null;
+
+ // An outline path that will be the outline of the shape or in case of
+ // text the rect that bounds the text.
+ this.outlinePath = null;
+
+ this.conf = {};
+ };
+
+ FauxNode.prototype = {
+
+ constructor: FauxNode,
+
+ /**
+ * This method does the complete rendering of the element, including
+ * (re)setting the bbox and image map.
+ *
+ * @returns {_L10.FauxNode.prototype}
+ */
+ render: function () {
+
+ var o = this;
+
+ o.draw();
+ o.setBBox();
+
+ return o;
+ },
+
+ /**
+ * Applies the transforms and clipping to the context and draws the
+ * element.
+ *
+ * @returns {undefined}
+ */
+ draw: function () {
+ var o = this,
+ ctx = o.context,
+ el = o._rElement,
+ m = el.matrix,
+ isClipped = o.isClipped,
+ attrs = o.validateAttrs(),
+ cr,
+ end;
+
+
+ // After the validation the attributes need to be set to the element
+ // as validateAttrs works on a copy of the attrs object.
+ el.attrs = attrs;
+
+ ctx.save();
+
+ ctx.fillStyle = attrs.fill;
+ ctx.strokeStyle = attrs.stroke;
+ ctx.lineWidth = attrs['stroke-width'];
+
+ // Applying the clip before the context is transformed as is the case
+ // in case of SVG.
+ if (cr = attrs['clip-rect']) {
+ cr = cr.split(" ");
+ ctx.rect(cr[0], cr[1], cr[2], cr[3]);
+ ctx.clip();
+ isClipped = o.isClipped = true;
+ }
+
+ o.applyTransform(m);
+
+ o.paint();
+
+ ctx.restore();
+ },
+
+ /**
+ * Parse the attributes provided to paint the element shape using the
+ * canvas context.
+ *
+ * Overridden by individual derived FauxNodes
+ */
+ paint: function () {
+ },
+
+ /**
+ * The redraw of the FauxNodes is to be handled by the CanvasObjectModel
+ * instance as it involves redrawing all the elements corresponsing to
+ * that canvas in the proper order.
+ */
+ redraw: function () {
+ this.COMInstance.redraw(this);
+ },
+
+ /**
+ * Clears the rectangle corresponding to the bounding box of the node.
+ */
+ clear: function () {
+ var o = this,
+ ctx = o.context,
+ bbox = o._bbox;
+
+ /* @todo: while clearing the stroke-width also needs to be accounted for. */
+ if (bbox) {
+ ctx.clearRect(bbox.x, bbox.y, bbox.width, bbox.height);
+ }
+ },
+
+ /**
+ * Creates the area node in the image map so that mouse interactivity
+ * can be emulated using it.
+ */
+ addMouseInteractivity: function () {
+ var o = this,
+ attrs = o._rElement.attrs,
+ bbox = o._bbox,
+ map = o.owner.wrapper._map,
+ shape = (o.type === 'circle') ? 'circle' : 'rect',
+ coords = (shape === 'circle') ? [attrs.cx, attrs.cy, attrs.r].join(",")
+ : [bbox.x, bbox.y, bbox.x2, bbox.y2].join(","),
+ area,
+ end;
+
+ area = $('area', {shape: shape, coords: coords});
+ if (map.firstChild) {
+ map.insertBefore(area, map.firstChild);
+ }
+ else {
+ map.appendChild(area);
+ }
+
+ /* @todo: should be put this check here */
+ o._mouseArea = area;
+
+ // Needed for paths.
+ o.eventListeners = {};
+ },
+
+
+ /**
+ * Update the coords of the area node (image map) corresponding to the FauxNode
+ * after it has been modified by changing attributes.
+ */
+ updateMapAreaCoords: function () {
+ var o = this,
+ oArea = o._mouseArea,
+ bbox = o._bbox;
+
+ if (oArea) {
+ //o.context.strokeRect(bbox.x, bbox.y, bbox.width, bbox.height);
+ if (o instanceof CircleFauxNode) {
+ var r = bbox.width / 2;
+ oArea.setAttribute('coords',
+ [bbox.x + r, bbox.y + r, r].join(","));
+ }
+ else {
+ oArea.setAttribute('coords',
+ [bbox.x, bbox.y, bbox.x2, bbox.y2].join(","));
+ }
+ }
+ },
+
+ /**
+ * Applies the transform given the transformation matrix to the context.
+ *
+ * @param {type} matrix
+ * @param {type} bbox
+ * @param {type} dontsetbbox
+ *
+ * @returns {_L10.FauxNode.prototype.transformBBox.tbox}
+ */
+ applyTransform: function (m) {
+ var o = this,
+ ctx = o.context,
+ split;
+
+ if (m) {
+ split = m.split();
+ ctx.translate(split.dx, split.dy);
+ !split.noRotation && ctx.rotate(deg2rad * split.rotate);
+ ctx.scale(split.scalex, split.scaley);
+ }
+ },
+
+ /**
+ *
+ */
+ setBBox: function () {
+ var o = this,
+ el = o._rElement,
+ m = el.matrix,
+ parent = o.owner,
+ pm = parent.getTransformMatrix && parent.getTransformMatrix();
+
+ if (pm) {
+ pm = pm.clone();
+ pm.add(m);
+ m = pm;
+ }
+
+ if (o.outlinePath) {
+ o._bbox = R.pathBBox(R.transformPath(o.outlinePath, m.toTransformString()).toString());
+ }
+ else {
+ o.setShapeBBox(m);
+ }
+
+ o._mouseArea && o.updateMapAreaCoords();
+ },
+
+ getBBox: function () {
+ return this._bbox;
+ },
+
+ drawPath: function (path) {
+ var o = this,
+ ctx = o.context,
+ len = (path && path.length) || 0,
+ pp = PathParser,
+ i = 0,
+ command,
+ x,
+ y,
+ end;
+
+ // The PathParser object has been borrowed from canvg. All 3rd party attributions implied.
+ pp.reset();
+ pp.setTokens(path);
+
+ //var bb = new BoundingBox();
+ if (ctx != null) {
+ ctx.beginPath();
+ }
+
+ while (!pp.isEnd()) {
+ pp.nextCommand();
+ switch (pp.command) {
+ case 'M':
+ case 'm':
+ var p = pp.getAsCurrentPoint();
+ pp.addMarker(p);
+ //bb.addPoint(p.x, p.y);
+ if (ctx != null) {
+ ctx.moveTo(p.x, p.y);
+ }
+ pp.start = pp.current;
+ while (!pp.isCommandOrEnd()) {
+ var p = pp.getAsCurrentPoint();
+ pp.addMarker(p, pp.start);
+ //bb.addPoint(p.x, p.y);
+ if (ctx != null) {
+ ctx.lineTo(p.x, p.y);
+ }
+ }
+ break;
+ case 'L':
+ case 'l':
+ while (!pp.isCommandOrEnd()) {
+ var c = pp.current;
+ var p = pp.getAsCurrentPoint();
+ pp.addMarker(p, c);
+ //bb.addPoint(p.x, p.y);
+ if (ctx != null) {
+ ctx.lineTo(p.x, p.y);
+ }
+ }
+ break;
+ case 'H':
+ case 'h':
+ while (!pp.isCommandOrEnd()) {
+ var newP = new Point((pp.isRelativeCommand() ? pp.current.x : 0) + pp.getScalar(), pp.current.y);
+ pp.addMarker(newP, pp.current);
+ pp.current = newP;
+ //bb.addPoint(pp.current.x, pp.current.y);
+ if (ctx != null) {
+ ctx.lineTo(pp.current.x, pp.current.y);
+ }
+ }
+ break;
+ case 'V':
+ case 'v':
+ while (!pp.isCommandOrEnd()) {
+ var newP = new Point(pp.current.x, (pp.isRelativeCommand() ? pp.current.y : 0) + pp.getScalar());
+ pp.addMarker(newP, pp.current);
+ pp.current = newP;
+ //bb.addPoint(pp.current.x, pp.current.y);
+ if (ctx != null) {
+ ctx.lineTo(pp.current.x, pp.current.y);
+ }
+ }
+ break;
+ case 'C':
+ case 'c':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var p1 = pp.getPoint();
+ var cntrl = pp.getAsControlPoint();
+ var cp = pp.getAsCurrentPoint();
+ pp.addMarker(cp, cntrl, p1);
+ //bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ if (ctx != null) {
+ ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ }
+ }
+ break;
+ case 'S':
+ case 's':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var p1 = pp.getReflectedControlPoint();
+ var cntrl = pp.getAsControlPoint();
+ var cp = pp.getAsCurrentPoint();
+ pp.addMarker(cp, cntrl, p1);
+ //bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ if (ctx != null) {
+ ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ }
+ }
+ break;
+ case 'Q':
+ case 'q':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var cntrl = pp.getAsControlPoint();
+ var cp = pp.getAsCurrentPoint();
+ pp.addMarker(cp, cntrl, cntrl);
+ //bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
+ }
+ break;
+ case 'T':
+ case 't':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var cntrl = pp.getReflectedControlPoint();
+ pp.control = cntrl;
+ var cp = pp.getAsCurrentPoint();
+ pp.addMarker(cp, cntrl, cntrl);
+ //bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);
+ if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
+ }
+ break;
+ case 'A':
+ case 'a':
+ while (!pp.isCommandOrEnd()) {
+ var curr = pp.current;
+ var rx = pp.getScalar();
+ var ry = pp.getScalar();
+ var xAxisRotation = pp.getScalar() * (Math.PI / 180.0);
+ var largeArcFlag = pp.getScalar();
+ var sweepFlag = pp.getScalar();
+ var cp = pp.getAsCurrentPoint();
+
+ // Conversion from endpoint to center parameterization
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+ // x1', y1'
+ var currp = new Point(
+ Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0,
+ -Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0
+ );
+ // adjust radii
+ var l = Math.pow(currp.x,2)/Math.pow(rx,2)+Math.pow(currp.y,2)/Math.pow(ry,2);
+ if (l > 1) {
+ rx *= Math.sqrt(l);
+ ry *= Math.sqrt(l);
+ }
+ // cx', cy'
+ var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt(
+ ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) /
+ (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2))
+ );
+ if (isNaN(s)) s = 0;
+ var cpp = new Point(s * rx * currp.y / ry, s * -ry * currp.x / rx);
+ // cx, cy
+ var centp = new Point(
+ (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y,
+ (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y
+ );
+ // vector magnitude
+ var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); }
+ // ratio between two vectors
+ var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) }
+ // angle between two vectors
+ var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); }
+ // initial angle
+ var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]);
+ // angle delta
+ var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry];
+ var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry];
+ var ad = a(u, v);
+ if (r(u,v) <= -1) ad = Math.PI;
+ if (r(u,v) >= 1) ad = 0;
+
+ // for markers
+ var dir = 1 - sweepFlag ? 1.0 : -1.0;
+ var ah = a1 + dir * (ad / 2.0);
+ var halfWay = new Point(
+ centp.x + rx * Math.cos(ah),
+ centp.y + ry * Math.sin(ah)
+ );
+ pp.addMarkerAngle(halfWay, ah - dir * Math.PI / 2);
+ pp.addMarkerAngle(cp, ah - dir * Math.PI);
+
+ //bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better
+ if (ctx != null) {
+ var r = rx > ry ? rx : ry;
+ var sx = rx > ry ? 1 : rx / ry;
+ var sy = rx > ry ? ry / rx : 1;
+
+ ctx.translate(centp.x, centp.y);
+ ctx.rotate(xAxisRotation);
+ ctx.scale(sx, sy);
+ ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag);
+ ctx.scale(1/sx, 1/sy);
+ ctx.rotate(-xAxisRotation);
+ ctx.translate(-centp.x, -centp.y);
+ }
+ }
+ break;
+ case 'Z':
+ case 'z':
+ if (ctx != null) ctx.closePath();
+ pp.current = pp.start;
+ }
+ }
+
+ o.outlinePath = path;
+
+ return o;
+ },
+
+ /**
+ * Methods to add and remove event listeners emulating the DOM of
+ * standard browsers (and also the non-standard one).
+ */
+ addEventListener: function () {
+ var o = this,
+ args = arguments,
+ eventName = args && args[0],
+ handler = args && args[1],
+ area,
+ checkPathHandler,
+ end;
+
+ if (!o._mouseArea) {
+ o.addMouseInteractivity();
+ }
+
+ area = o._mouseArea;
+
+ if (typeof eventName === 'string' && typeof handler === 'function') {
+ /*
+ * If the shape has an associated path then we need to check if
+ * the mouse is within the co-ordinates of the path.
+ */
+ if (o._path) {
+
+ /*
+ * If the event being listened to is mouseover, mouseout or
+ * mousemove then the mouse position has to be constantly
+ * monitored and the event handler called explicitly when
+ * appropriate.
+ */
+ if (eventName === 'mouseover' || eventName === 'mouseout' || eventName === 'mousemove') {
+
+ if (!o._mousemoveAdded) {
+ var startListening = (function (node) {
+
+ var isInside = false,
+ isOutside = true,
+ transition = false;
+
+ return function (event) {
+ /* @todo: replace layerX and layerY with
+ * standard ways of determining mouse position.
+ */
+ var x = event.layerX,
+ y = event.layerY;
+
+ transition = false;
+ /*
+ * Check if the current position of the mouse
+ * pointer lies within the path or not.
+ */
+ if (R.isPointInsidePath(node._transformPath, x, y)) {
+ /*
+ * @todo: fix isPointInsidePath to return the
+ * proper result when the mouse pointer is on
+ * the same horizontal/vertical lines as one
+ * of the vertices of the path.
+ */
+ isInside = true;
+ if (isOutside) {
+ isOutside = false;
+ transition = true;
+ }
+ }
+ else {
+ isOutside = true;
+ if (isInside) {
+ isInside = false;
+ transition = true;
+ }
+ }
+
+ // Based on the state of the flags, fire the
+ // appropriate event handlers.
+ if (isOutside && transition && node.eventListeners['mouseout']) {
+ node.eventListeners['mouseout'].apply(this, arguments);
+ }
+ if (isInside) {
+ if (transition && node.eventListeners['mouseover']) {
+ node.eventListeners['mouseover'].apply(this, arguments);
+ }
+ if (node.eventListeners['mousemove']) {
+ node.eventListeners['mousemove'].apply(this, arguments);
+ }
+ }
+ };
+ })(o);
+
+ area.addEventListener('mousemove', startListening, false);
+ o._mousemoveAdded = true;
+ }
+
+ o.eventListeners[eventName] = handler;
+ }
+ else {
+ var checkPathHandler = (function (node, handler) {
+ return function (event) {
+ if (R.isPointInsidePath(node._path, event.layerX, event.layerY)) {
+ handler.apply(this, arguments);
+ }
+ };
+ }(o, handler));
+
+ area.addEventListener(eventName, checkPathHandler, false);
+ }
+ }
+ else {
+ area.addEventListener(eventName, handler, false);
+ }
+ }
+ },
+
+ removeEventListener: function () {
+ var o = this,
+ args = arguments,
+ eventName = args && args[0],
+ handler = args && args[1],
+ area,
+ end;
+
+ if (!o._mouseArea) {
+ return;
+ }
+ area = o._mouseArea;
+
+ if (typeof eventName === 'string' && typeof handler === 'function') {
+ area.removeEventListener(eventName, handler);
+ }
+ },
+
+ attachEvent: function () {
+ },
+
+ detachEvent: function () {
+ },
+
+ validateAttrs: function (attrs) {
+
+ var o = this,
+ elAttrs = clone(o._rElement.attrs),
+ attr,
+ val;
+
+ if (attrs === null) {
+ if (o._isValid) {
+ return elAttrs;
+ }
+ else {
+ o._isValid = true;
+ }
+ }
+
+ attrs = attrs || elAttrs;
+
+ for (attr in attrs) {
+ val = attrs[attr];
+
+ switch (attr) {
+
+ default:
+ continue;
+ }
+ }
+
+ return attrs;
+ },
+
+ attrs: function () {
+ }
+ };
+
+
+
+
+ var NodeListItem = function (node) {
+ this.node = node;
+ this.next = null;
+ this.prev = null;
+ },
+
+ NodeList = function () {
+ this.top = null;
+ this.bottom = null;
+ };
+
+ NodeList.prototype = {
+
+ constructor: NodeList,
+
+ add: function (node) {
+
+ node = new NodeListItem(node);
+
+ if (!this.bottom) {
+ this.bottom = node;
+ }
+ if (this.top) {
+ this.top.next = node;
+ }
+ node.next = null;
+ node.prev = this.top;
+
+ this.top = node;
+ },
+
+ addList: function (list) {
+ if (!this.bottom) {
+ this.bottom = list.bottom;
+ }
+
+ if (this.top) {
+ this.top.next = list.bottom;
+ list.bottom.prev = this.top;
+ }
+
+ this.top = list.top;
+ },
+
+ toFront: function (node) {
+ if (this.top === node) {
+ return false;
+ }
+
+ if (this.bottom === node) {
+ this.bottom = node.next;
+ }
+
+ //var map = node.node.canvas._map,
+ // area = node.node._mouseArea;
+
+ node.prev && (node.prev.next = node.next);
+ node.next && (node.next.prev = node.prev);
+
+ this.top.next = node;
+ node.prev = this.top;
+ node.next = null;
+
+ this.top = node;
+
+ /*if (map.firstChild) {
+ map.insertBefore(area, map.firstChild);
+ }
+ else {
+ map.appendChild(area);
+ }
+
+ node.redraw();*/
+ },
+
+ toBack: function (node) {
+ if (this.bottom === node) {
+ return false;
+ }
+
+ if (this.top === node) {
+ this.top = node.prev;
+ }
+
+ //var map = node.canvas._map,
+ // area = node._mouseArea;
+
+ node.prev && (node.prev.next = node.next);
+ node.next && (node.next.prev = node.prev);
+
+ this.bottom.prev = node;
+ node.prev = null;
+ node.next = this.bottom;
+
+ this.bottom = node;
+
+ /*map.appendChild(area);
+
+ node.redraw();*/
+ },
+
+ insertBefore: function () {
+ },
+
+ insertAfter: function () {
+ },
+
+ each: function (fn, args) {
+ var item = this.bottom;
+
+ while (item) {
+ fn.apply(item.node, args);
+ item = item.next;
+ }
+ },
+
+ iterate: function (fn, args) {
+ var item = this.bottom,
+ retVal = true;
+
+ while (item) {
+ retVal = fn.apply(item.node, args);
+
+ if (retVal === false) {
+ break;
+ }
+
+ item = item.next;
+ }
+ },
+
+ dispose: function () {
+
+ this.each(function () {
+ this.node.dispose && this.node.dispose();
+ });
+
+ this.top = null;
+ this.bottom = null;
+ },
+ };
+
+ /**
+ *
+ ncowner, a NodeCollection that corresponds to the collection of which
+ the layer neing created is a part
+
+ above, a NodeCollection iterator, that indicated the collection the layer has to be rendered. If
+ not provided then this is the first layer of ncowner.
+ */
+ var CanvasLayer = function (ncowner, canvas) {
+ this.items = new NodeList();
+
+ this.owner = ncowner;
+ //this.above = above;
+ this.element = null;
+
+ if (canvas) {
+ this.element = canvas;
+ }
+ else {
+ this.init();
+ }
+ };
+
+ CanvasLayer.prototype = {
+ constructor: CanvasLayer,
+
+ appendChild: function () {
+ var o = this,
+ ownerWrapper = o.owner.wrapper,
+ ele = this.element;
+
+ if (ownerWrapper._image) {
+ ownerWrapper.insertBefore(ele, ownerWrapper._image);
+ }
+ else {
+ ownerWrapper.appendChild(ele);
+ }
+ },
+
+ insertBefore: function () {
+
+ },
+
+ insertAfter: function () {
+
+ },
+
+ init: function () {
+ this.element = $("canvas");
+ // CHECKPOINT: width and height in %?
+ $(this.element, {
+ width: this.owner.wrapper.offsetWidth,
+ height: this.owner.wrapper.offsetHeight
+ });
+
+ this.element.style.cssText = "position:absolute;left:0;top:0;";
+
+ this.appendChild();
+ },
+
+ getCanvas: function () {
+ return this.element;
+ },
+
+ getContext: function () {
+ return this.element.getContext('2d');
+ },
+
+ addToLayer: function (node) {
+ this.items.add(node);
+ },
+
+ mergeWithLayerOnTop: function (layerObj) {
+ this.items.addList(layerObj.items);
+ layerObj.dispose(true);
+ },
+
+ mergeWithLayerOnBottom: function (layerObj) {
+ layerObj.items.addList(this.items);
+ this.items = layerObj.items;
+ layerObj.dispose(true);
+ },
+
+ dispose: function (softDispose) {
+
+ if (!softDispose) {
+ this.items.each(function () {
+ this.dispose();
+ });
+ }
+
+ this.items = null;
+ this.owner = null;
+
+ this.element.parentNode.removeChild(this.element);
+ this.element = null;
+ }
+ };
+
+ var NodeCollection = function (parent, wrapper, canvas) {
+
+ this.nodeItems = new NodeList();
+ this.collectionItems = new NodeList();
+ this.layerItems = new NodeList();
+
+ this.owner = this.parent = parent;
+ this.layerOnTop = null;
+
+ this.currentLayer = null;
+ this.baseLayer = null;
+
+ if (wrapper) {
+ this.wrapper = wrapper;
+ this.currentLayer = this.baseLayer = new CanvasLayer(this, canvas);
+ }
+ else {
+ this.init();
+ }
+ };
+
+ NodeCollection.prototype = {
+ constructor: NodeCollection,
+
+ init: function () {
+
+ var o = this,
+ parent = o.parent,
+ imageMap = parent.wrapper._image,
+ wrapper = $("div");
+
+ // Hacky but need a refernce to the image map to addEventListeners.
+ wrapper.style.cssText = "width:100%;height:100%;position:absolute;left:0;top:0;";
+
+ wrapper._map = parent.wrapper._map;
+
+ if (imageMap) {
+ parent.wrapper.insertBefore(wrapper, imageMap);
+ }
+ else {
+ parent.wrapper.appendChild(wrapper);
+ }
+
+ o.wrapper = wrapper;
+ o.currentLayer = o.baseLayer = new CanvasLayer(o);
+ },
+
+ getCurrentContext: function () {
+ return this.currentLayer.getContext();
+ },
+
+ setLayerOnTop: function (layerObj) {
+ this.layerOnTop = layerObj;
+ },
+
+ getCurrentCanvas: function () {
+ return this.currentLayer.getCanvas();
+ },
+
+ addNode: function (node) {
+ this.nodeItems.add(node);
+
+ if (node.type === "group") {
+ this.addCollection(node);
+ }
+ else {
+ this.currentLayer.addToLayer(node);
+ }
+ },
+
+ addCollection: function (collectionNode) {
+
+ collectionNode = collectionNode || new NodeCollection(this);
+
+ this.collectionItems.add(collectionNode);
+ this.currentLayer = new CanvasLayer(this);
+ this.layerItems.add(this.currentLayer);
+ collectionNode.setLayerOnTop(this.currentLayer);
+ },
+
+ dispose: function () {
+ this.nodeItems.dispose();
+ this.collectionItems.dispose();
+ this.layerItems.dispose();
+ this.owner = this.parent = null;
+
+ this.ownerLayer = null;
+ this.currentLayer = null;
+ this.baseLayer = null;
+ }
+ };
+
+ /**
+ * The CanvasObjectModel will be a layer of abstraction above the individual
+ * FauxNodes created to emulate the DOM in case of canvas rendering.
+ * The engine will be the point of contact for Raphael._engine that will be
+ * the direct consumer of the FauxNodes.
+ */
+ var CanvasObjectModel = function (cnvs, wrpr, width, height) {
+
+ var com = this,
+ root = new NodeCollection(null, wrpr, cnvs);
+
+ //root.set
+
+ com.width = width;
+ com.height = height;
+
+ com.createNode = function (type, parent) {
+
+ parent = parent || root;
+
+ var node,
+ nodeItems = parent.nodeItems,
+ layer = parent.currentLayer,
+ canvasEle = layer.getCanvas();
+
+ switch (type) {
+ case 'rect':
+ node = new RectFauxNode(parent);
+ break;
+
+ case 'circle':
+ node = new CircleFauxNode(parent);
+ break;
+
+ case 'path':
+ node = new PathFauxNode(parent);
+ break;
+
+ case 'text':
+ node = new TextFauxNode(parent);
+ break;
+
+ case 'group':
+ node = new GroupFauxNode(parent);
+ parent.addCollection(node);
+ break;
+
+ default:
+ node = new FauxNode(canvasEle);
+ }
+
+ node.COMInstance = this;
+ nodeItems.add(node);
+ layer.addToLayer(node);
+
+ return node;
+ };
+
+ /**
+ * This method is needed to redraw a node. Redraw is to be handled at the
+ * COM level as redrawing one node needs all the (connected) nodes to be
+ * redrawn in the right order.
+ *
+ * @param {type} node The node that needs to be redrawn.
+ *
+ * @returns {undefined}
+ */
+ com.redraw = function (node) {
+
+ // Check if node is a group or a shape.
+ var nodeList,
+ childNode,
+ layer;
+
+ if (node.type === "group") {
+ nodeList = node.nodeItems;
+ node.render();
+ }
+ else {
+
+ layer = node.layer;
+ nodeList = layer.items;
+ childNode = nodeList.bottom;
+
+ // Clear the canvas.
+ layer.element.width = layer.element.width;
+
+ while (childNode) {
+ fNode = childNode.node;
+ (fNode.type !== "group") && fNode.render();
+ childNode = childNode.next;
+ }
+
+ }
+
+ };
+
+ com.insertBefore = function (node) {
+
+ };
+
+ com.insertAfter = function (node) {
+
+ };
+
+ com.removeNode = function (node) {
+
+ };
+
+ com.refreshNode = function (node) {
+
+ };
+
+ com.refreshAll = function () {
+
+ };
+ };
+
+
+
+ Point = function(x, y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ Point.prototype.angleTo = function(p) {
+ return Math.atan2(p.y - this.y, p.x - this.x);
+ }
+
+ Point.prototype.applyTransform = function(v) {
+ var xp = this.x * v[0] + this.y * v[2] + v[4];
+ var yp = this.x * v[1] + this.y * v[3] + v[5];
+ this.x = xp;
+ this.y = yp;
+ }
+
+ PathParser = new (function() {
+
+ this.tokens = null;
+
+ this.setTokens = function (d) {
+ if (typeof d === 'string') {
+ this.tokens = d.split(' ');
+ }
+ else {
+ this.tokens = d;
+ }
+ };
+
+ this.reset = function() {
+ this.i = -1;
+ this.command = '';
+ this.previousCommand = '';
+ this.start = new Point(0, 0);
+ this.control = new Point(0, 0);
+ this.current = new Point(0, 0);
+ this.points = [];
+ this.angles = [];
+ };
+
+ this.isEnd = function() {
+ return this.i >= this.tokens.length - 1;
+ }
+
+ this.isCommandOrEnd = function() {
+ if (this.isEnd()) {
+ return true;
+ }
+
+ return this.tokens[this.i + 1].toString().match(/^[A-Za-z]$/) != null;
+ }
+
+ this.isRelativeCommand = function() {
+ switch(this.command)
+ {
+ case 'm':
+ case 'l':
+ case 'h':
+ case 'v':
+ case 'c':
+ case 's':
+ case 'q':
+ case 't':
+ case 'a':
+ case 'z':
+ return true;
+ break;
+ }
+ return false;
+ }
+
+ this.getToken = function() {
+ this.i++;
+ return this.tokens[this.i];
+ }
+
+ this.getScalar = function() {
+ return parseFloat(this.getToken());
+ }
+
+ this.nextCommand = function() {
+ this.previousCommand = this.command;
+ this.command = this.getToken();
+ }
+
+ this.getPoint = function() {
+ var p = new Point(this.getScalar(), this.getScalar());
+ return this.makeAbsolute(p);
+ }
+
+ this.getAsControlPoint = function() {
+ var p = this.getPoint();
+ this.control = p;
+ return p;
+ }
+
+ this.getAsCurrentPoint = function() {
+ var p = this.getPoint();
+ this.current = p;
+ return p;
+ }
+
+ this.getReflectedControlPoint = function() {
+ if (this.previousCommand.toLowerCase() != 'c' &&
+ this.previousCommand.toLowerCase() != 's' &&
+ this.previousCommand.toLowerCase() != 'q' &&
+ this.previousCommand.toLowerCase() != 't' ){
+ return this.current;
+ }
+
+ // reflect point
+ var p = new Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y);
+ return p;
+ }
+
+ this.makeAbsolute = function(p) {
+ if (this.isRelativeCommand()) {
+ p.x += this.current.x;
+ p.y += this.current.y;
+ }
+ return p;
+ }
+
+ this.addMarker = function(p, from, priorTo) {
+ // if the last angle isn't filled in because we didn't have this point yet ...
+ if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) {
+ this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo);
+ }
+ this.addMarkerAngle(p, from == null ? null : from.angleTo(p));
+ }
+
+ this.addMarkerAngle = function(p, a) {
+ this.points.push(p);
+ this.angles.push(a);
+ }
+
+ this.getMarkerPoints = function() {
+ return this.points;
+ }
+
+ this.getMarkerAngles = function() {
+ for (var i=0; i maxR) {
+ attrs.r = maxR;
+ }
+
+ if (val < 0) {
+ attrs.r = 0;
+ }
+ break;
+
+ case "width":
+ case "height":
+ if (val < 0) {
+ attrs[attr] = 0;
+ };
+ break;
+
+ default:
+ continue;
+ }
+ }
+
+ return attrs;
+ },
+
+ setShapeBBox: function (m) {
+ var o = this,
+ el = o._rElement,
+ attrs = el.attrs,
+ sX = m.get(0),
+ sY = m.get(3),
+ tX = m.get(4),
+ tY = m.get(5),
+ strokeW = attrs['stroke-width'];
+
+ o._bbox = {
+ x: ((attrs.x * sX) + tX) - strokeW,
+ y: ((attrs.y * sY) + tY) - strokeW,
+ width: (attrs.width * sX) + (2 * strokeW),
+ height: (attrs.height * sY) + (2 * strokeW),
+ };
+
+ o._bbox.x2 = o._bbox.x + o._bbox.width;
+ o._bbox.y2 = o._bbox.y + o._bbox.height;
+
+ o.X = o._bbox.x;
+ o.Y = o._bbox.y;
+ o.W = o._bbox.width;
+ o.H = o._bbox.height;
+ }
+ });
+
+ var CircleFauxNode = function (parentObj) {
+ this.type = "circle";
+ this._isValid = false;
+
+ this.parent = this.owner = parentObj;
+ this.context = parentObj.getCurrentContext();
+ this.layer = parentObj.currentLayer;
+ },
+
+ PathFauxNode = function (parentObj) {
+ this.type = "path";
+ this._isValid = false;
+
+ this.parent = this.owner = parentObj;
+ this.context = parentObj.getCurrentContext();
+ this.layer = parentObj.currentLayer;
+ },
+
+ TextFauxNode = function (parentObj) {
+ this.type = "text";
+ this._isValid = false;
+
+ this.parent = this.owner = parentObj;
+ this.context = parentObj.getCurrentContext();
+ this.layer = parentObj.currentLayer;
+ },
+
+ GroupFauxNode = function (parent, width, height) {
+
+ this.type = "group";
+
+ this.nodeItems = new NodeList();
+ this.collectionItems = new NodeList();
+ this.layerItems = new NodeList();
+
+ this.owner = this.parent = parent;
+ this.layerOnTop = parent.currentLayer;
+
+ this.currentLayer = null;
+ this.baseLayer = null;
+
+ this.init();
+ };
+
+ CircleFauxNode.prototype = R.extend(new FauxNode(), {
+
+ constructor: CircleFauxNode,
+
+ paint: function () {
+ var o = this,
+ ctx = o.context,
+ attrs = o.validateAttrs(),
+ x = attrs.cx,
+ y = attrs.cy,
+ r = attrs.r,
+ /* @todo: provide support for rx, ry */
+ rx = r || attrs.rx,
+ ry = r || attrs.ry;
+
+ if (attrs.r) {
+
+ o.drawPath(["M", x + r, y, "A", rx, ry, 0, 1, 0, x - r, y, "A", rx, ry, 0, 1, 0, x + r, y, "Z"]);
+
+ if (attrs['stroke-width']) {
+ var strokeAlpha = attrs['stroke-opacity'] === undefined ? attrs['opacity'] : attrs['stroke-opacity'];
+ if (strokeAlpha !== undefined) {
+ ctx.globalAlpha = strokeAlpha;
+ }
+ ctx.stroke();
+ }
+ var fillAlpha = attrs['fill-opacity'] === undefined ? attrs['opacity'] : attrs['fill-opacity'];
+ if (fillAlpha !== undefined) {
+ ctx.globalAlpha = fillAlpha;
+ }
+ ctx.fill();
+ }
+
+ return;
+ },
+
+ setShapeBBox: function (m) {
+ var o = this,
+ el = o._rElement,
+ attrs = el.attrs,
+ sX = m.get(0),
+ sY = m.get(3),
+ tX = m.get(4),
+ tY = m.get(5),
+ strokeW = attrs['stroke-width'];
+
+ o._bbox = {
+ x: tX + ((attrs.cx - attrs.r) * sX) - strokeW,
+ y: tY + ((attrs.cy - attrs.r) * sY) - strokeW,
+ width: 2 * (strokeW + (attrs.r * sX)),
+ height: 2 * ((attrs.r * sY) + strokeW)
+ };
+
+ o._bbox.x2 = o._bbox.x + o._bbox.width;
+ o._bbox.y2 = o._bbox.y + o._bbox.height;
+
+ o.X = o._bbox.x;
+ o.Y = o._bbox.y;
+ o.W = o._bbox.width;
+ o.H = o._bbox.height;
+ }
+ });
+
+ PathFauxNode.prototype = R.extend(new FauxNode(), {
+
+ constructor: PathFauxNode,
+
+ paint: function () {
+ var o = this,
+ el = o._rElement,
+ attrs = el.attrs,
+ path = el.attr('path'),
+ m = el.matrix,
+ ctx = o.context;
+
+ // 1. Get the path from the path attribute
+ // 2. Accept paths in different array formats.
+ // 3. Optimize as this can potentially be a huge pain-point.
+ // 4. Draw path mapping M,L,H,V etc to canvas APIs
+ o.drawPath(path);
+ o._transformPath = R.transformPath(path, m.toTransformString());
+
+ var strokeAlpha = attrs['stroke-opacity'] === undefined ? attrs['opacity'] : attrs['stroke-opacity'];
+ if (strokeAlpha !== undefined) {
+ ctx.globalAlpha = strokeAlpha;
+ }
+ ctx.stroke();
+ var fillAlpha = attrs['fill-opacity'] === undefined ? attrs['opacity'] : attrs['fill-opacity'];
+ if (fillAlpha !== undefined) {
+ ctx.globalAlpha = fillAlpha;
+ }
+ ctx.fill();
+
+ return;
+ }
+ });
+
+ TextFauxNode.prototype = R.extend(new FauxNode(), {
+
+ constructor: TextFauxNode,
+
+ paint: function () {
+ var o = this,
+ el = o._rElement,
+ attrs = el.attr(),
+ text = attrs['text'],
+ stroke = attrs['stroke'],
+ valign = attrs['vertical-align'],
+ halign = attrs['text-anchor'],
+ x = attrs['x'],
+ y = attrs['y'],
+ m = el.matrix,
+ ctx = o.context,
+ path;
+
+ // apply the font styles, if any
+
+ // find the dimensions of the text using the given styles.
+ // All the dimensions should be present in the attrs user provided OR default.
+ var fontSize = attrs['font-size'] || 10,
+ lineHeight = attrs['line-height'] || toInt(fontSize, 10) * 1.2,
+ fontArr = ["normal", fontSize, attrs['font']];
+
+ // draw the text.
+ ctx.fillStyle = stroke;
+ ctx.font = fontArr.join(" ");
+
+ if (text) {
+ var texts = Str(text).split(/\n| /ig),
+ totalHeight = texts.length * lineHeight,
+ totalWidth = -Infinity,
+ startX = Infinity,
+ startY,
+ width,
+ textX,
+ textY;
+
+ if (valign === "top") {
+ startY = y + lineHeight;
+ }
+ else if (valign === "middle") {
+ startY = y - (totalHeight / 2) + (lineHeight / 2);
+ }
+ else { // valign is bottom.
+ startY = y - totalHeight + lineHeight;
+ }
+
+ for (var i = 0, ii = texts.length; i < ii; i += 1) {
+
+ text = texts[i];
+ textY = startY + (lineHeight * i);
+ width = ctx.measureText(text).width;
+
+ if (halign === "start") {
+ textX = x;
+ }
+ else if (halign === "middle") {
+ textX = x - (width / 2);
+ }
+ else {
+ textX = x - width;
+ }
+
+ totalWidth = mmax(totalWidth, width);
+ startX = mmin(startX, textX);
+
+ ctx.fillText(text, textX, textY);
+ }
+
+ el._textdirty = false;
+ }
+
+ o.outlinePath = [
+ "M",
+ startX,
+ startY - (lineHeight / 1.4),
+ "H",
+ startX + totalWidth,
+ "V",
+ startY - lineHeight + totalHeight,
+ "H",
+ startX,
+ "V",
+ startY - (lineHeight / 1.4)
+ ];
+
+ return;
+ }
+ });
+
+ GroupFauxNode.prototype = R.extend(R.extend(new FauxNode, NodeCollection.prototype), {
+
+ constructor: GroupFauxNode,
+
+ draw: function () {
+
+ // Clear the group canvas first.
+ this.layerItems.each(function () {
+ this.element.width = this.element.width;
+ });
+
+ FauxNode.prototype.draw.apply(this, arguments);
+ },
+
+ /**
+ * This method does the complete rendering of the element, including
+ * (re)setting the bbox and image map.
+ *
+ * @returns {_L10.FauxNode.prototype}
+ */
+ render: function () {
+
+ var o = this;
+
+ o.draw();
+ o.setBBox();
+
+ return o;
+ },
+
+ paint: function () {
+ var o = this,
+ list = o.nodeList,
+ el = o._rElement,
+ canvas = o.canvas,
+ attrs = el.attrs,
+ childNode = list.bottom;
+
+ /* @todo: Clean this up */
+ if (attrs.opacity !== undefined) {
+ this.layerItems.each(function () {
+ this.getContext().globalAlpha = attrs.opacity;
+ });
+ }
+
+ while (childNode) {
+ childNode.render();
+ childNode = childNode.next;
+ }
+ },
+
+ setBBox: function () {
+
+ },
+
+ addMouseInteractivity: function () {
+ },
+
+ applyTransform: function (m) {
+ var o = this,
+ parent = o.parent,
+ parentMatrix = parent.getTransformMatrix && parent.getTransformMatrix();
+
+ // Parent is a group element with a transformation applied to it.
+ if (parentMatrix) {
+ o.matrixApplied = parentMatrix.clone();
+ o.matrixApplied.add(m.a, m.b, m.c, m.d, m.e, m.f);
+ }
+ else {
+ o.matrixApplied = m;
+ }
+
+ this.layerItems.each(function () {
+ FauxNode.prototype.applyTransform.apply(this, [o.matrixApplied]);
+ })
+ },
+
+ getTransformMatrix: function () {
+ return this.matrixApplied;
+ }
+ });
+
+ Element = function (node, paper, group) {
+ var o = this,
+ parent = group || paper;
+
+ o.node = o[0] = node;
+ node.raphael = true;
+ node.raphaelid = o.id = R._oid++;
+ node._rElement = o;
+
+ o.X = 0;
+ o.Y = 0;
+
+ o.attrs = o.attrs || {};
+ o.styles = o.styles || {};
+ o.followers = o.followers || [];
+
+ o.paper = paper;
+ o.com = parent.com;
+
+ o.ca = o.customAttributes = o.customAttributes ||
+ new paper._CustomAttributes();
+
+ o.matrix = R.matrix();
+ o._ = {
+ transform: [],
+ sx: 1,
+ sy: 1,
+ dx: 0,
+ dy: 0,
+ deg: 0
+ };
+
+ o.parent = parent;
+ !parent.bottom && (parent.bottom = o);
+
+ o.prev = parent.top || null;
+ parent.top && (parent.top.next = o);
+ parent.top = o;
+ o.next = null;
+ };
+
+ Element.prototype = elproto;
+ elproto.constructor = Element;
+
+ var
+ repaint = function (el, finalAttrs, positionChanged, dimensionChanged) {
+
+ var node = getNode(el),
+ preC = R._getConnectedNodes(node),
+ attrs = el.attrs,
+ elAbove = preC.above,
+ elBelow = preC.below,
+ len,
+ attr,
+ i;
+
+ for (attr in finalAttrs) {
+ attrs[attr] = finalAttrs[attr];
+ }
+
+ node.redraw();
+ },
+
+ setFillAndStroke = function (el, params) {
+
+ var attrs = el.attrs,
+ node = el.node,
+ finalAttrs = {},
+ att,
+ val,
+ needsRepaint = false,
+ positionChanged = false,
+ dimensionChanged = false,
+ i;
+
+ for (att in params) {
+ if (params[has](att)) {
+ if (!R._availableAttrs[has](att)) {
+ continue;
+ }
+ val = params[att];
+
+ switch (att) {
+
+ case 'fill-opacity':
+ case 'opacity':
+ case 'stroke-opcaity':
+ case 'stroke':
+ case 'fill':
+ finalAttrs[att] = val;
+ needsRepaint = true;
+ break;
+
+ case 'stroke-width':
+ case "cx":
+ case "cy":
+ case "x":
+ case "y":
+ finalAttrs[att] = val;
+ positionChanged = true;
+ break;
+
+ case "width":
+ case "height":
+ finalAttrs[att] = val;
+ dimensionChanged = true;
+ break;
+
+ case "clip-rect":
+ finalAttrs[att] = val;
+ needsRepaint = true;
+ break;
+
+ case "font-size":
+ case "font":
+ case "vertical-align":
+ case "text-anchor":
+ finalAttrs[att] = val;
+ needsRepaint = true;
+
+ default:
+ continue;
+ }
+ }
+ }
+
+ tuneText(el, params, finalAttrs);
+
+ finalAttrs = node.validateAttrs(finalAttrs);
+
+ if (needsRepaint || positionChanged || dimensionChanged) {
+ repaint(el, finalAttrs, positionChanged, dimensionChanged);
+ }
+ },
+
+ leading = 1.2,
+
+ tuneText = function(el, params, finalAttrs) {
+ if (el.type != "text" || !(params[has]("text") || params[has]("font") ||
+ params[has]("font-size") || params[has]("x") || params[has]("y") ||
+ params[has]("line-height") || params[has]("vertical-align"))) {
+ return;
+ }
+
+ var a = el.attr(),
+ fontSize = params['font-size'] || a['font-size'] || 10,
+ lineHeight = toFloat(params['line-height'] || a['line-height']) || toInt(fontSize, 10) * leading,
+ valign = params["vertical-align"] || a["vertical-align"] || "middle";
+
+ if (isNaN(lineHeight)) {
+ lineHeight = fontSize * leading;
+ }
+
+ finalAttrs['font-size'] = toInt(fontSize, 10) + "px";
+ finalAttrs['font'] = params['font'] || a['font'] || 'Verdana';
+ finalAttrs['vertical-align'] = valign;
+ finalAttrs['x'] = params['x'] || a['x'] || 0;
+ finalAttrs['y'] = params['y'] || a['y'] || 0;
+ finalAttrs['line-height'] = toInt(lineHeight, 10);
+ finalAttrs['text-anchor'] = params['text-anchor'] || a['text-anchor'] || 'middle';
+ };
+
+ R._engine.initWin = function (win) {
+ win = win;
+ doc = win.document;
+ };
+
+ R._engine.setSize = function (w, h) {
+ var paper = this,
+ cs = paper.canvas.style;
+
+ cs.width = (paper.width = (+w || paper.width)) + PX;
+ cs.height = (paper.height = (+h || paper.height)) + PX;
+ /* @todo call setViewBox from setSize() */
+ return paper;
+ };
+ /* @todo implement setViewBox() */
+ R._engine.create = function () {
+ var con = R._getContainer.apply(0, arguments) || {},
+ container = con.container,
+ x = con.x,
+ y = con.y,
+ width = con.width,
+ height = con.height,
+ //handler = R._containerEventHandler,
+ wrapper,
+ cssText,
+ image,
+ mmap,
+ i,
+ paper,
+ canvas;
+
+ if (!container) {
+ throw new Error("Canvas container not found.");
+ }
+
+ paper = new R._Paper();
+ paper.canvas = wrapper = $("div");
+
+ x = (x || 0);
+ y = (y || 0);
+ paper.width = width = (width || 512);
+ paper.height = height = (height || 342);
+ paper.left = paper.top = 0;
+
+ if (container == 1) {
+ wrapper.style.cssText = cssText +
+ R.format(";width:100%;height:100%;position:absolute;left:{0}px;top:{1}px;", [x, y]);
+ doc.body.appendChild(wrapper);
+ }
+ else {
+ wrapper.style.cssText = cssText + ";width:100%;height:100%;position:absolute";
+ if (container.firstChild) {
+ container.insertBefore(wrapper, container.firstChild);
+ }
+ else {
+ container.appendChild(wrapper);
+ }
+ }
+
+ cssText = "overflow:hidden;-webkit-tap-highlight-color:rgba(0,0,0,0);" +
+ "-webkit-user-select:none;-moz-user-select:-moz-none;" +
+ "-khtml-user-select:none;-ms-user-select:none;user-select:none;" +
+ "-o-user-select:none;cursor:default;" +
+ R.format("width:{0}px;height:{1}px;", [width, height]);
+
+ // Create the canvas element and set it to occupy full space. Retain a
+ // reference to its context.
+ canvas = $("canvas");
+ canvas.style.cssText = "position:absolute;left:0;top:0";
+ canvas.setAttribute('width', paper.width);
+ canvas.setAttribute('height', paper.height);
+
+ paper.com = new CanvasObjectModel(canvas, wrapper, paper.width, paper.height);
+
+ wrapper.appendChild(canvas);
+
+ image = $("img");
+
+ // Easter egg idea! :)
+ image.src = "image1.png";
+
+ image.style.cssText = "opacity: 0;z-index: 100;background: transparent;position: absolute;left: 0;top: 0;width: "+width+"px;height: "+height+"px";
+ wrapper.appendChild(image);
+
+ mmap = $("map");
+
+ mmap.setAttribute("name", "mousemap");
+ mmap.setAttribute("id", "mousemap"); // Needed for FF.
+
+ wrapper.appendChild(mmap);
+
+ image.setAttribute("usemap","#mousemap");
+ wrapper._image = image;
+ wrapper._map = mmap;
+
+ return paper;
+ };
+
+ var getNode = R._engine.getNode = function (el) {
+ return el.node || el[0].node;
+ };
+
+ R._engine.getLastNode = function (el) {
+ return el.node || el[el.length - 1].node;
+ };
+
+ R._engine.rect = function(paper, x, y, w, h, r, group) {
+
+ var node = paper.com.createNode('rect', group && group.node),
+ el = new Element(node, paper, group),
+ attrs = el.attrs;
+
+ attrs.x = x;
+ attrs.y = y;
+ attrs.width = w;
+ attrs.height = h;
+ attrs.fill = "#fff";
+ attrs.stroke = "#000";
+ attrs['stroke-width'] = 1;
+ attrs.r = r || 0;
+ attrs.rx = r || 0;
+ attrs.ry = r || 0;
+
+ el.type = "rect";
+
+ node.render();
+ return el;
+ };
+
+ R._engine.circle = function(paper, x, y, r, group) {
+ var node = paper.com.createNode('circle', group && group.node),
+ el = new Element(node, paper, group),
+ attrs = el.attrs;
+
+ attrs.cx = x;
+ attrs.cy = y;
+ attrs.r = r;
+ attrs.fill = 'none';
+ attrs.stroke = '#000';
+ attrs['stroke-width'] = 1;
+
+ el.type = "circle";
+
+ node.render();
+ return el;
+ };
+
+ R._engine.ellipse = function(paper, x, y, rx, ry, group) {
+ var node = new FauxNode(),
+ el = new Element(node, paper, group);
+
+ el.type = "ellipse";
+ return el;
+ };
+
+ R._engine.image = function(paper, src, x, y, w, h, group) {
+ var node = new FauxNode(),
+ el = new Element(node, paper, group);
+
+ el.type = "image";
+ return el;
+ };
+
+ R._engine.text = function(paper, x, y, text, group) {
+ var node = paper.com.createNode('text', group && group.node),
+ el = new Element(node, paper, group),
+ attrs = el.attrs;
+
+ attrs.x = x;
+ attrs.y = y;
+ attrs.text = text;
+ attrs.fill = 'none';
+ attrs.stroke = '#000';
+ attrs.font = 'Verdana';
+ attrs['font-size'] = '12px';
+ attrs['vertical-align'] = 'middle';
+ attrs['text-anchor'] = 'middle'
+
+ el.type = "text";
+ node.render();
+ return el;
+ };
+
+ R._engine.path = function(pathString, paper, group) {
+ var node = paper.com.createNode('path', group && group.node),
+ el = new Element(node, paper, group),
+ attrs = el.attrs;
+
+ attrs.path = pathString;
+ attrs.fill = "#fff";
+ attrs.stroke = "#000";
+ attrs['stroke-width'] = 1;
+
+ el.type = "path";
+
+ node.render();
+
+ return el;
+ };
+
+ R._engine.group = function (paper, id, group) {
+
+ var node = paper.com.createNode('group', group && group.node),
+ el = new Element(node, paper, group),
+ wrapper = node.wrapper;
+
+ id && wrapper.setAttribute('class', ['red', id].join('-'));
+
+ el.canvas = wrapper;
+
+ //(group && group.canvas.appendChild(wrapper)) || paper.canvas.appendChild(wrapper);
+
+ el.type = "group";
+ return el;
+ };
+
+ elproto._getBBox = function() {
+ if (this.removed) {
+ return {};
+ }
+
+ return {
+ x: this.X + (this.bbx || 0) - this.W / 2,
+ y: this.Y + (this.bby || 0) - this.H / 2,
+ width: this.W,
+ height: this.H
+ };
+ };
+
+ /***** ELEMENT REORDERING / RESTRUCTING *****/
+
+ elproto.toFront = function() {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = o.node,
+ parent = o.parent,
+ parentNode = thisNode.owner,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (R._tofront(o, parent)) {
+ if (elproto.type === "group") {
+ parent.canvas.appendChild(thisNode);
+ }
+ else {
+ parentNode.nodeList.tofront(thisNode);
+ }
+ }
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk && follower.el[follower.stalk](o);
+ }
+
+ return o;
+ };
+
+ elproto.toBack = function() {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = o.node,
+ parent = o.parent,
+ parentNode = thisNode.owner,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (R._toback(o, parent)) {
+ if (elproto.type === "group") {
+ parent.canvas.appendChild(thisNode);
+ }
+ else {
+ parentNode.nodeList.toback(thisNode);
+ }
+ }
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk && follower.el[follower.stalk](o);
+ }
+
+
+ return o;
+ };
+
+ elproto.insertAfter = function(element) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = o.node,
+ thatNode = element.node,
+ parentNode = thatNode.owner,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (thatNode.next) {
+ parentNode.nodeList.insertBefore(thisNode, thatNode.next);
+ }
+ else {
+ parentNode.appendChild(thisNode);
+ }
+
+ R._insertafter(o, element, o.parent, element.parent);
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+
+ return o;
+ };
+
+ elproto.insertBefore = function(element) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = o.node,
+ thatNode = element.node,
+ parentNode = thatNode.owner,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (thatNode) {
+ parentNode.nodeList.insertBefore(thisNode, thatNode);
+ }
+ else {
+ parentNode.appendChild(thisNode);
+ }
+
+ R._insertafter(o, element, o.parent, element.parent);
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+
+ return o;
+ };
+
+ elproto.appendChild = function(element) {
+ return this;
+ };
+
+ elproto.removeChild = function(element) {
+ return this;
+ };
+
+ /***** ELEMENT REORDERING / RESTRUCTING *****/
+
+
+
+ elproto.attr = function(name, value) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+
+ attrs = o.attrs,
+ ca = o.ca,
+ names,
+ params,
+ par,
+
+ res,
+ key,
+ out,
+
+ subkey,
+ delkeys,
+
+ follower,
+ ii,
+ i;
+
+ // fetch a copy of all attributes
+ if (name == null) {
+ res = {};
+ for (key in attrs) if (attrs.hasOwnProperty(key)) {
+ res[key] = attrs[key];
+ }
+ res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
+ res.transform = o._.transform;
+ /* @todo res.visibility = o.node.style.display === "none" ? "hidden" : "visible"; */
+ return res;
+ }
+
+ // fetch a single value
+ if (value == null && R.is(name, "string")) {
+ if (name == "fill" && attrs.fill == "none" && attrs.gradient) {
+ return attrs.gradient;
+ }
+ if (name == "transform") {
+ return o._.transform;
+ }
+ /* @todo if (name == "visibility") {
+ return this.node.style.display === "none" ? "hidden" : "visible";
+ }*/
+
+ names = name.split(separator),
+ out = {};
+
+ for (i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in attrs) {
+ out[name] = attrs[name];
+ }
+ else if (R.is(ca[name], "function")) {
+ out[name] = ca[name].def;
+ } else {
+ out[name] = R._availableAttrs[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+
+ // fetch specific attributes
+ if (value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = o.attr(name[i]);
+ }
+ return out;
+ }
+
+ // prepare setter params
+ if (value != null) {
+ params = {};
+ params[name] = value;
+ }
+ else if (name != null && R.is(name, "object")) {
+ params = name;
+ }
+
+ for (key in params) {
+ eve("raphael.attr." + key + "." + o.id, o, params[key], key);
+ }
+
+ delkeys = {};
+ for (key in ca) {
+
+ if (ca[key] && params.hasOwnProperty(key) &&
+ R.is(ca[key], "function") && !ca['_invoked' + key]) {
+
+ ca['_invoked'+key] = true; // prevent recursion
+ par = ca[key].apply(o, [].concat(params[key]));
+ delete ca['_invoked'+key];
+
+ for (subkey in par) {
+ if (par.hasOwnProperty(subkey)) {
+ params[subkey] = par[subkey];
+ }
+ }
+ attrs[key] = params[key];
+ if (par === false) {
+ delkeys[key] = params[key];
+ delete params[key];
+ }
+ }
+ }
+
+ setFillAndStroke(this, params);
+
+ for (i = 0, ii = o.followers.length; i < ii; i++) {
+ follower = o.followers[i];
+ (follower.cb && !follower.cb.call(follower.el, params, o)) ||
+ follower.el.attr(params);
+ }
+
+ for (subkey in delkeys) {
+ params[subkey] = delkeys[subkey];
+ }
+ return this;
+ };
+
+ elproto.css = function (name, value) {
+ return this;
+ };
+
+
+
+
+ /**************** Drag *********************/
+ elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
+
+ function start(e) {
+ (e.originalEvent || e).preventDefault();
+ var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
+ this._drag.x = e.clientX + scrollX;
+ this._drag.y = e.clientY + scrollY;
+ this._drag.id = e.identifier;
+ !drag.length && R.mousemove(dragMove).mouseup(dragUp);
+ drag.push({
+ el: this,
+ move_scope: move_scope,
+ start_scope: start_scope,
+ end_scope: end_scope
+ });
+ onstart && eve.on("raphael.drag.start." + this.id, onstart);
+ onmove && eve.on("raphael.drag.move." + this.id, onmove);
+ onend && eve.on("raphael.drag.end." + this.id, onend);
+ eve("raphael.drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
+ }
+ this._drag = {};
+ draggable.push({
+ el: this,
+ start: start
+ });
+ this.mousedown(start);
+ return this;
+ }
+
+ elproto.undrag = function() {
+ var i = draggable.length;
+ while (i--)
+ if (draggable[i].el == this) {
+ this.unmousedown(draggable[i].start);
+ draggable.splice(i, 1);
+ eve.unbind("raphael.drag.*." + this.id);
+ }
+ !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp);
+ };
+
+
+ /***************** Drag *****************/
+ /************ TRANSFORMATIONS *************/
+
+
+
+ elproto.rotate = function(deg, cx, cy) {
+
+ var o = this,
+ bbox;
+ if (o.removed) {
+ return o;
+ }
+ deg = Str(deg).split(separator);
+ if (deg.length - 1) {
+ cx = toFloat(deg[1]);
+ cy = toFloat(deg[2]);
+ }
+ deg = toFloat(deg[0]);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ bbox = o.getBBox(1);
+ cx = bbox.x + bbox.width / 2;
+ cy = bbox.y + bbox.height / 2;
+ }
+ o.transform(o._.transform.concat([["r", deg, cx, cy]]));
+ return o;
+ };
+
+ elproto.scale = function(sx, sy, cx, cy) {
+ var o = this,
+ bbox;
+ if (o.removed) {
+ return o;
+ }
+ sx = Str(sx).split(separator);
+ if (sx.length - 1) {
+ sy = toFloat(sx[1]);
+ cx = toFloat(sx[2]);
+ cy = toFloat(sx[3]);
+ }
+ sx = toFloat(sx[0]);
+ (sy == null) && (sy = sx);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ bbox = o.getBBox(1);
+ }
+ cx = cx == null ? bbox.x + bbox.width / 2 : cx;
+ cy = cy == null ? bbox.y + bbox.height / 2 : cy;
+ o.transform(o._.transform.concat([["s", sx, sy, cx, cy]]));
+
+ return o;
+ };
+
+ elproto.translate = function(dx, dy) {
+ var o = this;
+ if (o.removed) {
+ return o;
+ }
+ dx = Str(dx).split(separator);
+ if (dx.length - 1) {
+ dy = toFloat(dx[1]);
+ }
+ dx = toFloat(dx[0]) || 0;
+ dy = +dy || 0;
+ o.transform(o._.transform.concat([["t", dx, dy]]));
+
+ return o;
+ };
+
+ elproto.transform = function(tstr) {
+
+ var o = this,
+ _ = o._,
+ sw;
+
+ if (tstr === null) {
+ return _.transform;
+ }
+
+ R._extractTransform(o, tstr);
+
+ /* @todo: what changes to be made here in the context of canvas */
+ /*o.clip && !_.clipispath && $(o.clip, {
+ transform: o.matrix.invert()
+ });
+ o.pattern && updatePosition(o); */
+ if (_.sx != 1 || _.sy != 1) {
+ sw = o.attrs[has]("stroke-width") ? o.attrs["stroke-width"] : 1;
+ o.attr({
+ "stroke-width": sw
+ });
+ }
+
+ o.node && o.node.redraw();
+
+ return o;
+ };
+
+ /************ TRANSFORMATIONS *************/
+
+
+ elproto.hide = function() {
+ return this;
+ };
+
+ elproto.show = function() {
+ return this;
+ };
+
+ elproto.blur = function(size) {
+ return this;
+ };
+
+ elproto.on = function(eventType, handler) {
+ var el = this,
+ listeners = el.listeners;
+
+ if (!listeners) {
+ listeners = el.listeners = {};
+ }
+
+ if (!listeners[eventType]) {
+ listeners[eventType] = [];
+ }
+
+ listeners[eventType].push(handler);
+ };
+
+ elproto.remove = function() {
+ return this;
+ };
+
+
+
+
+ paperproto.clear = function () {
+ eve("raphael.clear", this);
+ return this;
+ };
+
+ paperproto.remove = function () {
+ if (this.removed) {
+ return;
+ }
+
+ var paper = this,
+ canvas = paper.canvas,
+ pn = canvas.parentNode,
+ i;
+
+ eve("raphael.remove", paper);
+ pn.removeChild(canvas);
+
+ for (i in paper) {
+ paper[i] = typeof paper[i] == "function" ? R._removedFactory(i) : null;
+ }
+
+ this.removed = true;
+ };
+
+ R.toString = function () {
+ return "Your browser supports canvas.\nYou are running RedRaphael " +
+ R.version;
+ };
+
+ for (var method in elproto) {
+ if (elproto.hasOwnProperty(method) &&
+ !setproto.hasOwnProperty(method)) {
+ setproto[method] = (function (methodname) {
+ return function () {
+ var arg = arguments;
+ return this.forEach(function (el) {
+ el[methodname].apply(el, arg);
+ });
+ };
+ })(method);
+ }
+ };
+
+}(window.Raphael);
diff --git a/source/raphael.core.js b/source/raphael.core.js
new file mode 100644
index 0000000..70edfa2
--- /dev/null
+++ b/source/raphael.core.js
@@ -0,0 +1,6328 @@
+/**!
+ * RedRaphael 1.0.0 - JavaScript Vector Library
+ * Copyright (c) 2012-2013 FusionCharts Technologies
+ *
+ * Raphael 2.1.0
+ * Copyright (c) 2008-2012 Dmitry Baranovskiy
+ * Copyright © 2008-2012 Sencha Labs
+ *
+ * Licensed under the MIT license.
+ */
+(function (glob, factory) {
+ // AMD support
+ if (typeof define === "function" && define.amd) {
+ // Define as an anonymous module
+ define(["eve"], function( eve ) {
+ return factory(glob, eve);
+ });
+ } else {
+ // Browser globals (glob is window)
+ // Raphael adds itself to window
+ factory(glob, glob.eve);
+ }
+}(this, function (window, eve) {
+ /*\
+ * Raphael
+ [ method ]
+ **
+ * Creates a canvas object on which to draw.
+ * You must do this first, as all future calls to drawing methods
+ * from this instance will be bound to this canvas.
+ > Parameters
+ **
+ - container (HTMLElement|string) DOM element or its ID which is going to be a parent for drawing surface
+ - width (number)
+ - height (number)
+ - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+ * or
+ - x (number)
+ - y (number)
+ - width (number)
+ - height (number)
+ - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+ * or
+ - all (array) (first 3 or 4 elements in the array are equal to [containerID, width, height] or [x, y, width, height]. The rest are element descriptions in format {type: type, }). See @Paper.add.
+ - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+ * or
+ - onReadyCallback (function) function that is going to be called on DOM ready event. You can also subscribe to this event via Eve’s “DOMLoad” event. In this case method returns `undefined`.
+ = (object) @Paper
+ > Usage
+ | // Each of the following examples create a canvas
+ | // that is 320px wide by 200px high.
+ | // Canvas is created at the viewport’s 10,50 coordinate.
+ | var paper = Raphael(10, 50, 320, 200);
+ | // Canvas is created at the top left corner of the #notepad element
+ | // (or its top right corner in dir="rtl" elements)
+ | var paper = Raphael(document.getElementById("notepad"), 320, 200);
+ | // Same as above
+ | var paper = Raphael("notepad", 320, 200);
+ | // Image dump
+ | var set = Raphael(["notepad", 320, 200, {
+ | type: "rect",
+ | x: 10,
+ | y: 10,
+ | width: 25,
+ | height: 25,
+ | stroke: "#f00"
+ | }, {
+ | type: "text",
+ | x: 30,
+ | y: 40,
+ | text: "Dump"
+ | }]);
+ \*/
+ function R(first) {
+ var args,
+ f;
+
+
+ if (R._url) { // reinitialize URL to be safe from popstate event
+ R._url = (R._g && R._g.win || window).location.href.replace(/#.*?$/, "");
+ }
+ if (R.is(first, "function")) {
+ return loaded ? first() : eve.on("raphael.DOMload", first);
+ }
+ else if (R.is(first, array)) {
+ return R._engine.create[apply](R, first.splice(0, 3 + R.is(first[0], nu))).add(first);
+ }
+ else {
+ args = Array.prototype.slice.call(arguments, 0);
+ if (R.is(args[args.length - 1], "function")) {
+ f = args.pop();
+ return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("raphael.DOMload", function() {
+ f.call(R._engine.create[apply](R, args));
+ });
+ } else {
+ return R._engine.create[apply](R, arguments);
+ }
+ }
+ }
+
+ R.upgrade = "1.0.0";
+ R.version = "2.1.0";
+ R.eve = eve;
+
+ var loaded,
+
+ undef,
+ E = "",
+ S = " ",
+ proto = "prototype",
+ has = "hasOwnProperty",
+ appendChild = "appendChild",
+ apply = "apply",
+ concat = "concat",
+ nu = "number",
+ string = "string",
+ array = "array",
+ object = "object",
+ finite = "finite",
+ toString = "toString",
+ fillString = "fill",
+ push = "push",
+ setAttribute = "setAttribute",
+ split = "split",
+ none = "none",
+ OBJECTSTRING = "object",
+ arrayToStr = "[object Array]",
+ objectToStr = "[object Object]",
+ arraySlice = Array.prototype.slice,
+ arraySplice = Array.prototype.splice,
+ g = {
+ doc: document,
+ win: window
+ },
+ oldRaphael = {
+ was: Object.prototype[has].call(g.win, "Raphael"),
+ is: g.win.Raphael
+ },
+ doc = g.doc,
+ win = g.win,
+
+ supportsTouch = R.supportsTouch = "createTouch" in doc,
+
+ CustomAttributes = function () {
+ /*\
+ * Raphael.ca
+ [ property (object) ]
+ **
+ * Shortcut for @Raphael.customAttributes
+ \*/
+ /*\
+ * Raphael.customAttributes
+ [ property (object) ]
+ **
+ * If you have a set of attributes that you would like to represent
+ * as a function of some number across all papers you can do it
+ * easily with custom attributes:
+ > Usage
+ | Raphael.customAttributes.hue = function (num) {
+ | num = num % 1;
+ | return {fill: "hsb(" + num + ", 0.75, 1)"};
+ | };
+ | // Custom attribute “hue” will change fill
+ | // to be given hue with fixed saturation and brightness.
+ | // Now you can use it like this:
+ | var c = paper.circle(10, 10, 10).attr({hue: .45});
+ | // or even like this:
+ | c.animate({hue: 1}, 1e3);
+ |
+ | // You could also create custom attribute
+ | // with multiple parameters:
+ | Raphael.customAttributes.hsb = function (h, s, b) {
+ | return {fill: "hsb(" + [h, s, b].join(",") + ")"};
+ | };
+ | c.attr({hsb: "0.5 .8 1"});
+ | c.animate({hsb: [1, 0, 0.5]}, 1e3);
+ \*/
+ },
+ caproto = R.ca = R.customAttributes = CustomAttributes.prototype,
+
+ Paper = function () {
+ /*\
+ * Paper.ca
+ [ property (object) ]
+ **
+ * Shortcut for @Paper.customAttributes
+ \*/
+ /*\
+ * Paper.customAttributes
+ [ property (object) ]
+ **
+ * If you have a set of attributes that you would like to represent
+ * as a function of some number you can do it easily with custom attributes:
+ > Usage
+ | paper.customAttributes.hue = function (num) {
+ | num = num % 1;
+ | return {fill: "hsb(" + num + ", 0.75, 1)"};
+ | };
+ | // Custom attribute “hue” will change fill
+ | // to be given hue with fixed saturation and brightness.
+ | // Now you can use it like this:
+ | var c = paper.circle(10, 10, 10).attr({hue: .45});
+ | // or even like this:
+ | c.animate({hue: 1}, 1e3);
+ |
+ | // You could also create custom attribute
+ | // with multiple parameters:
+ | paper.customAttributes.hsb = function (h, s, b) {
+ | return {fill: "hsb(" + [h, s, b].join(",") + ")"};
+ | };
+ | c.attr({hsb: "0.5 .8 1"});
+ | c.animate({hsb: [1, 0, 0.5]}, 1e3);
+ \*/
+ this.ca = this.customAttributes = new CustomAttributes();
+ this._CustomAttributes = function () {};
+ this._CustomAttributes.prototype = this.ca;
+ },
+
+ /*\
+ * Raphael.fn
+ [ property (object) ]
+ **
+ * You can add your own method to the canvas. For example if you want to draw a pie chart,
+ * you can create your own pie chart function and ship it as a Raphaël plugin. To do this
+ * you need to extend the `Raphael.fn` object. You should modify the `fn` object before a
+ * Raphaël instance is created, otherwise it will take no effect. Please note that the
+ * ability for namespaced plugins was removed in Raphael 2.0. It is up to the plugin to
+ * ensure any namespacing ensures proper context.
+ > Usage
+ | Raphael.fn.arrow = function (x1, y1, x2, y2, size) {
+ | return this.path( ... );
+ | };
+ | // or create namespace
+ | Raphael.fn.mystuff = {
+ | arrow: function () {…},
+ | star: function () {…},
+ | // etc…
+ | };
+ | var paper = Raphael(10, 10, 630, 480);
+ | // then use it
+ | paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"});
+ | paper.mystuff.arrow();
+ | paper.mystuff.star();
+ \*/
+ paperproto = R.fn = Paper.prototype = R.prototype,
+
+ elements = {
+ circle: 1,
+ rect: 1,
+ path: 1,
+ ellipse: 1,
+ text: 1,
+ image: 1,
+ group: 1
+ },
+ events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S),
+ touchMap = R._touchMap = {
+ mousedown: "touchstart",
+ mousemove: "touchmove",
+ mouseup: "touchend"
+ },
+
+ Str = win.String,
+ toFloat = win.parseFloat,
+ toInt = win.parseInt,
+ math = win.Math,
+ mmax = math.max,
+ mmin = math.min,
+ abs = math.abs,
+ pow = math.pow,
+ mathCos = math.cos,
+ mathSin = math.sin,
+ mathSqrt = math.sqrt,
+ round = math.round,
+ PI = math.PI,
+ deg2rad = PI / 180,
+ rad2deg = 180 / PI,
+
+ lowerCase = Str.prototype.toLowerCase,
+ upperCase = Str.prototype.toUpperCase,
+ objectToString = win.Object.prototype.toString,
+ paper = {},
+
+ separator = /[, ]+/,
+ formatrg = /\{(\d+)\}/g,
+ ISURL = R._ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i,
+ colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i,
+ bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
+ whitespace = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]/g,
+ commaSpaces = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/,
+ p2s = /,?([achlmqrstvxz]),?/gi,
+ pathCommand = /([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig,
+ tCommand = /([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig,
+ pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig,
+ radial_gradient = R._radial_gradient = /^x?r(?:\(([^\)]*?)\))?/,
+
+ isnan = {
+ "NaN": 1,
+ "Infinity": 1,
+ "-Infinity": 1
+ },
+ hsrg = {
+ hs: 1,
+ rg: 1
+ },
+ availableAttrs = R._availableAttrs = {
+ "arrow-end": none,
+ "arrow-start": none,
+ blur: 0,
+ "clip-rect": "0 0 1e9 1e9",
+ "clip-path": E,
+ cursor: "default",
+ cx: 0,
+ cy: 0,
+ fill: "#fff",
+ "fill-opacity": 1,
+ font: '10px "Arial"',
+ "font-family": '"Arial"',
+ "font-size": "10",
+ "font-style": "normal",
+ "font-weight": 400,
+ gradient: 0,
+ height: 0,
+ href: "about:blank",
+ "letter-spacing": 0,
+ "line-height": 12,
+ "vertical-align": "middle",
+ opacity: 1,
+ path: "M0,0",
+ r: 0,
+ rx: 0,
+ ry: 0,
+ src: E,
+ stroke: "#000",
+ "stroke-dasharray": E,
+ "stroke-linecap": "butt",
+ "stroke-linejoin": "butt",
+ "stroke-miterlimit": 0,
+ "stroke-opacity": 1,
+ "stroke-width": 1,
+ target: "_blank",
+ "text-anchor": "middle",
+ "visibility": E,
+ title: E,
+ transform: E,
+ rotation: 0,
+ width: 0,
+ x: 0,
+ y: 0
+ },
+ availableAnimAttrs = R._availableAnimAttrs = {
+ blur: nu,
+ "clip-rect": "csv",
+ "clip-path": "path",
+ cx: nu,
+ cy: nu,
+ fill: "colour",
+ "fill-opacity": nu,
+ "font-size": nu,
+ height: nu,
+ opacity: nu,
+ path: "path",
+ r: nu,
+ rx: nu,
+ ry: nu,
+ stroke: "colour",
+ "stroke-opacity": nu,
+ "stroke-width": nu,
+ transform: "transform",
+ width: nu,
+ x: nu,
+ y: nu
+ },
+ eldata = {},
+
+ sortByKey = function(a, b) {
+ return a.key - b.key;
+ },
+ sortByNumber = function(a, b) {
+ return toFloat(a) - toFloat(b);
+ },
+ fun = function() {
+ },
+ pipe = function(x) {
+ return x;
+ },
+
+ rectPath = R._rectPath = function(x, y, w, h, r) {
+ if (r) {
+ return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]];
+ }
+ return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]];
+ },
+
+ ellipsePath = function(x, y, rx, ry) {
+ if (ry == null) {
+ ry = rx;
+ }
+ return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]];
+ },
+
+ getPath = R._getPath = {
+ group: function() {
+ return false;
+ },
+ path: function(el) {
+ return el.attr("path");
+ },
+ circle: function(el) {
+ var a = el.attrs;
+ return ellipsePath(a.cx, a.cy, a.r);
+ },
+ ellipse: function(el) {
+ var a = el.attrs;
+ return ellipsePath(a.cx, a.cy, a.rx, a.ry);
+ },
+ rect: function(el) {
+ var a = el.attrs;
+ return rectPath(a.x, a.y, a.width, a.height, a.r);
+ },
+ image: function(el) {
+ var a = el.attrs;
+ return rectPath(a.x, a.y, a.width, a.height);
+ },
+ text: function(el) {
+ var bbox = el._getBBox();
+ return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
+ }
+ },
+
+ /*\
+ * Raphael.mapPath
+ [ method ]
+ **
+ * Transform the path string with given matrix.
+ > Parameters
+ - path (string) path string
+ - matrix (object) see @Matrix
+ = (string) transformed path string
+ \*/
+ mapPath = R.mapPath = function(path, matrix) {
+ if (!matrix) {
+ return path;
+ }
+ var x,
+ y,
+ i,
+ j,
+ ii,
+ jj,
+ pathi;
+
+ path = path2curve(path);
+ for (i = 0, ii = path.length; i < ii; i++) {
+ pathi = path[i];
+ for (j = 1, jj = pathi.length; j < jj; j += 2) {
+ x = matrix.x(pathi[j], pathi[j + 1]);
+ y = matrix.y(pathi[j], pathi[j + 1]);
+ pathi[j] = x;
+ pathi[j + 1] = y;
+ }
+ }
+ return path;
+ },
+
+ /*\
+ * Raphael.pick
+ [ method ]
+ **
+ * Returns the first truthy argument.
+ \*/
+ pick = R.pick = function() {
+ for (var arg, i = 0, ii = arguments.length; i < ii; i += 1) {
+ arg = arguments[i];
+ if (!arg && arg !== false && arg !== 0) {
+ continue;
+ }
+ return arg;
+ }
+ return undef;
+ },
+
+ lastArgIfGroup = R._lastArgIfGroup = function (args, clear) {
+ var last = args.length - 1,
+ arg = args[last];
+
+ if (arg && (arg.constructor === R.el.constructor) && arg.type === 'group') {
+ if (clear) {
+ arraySplice.call(args, last, 1);
+ }
+ return arg;
+ }
+ },
+
+ merge = R.merge = function (obj1, obj2, skipUndef, tgtArr, srcArr) {
+ var item,
+ srcVal,
+ tgtVal,
+ str,
+ cRef;
+ //check whether obj2 is an array
+ //if array then iterate through it's index
+ //**** MOOTOOLS precution
+
+ if (!srcArr) {
+ tgtArr = [obj1];
+ srcArr = [obj2];
+ }
+ else {
+ tgtArr.push(obj1);
+ srcArr.push(obj2);
+ }
+
+ if (obj2 instanceof Array) {
+ for (item = 0; item < obj2.length; item += 1) {
+ try {
+ srcVal = obj1[item];
+ tgtVal = obj2[item];
+ }
+ catch (e) {
+ continue;
+ }
+
+ if (typeof tgtVal !== OBJECTSTRING) {
+ if (!(skipUndef && tgtVal === undefined)) {
+ obj1[item] = tgtVal;
+ }
+ }
+ else {
+ if (srcVal === null || typeof srcVal !== OBJECTSTRING) {
+ srcVal = obj1[item] = tgtVal instanceof Array ? [] : {};
+ }
+ cRef = checkCyclicRef(tgtVal, srcArr);
+ if (cRef !== -1) {
+ srcVal = obj1[item] = tgtArr[cRef];
+ }
+ else {
+ merge(srcVal, tgtVal, skipUndef, tgtArr, srcArr);
+ }
+ }
+ }
+ }
+ else {
+ for (item in obj2) {
+ try {
+ srcVal = obj1[item];
+ tgtVal = obj2[item];
+ }
+ catch (e) {
+ continue;
+ }
+
+ if (tgtVal !== null && typeof tgtVal === OBJECTSTRING) {
+ // Fix for issue BUG: FWXT-602
+ // IE < 9 Object.prototype.toString.call(null) gives
+ // "[object Object]" instead of "[object Null]"
+ // that's why null value becomes Object in IE < 9
+ str = objectToString.call(tgtVal);
+ if (str === objectToStr) {
+ if (srcVal === null || typeof srcVal !== OBJECTSTRING) {
+ srcVal = obj1[item] = {};
+ }
+ cRef = checkCyclicRef(tgtVal, srcArr);
+ if (cRef !== -1) {
+ srcVal = obj1[item] = tgtArr[cRef];
+ }
+ else {
+ merge(srcVal, tgtVal, skipUndef, tgtArr, srcArr);
+ }
+ }
+ else if (str === arrayToStr) {
+ if (srcVal === null || !(srcVal instanceof Array)) {
+ srcVal = obj1[item] = [];
+ }
+ cRef = checkCyclicRef(tgtVal, srcArr);
+ if (cRef !== -1) {
+ srcVal = obj1[item] = tgtArr[cRef];
+ }
+ else {
+ merge(srcVal, tgtVal, skipUndef, tgtArr, srcArr);
+ }
+ }
+ else {
+ obj1[item] = tgtVal;
+ }
+ }
+ else {
+ obj1[item] = tgtVal;
+ }
+ }
+ }
+ return obj1;
+ },
+
+ extend = R.extend = function (obj1, obj2, skipUndef) {
+ if (typeof obj1 !== OBJECTSTRING && typeof obj2 !== OBJECTSTRING) {//if none of the arguments are object then return back
+ return null;
+ }
+
+ if (typeof obj2 !== OBJECTSTRING || obj2 === null) {
+ return obj1;
+ }
+
+ if (typeof obj1 !== OBJECTSTRING) {
+ obj1 = obj2 instanceof Array ? [] : {};
+ }
+ merge(obj1, obj2, skipUndef);
+ return obj1;
+
+ },
+
+ /*\
+ * Raphael.is
+ [ method ]
+ **
+ * Handfull replacement for `typeof` operator.
+ > Parameters
+ - o (…) any object or primitive
+ - type (string) name of the type, i.e. “string”, “function”, “number”, etc.
+ = (boolean) is given value is of given type
+ \*/
+ is = R.is = function(o, type) {
+ type = lowerCase.call(type);
+
+ if (type == finite) {
+ return !isnan[has](+o);
+ }
+ if (type == array) {
+ return o instanceof Array;
+ }
+ if (type === 'object' && (o === undef || o === null)) {
+ return false;
+ }
+ return (type == "null" && o === null) ||
+ (type == typeof o && o !== null) ||
+ (type == object && o === Object(o)) ||
+ (type == "array" && Array.isArray && Array.isArray(o)) ||
+ objectToString.call(o).slice(8, -1).toLowerCase() == type;
+ },
+
+ /*\
+ * Raphael.clone
+ [ method ]
+ **
+ * Returns a recursively cloned version of an object.
+ \*/
+ clone = R.clone = function (obj) {
+ if (Object(obj) !== obj) {
+ return obj;
+ }
+ var res = new obj.constructor;
+ for (var key in obj)
+ if (obj[has](key)) {
+ res[key] = clone(obj[key]);
+ }
+ return res;
+ },
+
+ /*\
+ * Raphael.createUUID
+ [ method ]
+ **
+ * Returns RFC4122, version 4 ID
+ \*/
+ createUUID = R.createUUID = (function(uuidRegEx, uuidReplacer) {
+ return function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase();
+ };
+ })(/[xy]/g, function(c) {
+ var r = math.random() * 16 | 0,
+ v = c == "x" ? r : (r & 3 | 8);
+ return v.toString(16);
+ });
+
+ R._g = g;
+
+ /*\
+ * Raphael.type
+ [ property (string) ]
+ **
+ * Can be “SVG”, “VML” or empty, depending on browser support.
+ \*/
+ R.type = (win.ENABLE_RED_CANVAS && (win.CanvasRenderingContext2D || doc.createElement('canvas').getContext)) ? "CANVAS" :
+ (win.SVGAngle || doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML");
+
+ if (R.type == "VML") {
+ var d = doc.createElement("div"),
+ b;
+
+ d.innerHTML = ' ';
+ b = d.firstChild;
+ b.style.behavior = "url(#default#VML)";
+ if (!(b && typeof b.adj == object)) {
+ return (R.type = E);
+ }
+ d = null;
+ }
+
+ /*\
+ * Raphael.svg
+ [ property (boolean) ]
+ **
+ * `true` if browser supports SVG.
+ \*/
+ /*\
+ * Raphael.vml
+ [ property (boolean) ]
+ **
+ * `true` if browser supports VML.
+ \*/
+ R.svg = !((R.vml = R.type == "VML") || (R.canvas = R.type == "CANVAS"));
+
+ R._Paper = Paper;
+ R._id = 0;
+ R._oid = 0;
+
+ /*\
+ * Raphael.angle
+ [ method ]
+ **
+ * Returns angle between two or three points
+ > Parameters
+ - x1 (number) x coord of first point
+ - y1 (number) y coord of first point
+ - x2 (number) x coord of second point
+ - y2 (number) y coord of second point
+ - x3 (number) #optional x coord of third point
+ - y3 (number) #optional y coord of third point
+ = (number) angle in degrees.
+ \*/
+ R.angle = function (x1, y1, x2, y2, x3, y3) {
+ if (x3 == null) {
+ var x = x1 - x2,
+ y = y1 - y2;
+ if (!x && !y) {
+ return 0;
+ }
+ return (180 + math.atan2(-y, -x) * rad2deg + 360) % 360;
+ }
+ else {
+ return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3);
+ }
+ };
+
+ /*\
+ * Raphael.rad
+ [ method ]
+ **
+ * Transform angle to radians
+ > Parameters
+ - deg (number) angle in degrees
+ = (number) angle in radians.
+ \*/
+ R.rad = function (deg) {
+ return deg % 360 * deg2rad;
+ };
+
+ /*\
+ * Raphael.deg
+ [ method ]
+ **
+ * Transform angle to degrees
+ > Parameters
+ - deg (number) angle in radians
+ = (number) angle in degrees.
+ \*/
+ R.deg = function (rad) {
+ return rad * rad2deg % 360;
+ };
+
+ /*\
+ * Raphael.snapTo
+ [ method ]
+ **
+ * Snaps given value to given grid.
+ > Parameters
+ - values (array|number) given array of values or step of the grid
+ - value (number) value to adjust
+ - tolerance (number) #optional tolerance for snapping. Default is `10`.
+ = (number) adjusted value.
+ \*/
+ R.snapTo = function (values, value, tolerance) {
+ var rem,
+ i;
+
+ if (!is(tolerance, finite)) {
+ tolerance = 10;
+ }
+
+ if (is(values, array)) {
+ i = values.length;
+ while (i--) {
+ if (abs(values[i] - value) <= tolerance) {
+ return values[i];
+ }
+ }
+ }
+ else {
+ values = +values;
+ rem = value % values;
+
+ if (rem < tolerance) {
+ return value - rem;
+ }
+ if (rem > values - tolerance) {
+ return value - rem + values;
+ }
+ }
+ return value;
+ };
+
+ /*\
+ * Raphael.setWindow
+ [ method ]
+ **
+ * Used when you need to draw in `<iframe>`. Switched window to the iframe one.
+ > Parameters
+ - newwin (window) new window object
+ \*/
+ R.setWindow = function (newwin) {
+ eve("raphael.setWindow", R, g.win, newwin);
+ win = g.win = newwin;
+ doc = g.doc = g.win.document;
+ if (R._engine.initWin) {
+ R._engine.initWin(g.win);
+ }
+ };
+
+ var toHex = function (color) {
+ if (R.vml) {
+ // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/
+ var trim = /^\s+|\s+$/g;
+ var bod;
+ try {
+ var docum = new ActiveXObject("htmlfile");
+ docum.write("");
+ docum.close();
+ bod = docum.body;
+ } catch (e) {
+ bod = createPopup().document.body;
+ }
+ var range = bod.createTextRange();
+ toHex = cacher(function(color) {
+ try {
+ bod.style.color = Str(color).replace(trim, E);
+ var value = range.queryCommandValue("ForeColor");
+ value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16);
+ return "#" + ("000000" + value.toString(16)).slice(-6);
+ } catch (e) {
+ return none;
+ }
+ });
+ } else {
+ var i = g.doc.createElement("i");
+ i.title = "Rapha\xebl Colour Picker";
+ i.style.display = none;
+ g.doc.body.appendChild(i);
+ toHex = cacher(function(color) {
+ i.style.color = color;
+ return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
+ });
+ }
+ return toHex(color);
+ },
+ hsbtoString = function() {
+ return "hsb(" + [this.h, this.s, this.b] + ")";
+ },
+ hsltoString = function() {
+ return "hsl(" + [this.h, this.s, this.l] + ")";
+ },
+ rgbtoString = function() {
+ return this.hex;
+ },
+ prepareRGB = function(r, g, b) {
+ if (g == null && is(r, object) && "r" in r && "g" in r && "b" in r) {
+ b = r.b;
+ g = r.g;
+ r = r.r;
+ }
+ if (g == null && is(r, string)) {
+ var clr = R.getRGB(r);
+ r = clr.r;
+ g = clr.g;
+ b = clr.b;
+ }
+ if (r > 1 || g > 1 || b > 1) {
+ r /= 255;
+ g /= 255;
+ b /= 255;
+ }
+
+ return [r, g, b];
+ },
+ packageRGB = function(r, g, b, o) {
+ var rgb = {
+ r: (r *= 255),
+ g: (g *= 255),
+ b: (b *= 255),
+ hex: R.rgb(r, g, b),
+ toString: rgbtoString
+ };
+ is(o, "finite") && (rgb.opacity = o);
+ return rgb;
+ };
+
+ /*\
+ * Raphael.color
+ [ method ]
+ **
+ * Parses the color string and returns object with all values for the given color.
+ > Parameters
+ - clr (string) color string in one of the supported formats (see @Raphael.getRGB)
+ = (object) Combined RGB & HSB object in format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••,
+ o error (boolean) `true` if string can’t be parsed,
+ o h (number) hue,
+ o s (number) saturation,
+ o v (number) value (brightness),
+ o l (number) lightness
+ o }
+ \*/
+ R.color = function(clr) {
+ var rgb;
+ if (R.is(clr, object) && "h" in clr && "s" in clr && "b" in clr) {
+ rgb = R.hsb2rgb(clr);
+ clr.r = rgb.r;
+ clr.g = rgb.g;
+ clr.b = rgb.b;
+ clr.hex = rgb.hex;
+ } else if (R.is(clr, object) && "h" in clr && "s" in clr && "l" in clr) {
+ rgb = R.hsl2rgb(clr);
+ clr.r = rgb.r;
+ clr.g = rgb.g;
+ clr.b = rgb.b;
+ clr.hex = rgb.hex;
+ } else {
+ if (R.is(clr, "string")) {
+ clr = R.getRGB(clr);
+ }
+ if (R.is(clr, object) && "r" in clr && "g" in clr && "b" in clr) {
+ rgb = R.rgb2hsl(clr);
+ clr.h = rgb.h;
+ clr.s = rgb.s;
+ clr.l = rgb.l;
+ rgb = R.rgb2hsb(clr);
+ clr.v = rgb.b;
+ } else {
+ clr = {
+ hex: none
+ };
+ clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1;
+ }
+ }
+ clr.toString = rgbtoString;
+ return clr;
+ };
+
+ /*\
+ * Raphael.hsb2rgb
+ [ method ]
+ **
+ * Converts HSB values to RGB object.
+ > Parameters
+ - h (number) hue
+ - s (number) saturation
+ - v (number) value or brightness
+ = (object) RGB object in format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••
+ o }
+ \*/
+ R.hsb2rgb = function(h, s, v, o) {
+ if (this.is(h, object) && "h" in h && "s" in h && "b" in h) {
+ v = h.b;
+ s = h.s;
+ h = h.h;
+ o = h.o;
+ }
+ h *= 360;
+ var R, G, B, X, C;
+ h = (h % 360) / 60;
+ C = v * s;
+ X = C * (1 - abs(h % 2 - 1));
+ R = G = B = v - C;
+
+ h = ~~h;
+ R += [C, X, 0, 0, X, C][h];
+ G += [X, C, C, X, 0, 0][h];
+ B += [0, 0, X, C, C, X][h];
+ return packageRGB(R, G, B, o);
+ };
+
+ /*\
+ * Raphael.hsl2rgb
+ [ method ]
+ **
+ * Converts HSL values to RGB object.
+ > Parameters
+ - h (number) hue
+ - s (number) saturation
+ - l (number) luminosity
+ = (object) RGB object in format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••
+ o }
+ \*/
+ R.hsl2rgb = function(h, s, l, o) {
+ if (this.is(h, object) && "h" in h && "s" in h && "l" in h) {
+ l = h.l;
+ s = h.s;
+ h = h.h;
+ }
+ if (h > 1 || s > 1 || l > 1) {
+ h /= 360;
+ s /= 100;
+ l /= 100;
+ }
+ h *= 360;
+ var R, G, B, X, C;
+ h = (h % 360) / 60;
+ C = 2 * s * (l < .5 ? l : 1 - l);
+ X = C * (1 - abs(h % 2 - 1));
+ R = G = B = l - C / 2;
+
+ h = ~~h;
+ R += [C, X, 0, 0, X, C][h];
+ G += [X, C, C, X, 0, 0][h];
+ B += [0, 0, X, C, C, X][h];
+ return packageRGB(R, G, B, o);
+ };
+
+ /*\
+ * Raphael.rgb2hsb
+ [ method ]
+ **
+ * Converts RGB values to HSB object.
+ > Parameters
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (object) HSB object in format:
+ o {
+ o h (number) hue
+ o s (number) saturation
+ o b (number) brightness
+ o }
+ \*/
+ R.rgb2hsb = function(r, g, b) {
+ b = prepareRGB(r, g, b);
+ r = b[0];
+ g = b[1];
+ b = b[2];
+
+ var H, S, V, C;
+ V = mmax(r, g, b);
+ C = V - mmin(r, g, b);
+ H = (C == 0 ? null :
+ V == r ? (g - b) / C :
+ V == g ? (b - r) / C + 2 :
+ (r - g) / C + 4
+ );
+ H = ((H + 360) % 6) * 60 / 360;
+ S = C == 0 ? 0 : C / V;
+ return {
+ h: H,
+ s: S,
+ b: V,
+ toString: hsbtoString
+ };
+ };
+
+ /*\
+ * Raphael.rgb2hsl
+ [ method ]
+ **
+ * Converts RGB values to HSL object.
+ > Parameters
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (object) HSL object in format:
+ o {
+ o h (number) hue
+ o s (number) saturation
+ o l (number) luminosity
+ o }
+ \*/
+ R.rgb2hsl = function(r, g, b) {
+ b = prepareRGB(r, g, b);
+ r = b[0];
+ g = b[1];
+ b = b[2];
+
+ var H, S, L, M, m, C;
+ M = mmax(r, g, b);
+ m = mmin(r, g, b);
+ C = M - m;
+ H = (C == 0 ? null :
+ M == r ? (g - b) / C :
+ M == g ? (b - r) / C + 2 :
+ (r - g) / C + 4);
+ H = ((H + 360) % 6) * 60 / 360;
+ L = (M + m) / 2;
+ S = (C == 0 ? 0 :
+ L < .5 ? C / (2 * L) :
+ C / (2 - 2 * L));
+ return {
+ h: H,
+ s: S,
+ l: L,
+ toString: hsltoString
+ };
+ };
+
+ R._path2string = function() {
+ return this.join(",").replace(p2s, "$1");
+ };
+
+ function repush(array, item) {
+ for (var i = 0, ii = array.length; i < ii; i++) {
+ if (array[i] === item) {
+ return array.push(array.splice(i, 1)[0]);
+ }
+ }
+ }
+
+ var cacher = R._cacher = function (f, scope, postprocessor) {
+ function cachedfunction() {
+ var arg = arraySlice.call(arguments, 0),
+ args = arg.join("\u2400"),
+ cache = cachedfunction.cache = cachedfunction.cache || {},
+ count = cachedfunction.count = cachedfunction.count || [];
+ if (cache[has](args)) {
+ repush(count, args);
+ return postprocessor ? postprocessor(cache[args]) : cache[args];
+ }
+ count.length >= 1e3 && delete cache[count.shift()];
+ count.push(args);
+ cache[args] = f[apply](scope, arg);
+ return postprocessor ? postprocessor(cache[args]) : cache[args];
+ }
+ return cachedfunction;
+ };
+
+ var preload = R._preload = function(src, f) {
+ var img = doc.createElement("img");
+ img.style.cssText = "position:absolute;left:-9999em;top:-9999em";
+ img.onload = function() {
+ f.call(this);
+ this.onload = null;
+ doc.body.removeChild(this);
+ };
+ img.onerror = function() {
+ doc.body.removeChild(this);
+ };
+ doc.body.appendChild(img);
+ img.src = src;
+ };
+
+ function clrToString() {
+ return this.hex;
+ }
+
+ /*\
+ * Raphael.getRGB
+ [ method ]
+ **
+ * Parses colour string as RGB object
+ > Parameters
+ - colour (string) colour string in one of formats:
+ #
+ # Colour name (“red
”, “green
”, “cornflowerblue
”, etc)
+ # #••• — shortened HTML colour: (“#000
”, “#fc0
”, etc)
+ # #•••••• — full length HTML colour: (“#000000
”, “#bd2300
”)
+ # rgb(•••, •••, •••) — red, green and blue channels’ values: (“rgb(200, 100, 0)
”)
+ # rgb(•••%, •••%, •••%) — same as above, but in %: (“rgb(100%, 175%, 0%)
”)
+ # hsb(•••, •••, •••) — hue, saturation and brightness values: (“hsb(0.5, 0.25, 1)
”)
+ # hsb(•••%, •••%, •••%) — same as above, but in %
+ # hsl(•••, •••, •••) — same as hsb
+ # hsl(•••%, •••%, •••%) — same as hsb
+ #
+ = (object) RGB object in format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue
+ o hex (string) color in HTML/CSS format: #••••••,
+ o error (boolean) true if string can’t be parsed
+ o }
+ \*/
+ R.getRGB = cacher(function(colour) {
+ var opacity,
+ res,
+ red,
+ green,
+ blue,
+ t,
+ values,
+ rgb;
+
+ colour && is(colour, 'object') && "opacity" in colour &&
+ (opacity = colour.opacity);
+ if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
+ return {
+ r: -1,
+ g: -1,
+ b: -1,
+ hex: none,
+ error: 1,
+ toString: clrToString
+ };
+ }
+ if (colour == none) {
+ return {
+ r: -1,
+ g: -1,
+ b: -1,
+ hex: none,
+ toString: clrToString
+ };
+ }
+ !(hsrg[has](colour.toLowerCase().substring(0, 2)) ||
+ colour.charAt() === "#") && (colour = toHex(colour));
+
+
+ if ((rgb = colour.match(colourRegExp))) {
+ if (rgb[2]) {
+ blue = toInt(rgb[2].substring(5), 16);
+ green = toInt(rgb[2].substring(3, 5), 16);
+ red = toInt(rgb[2].substring(1, 3), 16);
+ }
+ if (rgb[3]) {
+ blue = toInt((t = rgb[3].charAt(3)) + t, 16);
+ green = toInt((t = rgb[3].charAt(2)) + t, 16);
+ red = toInt((t = rgb[3].charAt(1)) + t, 16);
+ }
+ if (rgb[4]) {
+ values = rgb[4][split](commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red *= 2.55);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green *= 2.55);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue *= 2.55);
+ rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ }
+ if (rgb[5]) {
+ values = rgb[5][split](commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red *= 2.55);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green *= 2.55);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue *= 2.55);
+ (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
+ rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ return R.hsb2rgb(red, green, blue, opacity);
+ }
+ if (rgb[6]) {
+ values = rgb[6][split](commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red *= 2.55);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green *= 2.55);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue *= 2.55);
+ (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
+ rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ return R.hsl2rgb(red, green, blue, opacity);
+ }
+ rgb = {
+ r: red,
+ g: green,
+ b: blue,
+ toString: clrToString
+ };
+ rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
+ R.is(opacity, "finite") && (rgb.opacity = opacity);
+ return rgb;
+ }
+ return {
+ r: -1,
+ g: -1,
+ b: -1,
+ hex: none,
+ error: 1,
+ toString: clrToString
+ };
+ }, R);
+
+ R.tintshade = cacher(function(colour, percent) {
+ var rgb = R.getRGB(colour),
+ tint,
+ offset = 255;
+
+ (percent < 0) && (percent *= -1, offset = 0);
+ (percent > 1) && (percent = 1);
+
+ tint = percent === 0 ? rgb : {
+ r: offset - (offset - rgb.r) * percent,
+ g: offset - (offset - rgb.g) * percent,
+ b: offset - (offset - rgb.b) * percent,
+ toString: clrToString
+ };
+ tint.hex = R.rgb(tint.r, tint.g, tint.b);
+ rgb.error && (tint.error = rgb.error);
+
+ if ("opacity" in rgb) {
+ tint.rgba = 'rgba(' + [tint.r, tint.g, tint.b, rgb.opacity].join(',') + ')';
+ tint.opacity = rgb.opacity;
+ }
+ else {
+ tint.rgba = 'rgb(' + [tint.r, tint.g, tint.b].join(',') + ')';
+ }
+ return tint;
+ }, R);
+
+ /*\
+ * Raphael.hsb
+ [ method ]
+ **
+ * Converts HSB values to hex representation of the colour.
+ > Parameters
+ - h (number) hue
+ - s (number) saturation
+ - b (number) value or brightness
+ = (string) hex representation of the colour.
+ \*/
+ R.hsb = cacher(function(h, s, b) {
+ return R.hsb2rgb(h, s, b).hex;
+ });
+
+ /*\
+ * Raphael.hsl
+ [ method ]
+ **
+ * Converts HSL values to hex representation of the colour.
+ > Parameters
+ - h (number) hue
+ - s (number) saturation
+ - l (number) luminosity
+ = (string) hex representation of the colour.
+ \*/
+ R.hsl = cacher(function(h, s, l) {
+ return R.hsl2rgb(h, s, l).hex;
+ });
+
+ /*\
+ * Raphael.rgb
+ [ method ]
+ **
+ * Converts RGB values to hex representation of the colour.
+ > Parameters
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (string) hex representation of the colour.
+ \*/
+ R.rgb = cacher(function(r, g, b) {
+ return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1);
+ });
+
+ /*\
+ * Raphael.getColor
+ [ method ]
+ **
+ * On each call returns next colour in the spectrum. To reset it back to red call @Raphael.getColor.reset
+ > Parameters
+ - value (number) #optional brightness, default is `0.75`
+ = (string) hex representation of the colour.
+ \*/
+ R.getColor = function(value) {
+ var start = this.getColor.start = this.getColor.start || {
+ h: 0,
+ s: 1,
+ b: value || .75
+ },
+ rgb = this.hsb2rgb(start.h, start.s, start.b);
+ start.h += .075;
+ if (start.h > 1) {
+ start.h = 0;
+ start.s -= .2;
+ start.s <= 0 && (this.getColor.start = {
+ h: 0,
+ s: 1,
+ b: start.b
+ });
+ }
+ return rgb.hex;
+ };
+
+ /*\
+ * Raphael.getColor.reset
+ [ method ]
+ **
+ * Resets spectrum position for @Raphael.getColor back to red.
+ \*/
+ R.getColor.reset = function() {
+ delete this.start;
+ };
+
+ // http://schepers.cc/getting-to-the-point
+ function catmullRom2bezier(crp, z) {
+ var d = [];
+ for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
+ var p = [
+ {
+ x: +crp[i - 2],
+ y: +crp[i - 1]
+ },
+ {
+ x: +crp[i],
+ y: +crp[i + 1]
+ },
+ {
+ x: +crp[i + 2],
+ y: +crp[i + 3]
+ },
+ {
+ x: +crp[i + 4],
+ y: +crp[i + 5]
+ }
+ ];
+ if (z) {
+ if (!i) {
+ p[0] = {
+ x: +crp[iLen - 2],
+ y: +crp[iLen - 1]
+ };
+ } else if (iLen - 4 == i) {
+ p[3] = {
+ x: +crp[0],
+ y: +crp[1]
+ };
+ } else if (iLen - 2 == i) {
+ p[2] = {
+ x: +crp[0],
+ y: +crp[1]
+ };
+ p[3] = {
+ x: +crp[2],
+ y: +crp[3]
+ };
+ }
+ } else {
+ if (iLen - 4 == i) {
+ p[3] = p[2];
+ } else if (!i) {
+ p[0] = {
+ x: +crp[i],
+ y: +crp[i + 1]
+ };
+ }
+ }
+ d.push(["C",
+ (-p[0].x + 6 * p[1].x + p[2].x) / 6,
+ (-p[0].y + 6 * p[1].y + p[2].y) / 6,
+ (p[1].x + 6 * p[2].x - p[3].x) / 6,
+ (p[1].y + 6 * p[2].y - p[3].y) / 6,
+ p[2].x,
+ p[2].y
+ ]);
+ }
+
+ return d;
+ }
+
+ /*\
+ * Raphael.parsePathString
+ [ method ]
+ **
+ * Utility method
+ **
+ * Parses given path string into an array of arrays of path segments.
+ > Parameters
+ - pathString (string|array) path string or array of segments (in the last case it will be returned straight away)
+ = (array) array of segments.
+ \*/
+ R.parsePathString = function(pathString) {
+ if (!pathString) {
+ return null;
+ }
+ var pth = paths(pathString);
+ if (pth.arr) {
+ return pathClone(pth.arr);
+ }
+
+ var paramCounts = {
+ a: 7,
+ c: 6,
+ h: 1,
+ l: 2,
+ m: 2,
+ r: 4,
+ q: 4,
+ s: 4,
+ t: 2,
+ v: 1,
+ z: 0
+ },
+ data = [];
+ if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption
+ data = pathClone(pathString);
+ }
+ if (!data.length) {
+ Str(pathString).replace(pathCommand, function(a, b, c) {
+ var params = [],
+ name = b.toLowerCase();
+ c.replace(pathValues, function(a, b) {
+ b && params.push(+b);
+ });
+ if (name == "m" && params.length > 2) {
+ data.push([b][concat](params.splice(0, 2)));
+ name = "l";
+ b = b == "m" ? "l" : "L";
+ }
+ if (name == "r") {
+ data.push([b][concat](params));
+ } else
+ while (params.length >= paramCounts[name]) {
+ data.push([b][concat](params.splice(0, paramCounts[name])));
+ if (!paramCounts[name]) {
+ break;
+ }
+ }
+ });
+ }
+ data.toString = R._path2string;
+ pth.arr = pathClone(data);
+ return data;
+ };
+
+ /*\
+ * Raphael.parseTransformString
+ [ method ]
+ **
+ * Utility method
+ **
+ * Parses given path string into an array of transformations.
+ > Parameters
+ - TString (string|array) transform string or array of transformations (in the last case it will be returned straight away)
+ = (array) array of transformations.
+ \*/
+ R.parseTransformString = cacher(function(TString) {
+ if (!TString) {
+ return null;
+ }
+ var paramCounts = {
+ r: 3,
+ s: 4,
+ t: 2,
+ m: 6
+ },
+ data = [];
+ if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption
+ data = pathClone(TString);
+ }
+ if (!data.length) {
+ Str(TString).replace(tCommand, function(a, b, c) {
+ var params = [],
+ name = lowerCase.call(b);
+ c.replace(pathValues, function(a, b) {
+ b && params.push(+b);
+ });
+ data.push([b][concat](params));
+ });
+ }
+ data.toString = R._path2string;
+ return data;
+ });
+ // PATHS
+ var paths = function(ps) {
+ var p = paths.ps = paths.ps || {};
+ if (p[ps]) {
+ p[ps].sleep = 100;
+ } else {
+ p[ps] = {
+ sleep: 100
+ };
+ }
+ setTimeout(function() {
+ for (var key in p)
+ if (p[has](key) && key != ps) {
+ p[key].sleep--;
+ !p[key].sleep && delete p[key];
+ }
+ });
+ return p[ps];
+ };
+
+ /*\
+ * Raphael.findDotsAtSegment
+ [ method ]
+ **
+ * Utility method
+ **
+ * Find dot coordinates on the given cubic bezier curve at the given t.
+ > Parameters
+ - p1x (number) x of the first point of the curve
+ - p1y (number) y of the first point of the curve
+ - c1x (number) x of the first anchor of the curve
+ - c1y (number) y of the first anchor of the curve
+ - c2x (number) x of the second anchor of the curve
+ - c2y (number) y of the second anchor of the curve
+ - p2x (number) x of the second point of the curve
+ - p2y (number) y of the second point of the curve
+ - t (number) position on the curve (0..1)
+ = (object) point information in format:
+ o {
+ o x: (number) x coordinate of the point
+ o y: (number) y coordinate of the point
+ o m: {
+ o x: (number) x coordinate of the left anchor
+ o y: (number) y coordinate of the left anchor
+ o }
+ o n: {
+ o x: (number) x coordinate of the right anchor
+ o y: (number) y coordinate of the right anchor
+ o }
+ o start: {
+ o x: (number) x coordinate of the start of the curve
+ o y: (number) y coordinate of the start of the curve
+ o }
+ o end: {
+ o x: (number) x coordinate of the end of the curve
+ o y: (number) y coordinate of the end of the curve
+ o }
+ o alpha: (number) angle of the curve derivative at the point
+ o }
+ \*/
+ R.findDotsAtSegment = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+ var t1 = 1 - t,
+ t13 = pow(t1, 3),
+ t12 = pow(t1, 2),
+ t2 = t * t,
+ t3 = t2 * t,
+ x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
+ y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y,
+ mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x),
+ my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y),
+ nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x),
+ ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y),
+ ax = t1 * p1x + t * c1x,
+ ay = t1 * p1y + t * c1y,
+ cx = t1 * c2x + t * p2x,
+ cy = t1 * c2y + t * p2y,
+ alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI);
+ (mx > nx || my < ny) && (alpha += 180);
+ return {
+ x: x,
+ y: y,
+ m: {
+ x: mx,
+ y: my
+ },
+ n: {
+ x: nx,
+ y: ny
+ },
+ start: {
+ x: ax,
+ y: ay
+ },
+ end: {
+ x: cx,
+ y: cy
+ },
+ alpha: alpha
+ };
+ };
+
+ /*\
+ * Raphael.bezierBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Return bounding box of a given cubic bezier curve
+ > Parameters
+ - p1x (number) x of the first point of the curve
+ - p1y (number) y of the first point of the curve
+ - c1x (number) x of the first anchor of the curve
+ - c1y (number) y of the first anchor of the curve
+ - c2x (number) x of the second anchor of the curve
+ - c2y (number) y of the second anchor of the curve
+ - p2x (number) x of the second point of the curve
+ - p2y (number) y of the second point of the curve
+ * or
+ - bez (array) array of six points for bezier curve
+ = (object) point information in format:
+ o {
+ o min: {
+ o x: (number) x coordinate of the left point
+ o y: (number) y coordinate of the top point
+ o }
+ o max: {
+ o x: (number) x coordinate of the right point
+ o y: (number) y coordinate of the bottom point
+ o }
+ o }
+ \*/
+ R.bezierBBox = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
+ if (!R.is(p1x, "array")) {
+ p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y];
+ }
+ var bbox = curveDim.apply(null, p1x);
+ return {
+ x: bbox.min.x,
+ y: bbox.min.y,
+ x2: bbox.max.x,
+ y2: bbox.max.y,
+ width: bbox.max.x - bbox.min.x,
+ height: bbox.max.y - bbox.min.y
+ };
+ };
+
+ /*\
+ * Raphael.isPointInsideBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if given point is inside bounding boxes.
+ > Parameters
+ - bbox (string) bounding box
+ - x (string) x coordinate of the point
+ - y (string) y coordinate of the point
+ = (boolean) `true` if point inside
+ \*/
+ R.isPointInsideBBox = function(bbox, x, y) {
+ return x >= bbox.x && x <= bbox.x2 && y >= bbox.y && y <= bbox.y2;
+ };
+
+ /*\
+ * Raphael.isBBoxIntersect
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if two bounding boxes intersect
+ > Parameters
+ - bbox1 (string) first bounding box
+ - bbox2 (string) second bounding box
+ = (boolean) `true` if they intersect
+ \*/
+ R.isBBoxIntersect = function(bbox1, bbox2) {
+ var i = R.isPointInsideBBox;
+ return i(bbox2, bbox1.x, bbox1.y) ||
+ i(bbox2, bbox1.x2, bbox1.y) ||
+ i(bbox2, bbox1.x, bbox1.y2) ||
+ i(bbox2, bbox1.x2, bbox1.y2) ||
+ i(bbox1, bbox2.x, bbox2.y) ||
+ i(bbox1, bbox2.x2, bbox2.y) ||
+ i(bbox1, bbox2.x, bbox2.y2) ||
+ i(bbox1, bbox2.x2, bbox2.y2) ||
+ (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x ||
+ bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) &&
+ (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y);
+ };
+
+ function base3(t, p1, p2, p3, p4) {
+ var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4,
+ t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
+ return t * t2 - 3 * p1 + 3 * p2;
+ }
+
+ function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) {
+ if (z == null) {
+ z = 1;
+ }
+ z = z > 1 ? 1 : z < 0 ? 0 : z;
+ var z2 = z / 2,
+ n = 12,
+ Tvalues = [-0.1252, 0.1252, -0.3678, 0.3678, -0.5873, 0.5873, -0.7699, 0.7699, -0.9041, 0.9041, -0.9816, 0.9816],
+ Cvalues = [0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472],
+ sum = 0;
+ for (var i = 0; i < n; i++) {
+ var ct = z2 * Tvalues[i] + z2,
+ xbase = base3(ct, x1, x2, x3, x4),
+ ybase = base3(ct, y1, y2, y3, y4),
+ comb = xbase * xbase + ybase * ybase;
+ sum += Cvalues[i] * mathSqrt(comb);
+ }
+ return z2 * sum;
+ }
+
+ function getTatLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) {
+ if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) {
+ return;
+ }
+ var t = 1,
+ step = t / 2,
+ t2 = t - step,
+ l,
+ e = .01;
+ l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
+ while (abs(l - ll) > e) {
+ step /= 2;
+ t2 += (l < ll ? 1 : -1) * step;
+ l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
+ }
+ return t2;
+ }
+
+ function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
+ if (
+ mmax(x1, x2) < mmin(x3, x4) ||
+ mmin(x1, x2) > mmax(x3, x4) ||
+ mmax(y1, y2) < mmin(y3, y4) ||
+ mmin(y1, y2) > mmax(y3, y4)
+ ) {
+ return;
+ }
+ var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4),
+ ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4),
+ denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+
+ if (!denominator) {
+ return;
+ }
+ var px = nx / denominator,
+ py = ny / denominator,
+ px2 = +px.toFixed(2),
+ py2 = + py.toFixed(2);
+ if (
+ px2 < +mmin(x1, x2).toFixed(2) ||
+ px2 > +mmax(x1, x2).toFixed(2) ||
+ px2 < +mmin(x3, x4).toFixed(2) ||
+ px2 > +mmax(x3, x4).toFixed(2) ||
+ py2 < +mmin(y1, y2).toFixed(2) ||
+ py2 > +mmax(y1, y2).toFixed(2) ||
+ py2 < +mmin(y3, y4).toFixed(2) ||
+ py2 > +mmax(y3, y4).toFixed(2)
+ ) {
+ return;
+ }
+ return {
+ x: px,
+ y: py
+ };
+ }
+
+ function inter(bez1, bez2) {
+ return interHelper(bez1, bez2);
+ }
+
+ function interCount(bez1, bez2) {
+ return interHelper(bez1, bez2, 1);
+ }
+
+ function interHelper(bez1, bez2, justCount) {
+ var bbox1 = R.bezierBBox(bez1),
+ bbox2 = R.bezierBBox(bez2);
+
+ if (!R.isBBoxIntersect(bbox1, bbox2)) {
+ return justCount ? 0 : [];
+ }
+ var l1 = bezlen.apply(0, bez1),
+ l2 = bezlen.apply(0, bez2),
+ n1 = mmax(~~(l1 / 5), 1),
+ n2 = mmax(~~(l2 / 5), 1),
+ dots1 = [],
+ dots2 = [],
+ xy = {},
+ res = justCount ? 0 : [];
+
+ for (var i = 0; i < n1 + 1; i++) {
+ var p = R.findDotsAtSegment.apply(R, bez1.concat(i / n1));
+ dots1.push({
+ x: p.x,
+ y: p.y,
+ t: i / n1
+ });
+ }
+ for (i = 0; i < n2 + 1; i++) {
+ p = R.findDotsAtSegment.apply(R, bez2.concat(i / n2));
+ dots2.push({
+ x: p.x,
+ y: p.y,
+ t: i / n2
+ });
+ }
+ for (i = 0; i < n1; i++) {
+ for (var j = 0; j < n2; j++) {
+ var di = dots1[i],
+ di1 = dots1[i + 1],
+ dj = dots2[j],
+ dj1 = dots2[j + 1],
+ ci = abs(di1.x - di.x) < .001 ? "y" : "x",
+ cj = abs(dj1.x - dj.x) < .001 ? "y" : "x",
+ is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y);
+ if (is) {
+ if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) {
+ continue;
+ }
+ xy[is.x.toFixed(4)] = is.y.toFixed(4);
+ var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t),
+ t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t);
+ if (t1 >= 0 && t1 <= 1.001 && t2 >= 0 && t2 <= 1.001) {
+ if (justCount) {
+ res++;
+ } else {
+ res.push({
+ x: is.x,
+ y: is.y,
+ t1: mmin(t1, 1),
+ t2: mmin(t2, 1)
+ });
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+
+ /*\
+ * Raphael.pathIntersection
+ [ method ]
+ **
+ * Utility method
+ **
+ * Finds intersections of two paths
+ > Parameters
+ - path1 (string) path string
+ - path2 (string) path string
+ = (array) dots of intersection
+ o [
+ o {
+ o x: (number) x coordinate of the point
+ o y: (number) y coordinate of the point
+ o t1: (number) t value for segment of path1
+ o t2: (number) t value for segment of path2
+ o segment1: (number) order number for segment of path1
+ o segment2: (number) order number for segment of path2
+ o bez1: (array) eight coordinates representing beziér curve for the segment of path1
+ o bez2: (array) eight coordinates representing beziér curve for the segment of path2
+ o }
+ o ]
+ \*/
+ R.pathIntersection = function(path1, path2) {
+ return interPathHelper(path1, path2);
+ };
+ R.pathIntersectionNumber = function(path1, path2) {
+ return interPathHelper(path1, path2, 1);
+ };
+ function interPathHelper(path1, path2, justCount) {
+ path1 = R._path2curve(path1);
+ path2 = R._path2curve(path2);
+ var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2,
+ res = justCount ? 0 : [];
+ for (var i = 0, ii = path1.length; i < ii; i++) {
+ var pi = path1[i];
+ if (pi[0] == "M") {
+ x1 = x1m = pi[1];
+ y1 = y1m = pi[2];
+ } else {
+ if (pi[0] == "C") {
+ bez1 = [x1, y1].concat(pi.slice(1));
+ x1 = bez1[6];
+ y1 = bez1[7];
+ } else {
+ bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m];
+ x1 = x1m;
+ y1 = y1m;
+ }
+ for (var j = 0, jj = path2.length; j < jj; j++) {
+ var pj = path2[j];
+ if (pj[0] == "M") {
+ x2 = x2m = pj[1];
+ y2 = y2m = pj[2];
+ } else {
+ if (pj[0] == "C") {
+ bez2 = [x2, y2].concat(pj.slice(1));
+ x2 = bez2[6];
+ y2 = bez2[7];
+ } else {
+ bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m];
+ x2 = x2m;
+ y2 = y2m;
+ }
+ var intr = interHelper(bez1, bez2, justCount);
+ if (justCount) {
+ res += intr;
+ } else {
+ for (var k = 0, kk = intr.length; k < kk; k++) {
+ intr[k].segment1 = i;
+ intr[k].segment2 = j;
+ intr[k].bez1 = bez1;
+ intr[k].bez2 = bez2;
+ }
+ res = res.concat(intr);
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+
+ /*\
+ * Raphael.isPointInsidePath
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if given point is inside a given closed path.
+ > Parameters
+ - path (string) path string
+ - x (number) x of the point
+ - y (number) y of the point
+ = (boolean) true, if point is inside the path
+ \*/
+ R.isPointInsidePath = function(path, x, y) {
+ var bbox = R.pathBBox(path);
+ return R.isPointInsideBBox(bbox, x, y) &&
+ ((interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1) ||
+ (interPathHelper(path, [["M", x, y], ["V", bbox.y2 + 10]], 1) % 2 == 1))
+ };
+ R._removedFactory = function(methodname) {
+ return function() {
+ eve("raphael.log", null, "Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object", methodname);
+ };
+ };
+
+ /*\
+ * Raphael.pathBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Return bounding box of a given path
+ > Parameters
+ - path (string) path string
+ = (object) bounding box
+ o {
+ o x: (number) x coordinate of the left top point of the box
+ o y: (number) y coordinate of the left top point of the box
+ o x2: (number) x coordinate of the right bottom point of the box
+ o y2: (number) y coordinate of the right bottom point of the box
+ o width: (number) width of the box
+ o height: (number) height of the box
+ o cx: (number) x coordinate of the center of the box
+ o cy: (number) y coordinate of the center of the box
+ o }
+ \*/
+ var pathDimensions = R.pathBBox = function(path) {
+ var pth = paths(path);
+ if (pth.bbox) {
+ return pth.bbox;
+ }
+ if (!path) {
+ return {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+ x2: 0,
+ y2: 0
+ };
+ }
+ path = path2curve(path);
+ var x = 0,
+ y = 0,
+ X = [],
+ Y = [],
+ p;
+ for (var i = 0, ii = path.length; i < ii; i++) {
+ p = path[i];
+ if (p[0] == "M") {
+ x = p[1];
+ y = p[2];
+ X.push(x);
+ Y.push(y);
+ } else {
+ var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+ X = X[concat](dim.min.x, dim.max.x);
+ Y = Y[concat](dim.min.y, dim.max.y);
+ x = p[5];
+ y = p[6];
+ }
+ }
+ var xmin = mmin[apply](0, X),
+ ymin = mmin[apply](0, Y),
+ xmax = mmax[apply](0, X),
+ ymax = mmax[apply](0, Y),
+ bb = {
+ x: xmin,
+ y: ymin,
+ x2: xmax,
+ y2: ymax,
+ width: xmax - xmin,
+ height: ymax - ymin
+ };
+ pth.bbox = clone(bb);
+ return bb;
+ },
+ pathClone = function(pathArray) {
+ var res = clone(pathArray);
+ res.toString = R._path2string;
+ return res;
+ },
+ pathToRelative = R._pathToRelative = function(pathArray) {
+ var pth = paths(pathArray);
+ if (pth.rel) {
+ return pathClone(pth.rel);
+ }
+ if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
+ pathArray = R.parsePathString(pathArray);
+ }
+ var res = [],
+ x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ start = 0;
+ if (pathArray[0][0] == "M") {
+ x = pathArray[0][1];
+ y = pathArray[0][2];
+ mx = x;
+ my = y;
+ start++;
+ res.push(["M", x, y]);
+ }
+ for (var i = start, ii = pathArray.length; i < ii; i++) {
+ var r = res[i] = [],
+ pa = pathArray[i];
+ if (pa[0] != lowerCase.call(pa[0])) {
+ r[0] = lowerCase.call(pa[0]);
+ switch (r[0]) {
+ case "a":
+ r[1] = pa[1];
+ r[2] = pa[2];
+ r[3] = pa[3];
+ r[4] = pa[4];
+ r[5] = pa[5];
+ r[6] = +(pa[6] - x).toFixed(3);
+ r[7] = +(pa[7] - y).toFixed(3);
+ break;
+ case "v":
+ r[1] = +(pa[1] - y).toFixed(3);
+ break;
+ case "m":
+ mx = pa[1];
+ my = pa[2];
+ default:
+ for (var j = 1, jj = pa.length; j < jj; j++) {
+ r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
+ }
+ }
+ } else {
+ r = res[i] = [];
+ if (pa[0] == "m") {
+ mx = pa[1] + x;
+ my = pa[2] + y;
+ }
+ for (var k = 0, kk = pa.length; k < kk; k++) {
+ res[i][k] = pa[k];
+ }
+ }
+ var len = res[i].length;
+ switch (res[i][0]) {
+ case "z":
+ x = mx;
+ y = my;
+ break;
+ case "h":
+ x += +res[i][len - 1];
+ break;
+ case "v":
+ y += +res[i][len - 1];
+ break;
+ default:
+ x += +res[i][len - 2];
+ y += +res[i][len - 1];
+ }
+ }
+ res.toString = R._path2string;
+ pth.rel = pathClone(res);
+ return res;
+ },
+ pathToAbsolute = R._pathToAbsolute = function(pathArray) {
+ var pth = paths(pathArray), res;
+ if (pth.abs) {
+ return pathClone(pth.abs);
+ }
+ if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
+ pathArray = R.parsePathString(pathArray);
+ }
+ if (!pathArray || !pathArray.length) {
+ res = ["M", 0, 0];
+ res.toString = R._path2string;
+ return res;
+ }
+ var x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ start = 0;
+ res = [];
+ if (pathArray[0][0] == "M") {
+ x = +pathArray[0][1];
+ y = +pathArray[0][2];
+ mx = x;
+ my = y;
+ start++;
+ res[0] = ["M", x, y];
+ }
+ var crz = pathArray.length == 3 && pathArray[0][0] == "M" && pathArray[1][0].toUpperCase() == "R" && pathArray[2][0].toUpperCase() == "Z";
+ for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
+ res.push(r = []);
+ pa = pathArray[i];
+ if (pa[0] != upperCase.call(pa[0])) {
+ r[0] = upperCase.call(pa[0]);
+ switch (r[0]) {
+ case "A":
+ r[1] = pa[1];
+ r[2] = pa[2];
+ r[3] = pa[3];
+ r[4] = pa[4];
+ r[5] = pa[5];
+ r[6] = +(pa[6] + x);
+ r[7] = +(pa[7] + y);
+ break;
+ case "V":
+ r[1] = +pa[1] + y;
+ break;
+ case "H":
+ r[1] = +pa[1] + x;
+ break;
+ case "R":
+ var dots = [x, y][concat](pa.slice(1));
+ for (var j = 2, jj = dots.length; j < jj; j++) {
+ dots[j] = +dots[j] + x;
+ dots[++j] = +dots[j] + y;
+ }
+ res.pop();
+ res = res[concat](catmullRom2bezier(dots, crz));
+ break;
+ case "M":
+ mx = +pa[1] + x;
+ my = +pa[2] + y;
+ default:
+ for (j = 1, jj = pa.length; j < jj; j++) {
+ r[j] = +pa[j] + ((j % 2) ? x : y);
+ }
+ }
+ } else if (pa[0] == "R") {
+ dots = [x, y][concat](pa.slice(1));
+ res.pop();
+ res = res[concat](catmullRom2bezier(dots, crz));
+ r = ["R"][concat](pa.slice(-2));
+ } else {
+ for (var k = 0, kk = pa.length; k < kk; k++) {
+ r[k] = pa[k];
+ }
+ }
+ switch (r[0]) {
+ case "Z":
+ x = mx;
+ y = my;
+ break;
+ case "H":
+ x = r[1];
+ break;
+ case "V":
+ y = r[1];
+ break;
+ case "M":
+ mx = r[r.length - 2];
+ my = r[r.length - 1];
+ default:
+ x = r[r.length - 2];
+ y = r[r.length - 1];
+ }
+ }
+ res.toString = R._path2string;
+ pth.abs = pathClone(res);
+ return res;
+ },
+ l2c = function(x1, y1, x2, y2) {
+ return [x1, y1, x2, y2, x2, y2];
+ },
+ q2c = function(x1, y1, ax, ay, x2, y2) {
+ var _13 = 1 / 3,
+ _23 = 2 / 3;
+ return [
+ _13 * x1 + _23 * ax,
+ _13 * y1 + _23 * ay,
+ _13 * x2 + _23 * ax,
+ _13 * y2 + _23 * ay,
+ x2,
+ y2
+ ];
+ },
+ a2c = function(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
+ // for more information of where this math came from visit:
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+ var _120 = PI * 120 / 180,
+ rad = deg2rad * (+angle || 0),
+ res = [],
+ xy,
+ rotate = cacher(function(x, y, rad) {
+ var X = x * mathCos(rad) - y * mathSin(rad),
+ Y = x * mathSin(rad) + y * mathCos(rad);
+ return {
+ x: X,
+ y: Y
+ };
+ });
+ if (!recursive) {
+ xy = rotate(x1, y1, -rad);
+ x1 = xy.x;
+ y1 = xy.y;
+ xy = rotate(x2, y2, -rad);
+ x2 = xy.x;
+ y2 = xy.y;
+ var cos = mathCos(deg2rad * angle),
+ sin = mathSin(deg2rad * angle),
+ x = (x1 - x2) / 2,
+ y = (y1 - y2) / 2;
+ var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
+ if (h > 1) {
+ h = mathSqrt(h);
+ rx = h * rx;
+ ry = h * ry;
+ }
+ var rx2 = rx * rx,
+ ry2 = ry * ry,
+ k = (large_arc_flag == sweep_flag ? -1 : 1) *
+ mathSqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
+ cx = k * rx * y / ry + (x1 + x2) / 2,
+ cy = k * -ry * x / rx + (y1 + y2) / 2,
+ f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
+ f2 = math.asin(((y2 - cy) / ry).toFixed(9));
+
+ f1 = x1 < cx ? PI - f1 : f1;
+ f2 = x2 < cx ? PI - f2 : f2;
+ f1 < 0 && (f1 = PI * 2 + f1);
+ f2 < 0 && (f2 = PI * 2 + f2);
+ if (sweep_flag && f1 > f2) {
+ f1 = f1 - PI * 2;
+ }
+ if (!sweep_flag && f2 > f1) {
+ f2 = f2 - PI * 2;
+ }
+ } else {
+ f1 = recursive[0];
+ f2 = recursive[1];
+ cx = recursive[2];
+ cy = recursive[3];
+ }
+ var df = f2 - f1;
+ if (abs(df) > _120) {
+ var f2old = f2,
+ x2old = x2,
+ y2old = y2;
+ f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
+ x2 = cx + rx * mathCos(f2);
+ y2 = cy + ry * mathSin(f2);
+ res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
+ }
+ df = f2 - f1;
+ var c1 = mathCos(f1),
+ s1 = mathSin(f1),
+ c2 = mathCos(f2),
+ s2 = mathSin(f2),
+ t = math.tan(df / 4),
+ hx = 4 / 3 * rx * t,
+ hy = 4 / 3 * ry * t,
+ m1 = [x1, y1],
+ m2 = [x1 + hx * s1, y1 - hy * c1],
+ m3 = [x2 + hx * s2, y2 - hy * c2],
+ m4 = [x2, y2];
+ m2[0] = 2 * m1[0] - m2[0];
+ m2[1] = 2 * m1[1] - m2[1];
+ if (recursive) {
+ return [m2, m3, m4][concat](res);
+ } else {
+ res = [m2, m3, m4][concat](res).join()[split](",");
+ var newres = [];
+ for (var i = 0, ii = res.length; i < ii; i++) {
+ newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
+ }
+ return newres;
+ }
+ },
+ findDotAtSegment = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+ var t1 = 1 - t;
+ return {
+ x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
+ y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
+ };
+ },
+ curveDim = cacher(function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
+ var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
+ b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
+ c = p1x - c1x,
+ t1 = (-b + mathSqrt(b * b - 4 * a * c)) / 2 / a,
+ t2 = (-b - mathSqrt(b * b - 4 * a * c)) / 2 / a,
+ y = [p1y, p2y],
+ x = [p1x, p2x],
+ dot;
+ abs(t1) > "1e12" && (t1 = .5);
+ abs(t2) > "1e12" && (t2 = .5);
+ if (t1 > 0 && t1 < 1) {
+ dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ if (t2 > 0 && t2 < 1) {
+ dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
+ b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
+ c = p1y - c1y;
+ t1 = (-b + mathSqrt(b * b - 4 * a * c)) / 2 / a;
+ t2 = (-b - mathSqrt(b * b - 4 * a * c)) / 2 / a;
+ abs(t1) > "1e12" && (t1 = .5);
+ abs(t2) > "1e12" && (t2 = .5);
+ if (t1 > 0 && t1 < 1) {
+ dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ if (t2 > 0 && t2 < 1) {
+ dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ return {
+ min: {
+ x: mmin[apply](0, x),
+ y: mmin[apply](0, y)
+ },
+ max: {
+ x: mmax[apply](0, x),
+ y: mmax[apply](0, y)
+ }
+ };
+ }),
+ path2curve = R._path2curve = cacher(function(path, path2) {
+ var pth = !path2 && paths(path);
+ if (!path2 && pth.curve) {
+ return pathClone(pth.curve);
+ }
+ var p = pathToAbsolute(path),
+ p2 = path2 && pathToAbsolute(path2),
+ attrs = {
+ x: 0,
+ y: 0,
+ bx: 0,
+ by: 0,
+ X: 0,
+ Y: 0,
+ qx: null,
+ qy: null
+ },
+ attrs2 = {
+ x: 0,
+ y: 0,
+ bx: 0,
+ by: 0,
+ X: 0,
+ Y: 0,
+ qx: null,
+ qy: null
+ },
+ processPath = function(path, d) {
+ var nx, ny;
+ if (!path) {
+ return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
+ }
+ !(path[0] in {
+ T: 1,
+ Q: 1
+ }) && (d.qx = d.qy = null);
+ switch (path[0]) {
+ case "M":
+ d.X = path[1];
+ d.Y = path[2];
+ break;
+ case "A":
+ path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1))));
+ break;
+ case "S":
+ nx = d.x + (d.x - (d.bx || d.x));
+ ny = d.y + (d.y - (d.by || d.y));
+ path = ["C", nx, ny][concat](path.slice(1));
+ break;
+ case "T":
+ d.qx = d.x + (d.x - (d.qx || d.x));
+ d.qy = d.y + (d.y - (d.qy || d.y));
+ path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
+ break;
+ case "Q":
+ d.qx = path[1];
+ d.qy = path[2];
+ path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
+ break;
+ case "L":
+ path = ["C"][concat](l2c(d.x, d.y, path[1], path[2]));
+ break;
+ case "H":
+ path = ["C"][concat](l2c(d.x, d.y, path[1], d.y));
+ break;
+ case "V":
+ path = ["C"][concat](l2c(d.x, d.y, d.x, path[1]));
+ break;
+ case "Z":
+ path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y));
+ break;
+ }
+ return path;
+ },
+ fixArc = function(pp, i) {
+ if (pp[i].length > 7) {
+ pp[i].shift();
+ var pi = pp[i];
+ while (pi.length) {
+ pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6)));
+ }
+ pp.splice(i, 1);
+ ii = mmax(p.length, p2 && p2.length || 0);
+ }
+ },
+ fixM = function(path1, path2, a1, a2, i) {
+ if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
+ path2.splice(i, 0, ["M", a2.x, a2.y]);
+ a1.bx = 0;
+ a1.by = 0;
+ a1.x = path1[i][1];
+ a1.y = path1[i][2];
+ ii = mmax(p.length, p2 && p2.length || 0);
+ }
+ };
+ for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
+ p[i] = processPath(p[i], attrs);
+ fixArc(p, i);
+ p2 && (p2[i] = processPath(p2[i], attrs2));
+ p2 && fixArc(p2, i);
+ fixM(p, p2, attrs, attrs2, i);
+ fixM(p2, p, attrs2, attrs, i);
+ var seg = p[i],
+ seg2 = p2 && p2[i],
+ seglen = seg.length,
+ seg2len = p2 && seg2.length;
+ attrs.x = seg[seglen - 2];
+ attrs.y = seg[seglen - 1];
+ attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
+ attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
+ attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
+ attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
+ attrs2.x = p2 && seg2[seg2len - 2];
+ attrs2.y = p2 && seg2[seg2len - 1];
+ }
+ if (!p2) {
+ pth.curve = pathClone(p);
+ }
+ return p2 ? [p, p2] : p;
+ }, null, pathClone),
+ parseDots = R._parseDots = cacher(function(gradient) {
+ var dots = [];
+ for (var i = 0, ii = gradient.length; i < ii; i++) {
+ var dot = {},
+ par = gradient[i].match(/^([^:]*):?([\d\.]*)/);
+ dot.color = R.getRGB(par[1]);
+ if (dot.color.error) {
+ return null;
+ }
+ //store opacity information
+ dot.opacity = dot.color.opacity;
+ dot.color = dot.color.hex;
+ par[2] && (dot.offset = par[2] + "%");
+ dots.push(dot);
+ }
+ for (i = 1, ii = dots.length - 1; i < ii; i++) {
+ if (!dots[i].offset) {
+ var start = toFloat(dots[i - 1].offset || 0),
+ end = 0;
+ for (var j = i + 1; j < ii; j++) {
+ if (dots[j].offset) {
+ end = dots[j].offset;
+ break;
+ }
+ }
+ if (!end) {
+ end = 100;
+ j = ii;
+ }
+ end = toFloat(end);
+ var d = (end - start) / (j - i + 1);
+ for (; i < j; i++) {
+ start += d;
+ dots[i].offset = start + "%";
+ }
+ }
+ }
+ return dots;
+ }),
+ tear = R._tear = function(el, paper) {
+ el == paper.top && (paper.top = el.prev);
+ el == paper.bottom && (paper.bottom = el.next);
+ el.next && (el.next.prev = el.prev);
+ el.prev && (el.prev.next = el.next);
+ },
+ tofront = R._tofront = function(el, paper) {
+ if (paper.top === el) {
+ return false;
+ }
+ tear(el, paper);
+ el.next = null;
+ el.prev = paper.top;
+ paper.top.next = el;
+ paper.top = el;
+ return true;
+ },
+ toback = R._toback = function(el, paper) {
+ if (paper.bottom === el) {
+ return false;
+ }
+ tear(el, paper);
+ el.next = paper.bottom;
+ el.prev = null;
+ paper.bottom.prev = el;
+ paper.bottom = el;
+ return true;
+ },
+ insertafter = R._insertafter = function(el, el2, paper, paper2) {
+ tear(el, paper);
+ el.parent = paper2;
+ el2 === paper2.top && (paper2.top = el);
+ el2.next && (el2.next.prev = el);
+ el.next = el2.next;
+ el.prev = el2;
+ el2.next = el;
+ },
+ insertbefore = R._insertbefore = function(el, el2, paper, paper2) {
+ tear(el, paper);
+ el.parent = paper2;
+ el2 === paper2.bottom && (paper2.bottom = el);
+ el2.prev && (el2.prev.next = el);
+ el.prev = el2.prev;
+ el2.prev = el;
+ el.next = el2;
+ },
+
+ /*\
+ * Raphael.toMatrix
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns matrix of transformations applied to a given path
+ > Parameters
+ - path (string) path string
+ - transform (string|array) transformation string
+ = (object) @Matrix
+ \*/
+ toMatrix = R.toMatrix = function(path, transform) {
+ var bb = pathDimensions(path),
+ el = {
+ _: {
+ transform: E
+ },
+ getBBox: function() {
+ return bb;
+ }
+ };
+ extractTransform(el, transform);
+ return el.matrix;
+ },
+
+ /*\
+ * Raphael.transformPath
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns path transformed by a given transformation
+ > Parameters
+ - path (string) path string
+ - transform (string|array) transformation string
+ = (string) path
+ \*/
+ transformPath = R.transformPath = function(path, transform) {
+ return mapPath(path, toMatrix(path, transform));
+ },
+ extractTransform = R._extractTransform = function(el, tstr) {
+ if (tstr == null) {
+ return el._.transform;
+ }
+ tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
+ var tdata = R.parseTransformString(tstr),
+ deg = 0,
+ dx = 0,
+ dy = 0,
+ sx = 1,
+ sy = 1,
+ _ = el._,
+ m = new Matrix;
+ _.transform = tdata || [];
+ if (tdata) {
+ for (var i = 0, ii = tdata.length; i < ii; i++) {
+ var t = tdata[i],
+ tlen = t.length,
+ command = Str(t[0]).toLowerCase(),
+ absolute = t[0] != command,
+ inver = absolute ? m.invert() : 0,
+ x1,
+ y1,
+ x2,
+ y2,
+ bb;
+ if (command == "t" && tlen == 3) {
+ if (absolute) {
+ x1 = inver.x(0, 0);
+ y1 = inver.y(0, 0);
+ x2 = inver.x(t[1], t[2]);
+ y2 = inver.y(t[1], t[2]);
+ m.translate(x2 - x1, y2 - y1);
+ } else {
+ m.translate(t[1], t[2]);
+ }
+ } else if (command == "r") {
+ if (tlen == 2) {
+ bb = bb || el.getBBox(1);
+ m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
+ deg += t[1];
+ } else if (tlen == 4) {
+ if (absolute) {
+ x2 = inver.x(t[2], t[3]);
+ y2 = inver.y(t[2], t[3]);
+ m.rotate(t[1], x2, y2);
+ } else {
+ m.rotate(t[1], t[2], t[3]);
+ }
+ deg += t[1];
+ }
+ } else if (command == "s") {
+ if (tlen == 2 || tlen == 3) {
+ bb = bb || el.getBBox(1);
+ m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
+ sx *= t[1];
+ sy *= t[tlen - 1];
+ } else if (tlen == 5) {
+ if (absolute) {
+ x2 = inver.x(t[3], t[4]);
+ y2 = inver.y(t[3], t[4]);
+ m.scale(t[1], t[2], x2, y2);
+ } else {
+ m.scale(t[1], t[2], t[3], t[4]);
+ }
+ sx *= t[1];
+ sy *= t[2];
+ }
+ } else if (command == "m" && tlen == 7) {
+ m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
+ }
+ _.dirtyT = 1;
+ el.matrix = m;
+ }
+ }
+
+ /*\
+ * Element.matrix
+ [ property (object) ]
+ **
+ * Keeps @Matrix object, which represents element transformation
+ \*/
+ el.matrix = m;
+
+ _.sx = sx;
+ _.sy = sy;
+ _.deg = deg;
+ _.dx = dx = m.e;
+ _.dy = dy = m.f;
+
+ if (sx == 1 && sy == 1 && !deg && _.bbox) {
+ _.bbox.x += +dx;
+ _.bbox.y += +dy;
+ } else {
+ _.dirtyT = 1;
+ }
+ },
+ getEmpty = function(item) {
+ var l = item[0];
+ switch (l.toLowerCase()) {
+ case "t":
+ return [l, 0, 0];
+ case "m":
+ return [l, 1, 0, 0, 1, 0, 0];
+ case "r":
+ if (item.length == 4) {
+ return [l, 0, item[2], item[3]];
+ } else {
+ return [l, 0];
+ }
+ case "s":
+ if (item.length == 5) {
+ return [l, 1, 1, item[3], item[4]];
+ } else if (item.length == 3) {
+ return [l, 1, 1];
+ } else {
+ return [l, 1];
+ }
+ }
+ },
+ equaliseTransform = R._equaliseTransform = function(t1, t2) {
+ t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
+ t1 = R.parseTransformString(t1) || [];
+ t2 = R.parseTransformString(t2) || [];
+ var maxlength = mmax(t1.length, t2.length),
+ from = [],
+ to = [],
+ i = 0, j, jj,
+ tt1, tt2;
+ for (; i < maxlength; i++) {
+ tt1 = t1[i] || getEmpty(t2[i]);
+ tt2 = t2[i] || getEmpty(tt1);
+ if ((tt1[0] != tt2[0]) ||
+ (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
+ (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
+ ) {
+ return;
+ }
+ from[i] = [];
+ to[i] = [];
+ for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) {
+ j in tt1 && (from[i][j] = tt1[j]);
+ j in tt2 && (to[i][j] = tt2[j]);
+ }
+ }
+ return {
+ from: from,
+ to: to
+ };
+ };
+ R._getContainer = function(x, y, w, h) {
+ var container;
+ container = h == null && !R.is(x, object) ? g.doc.getElementById(x) : x;
+ if (container == null) {
+ return;
+ }
+ if (container.tagName) {
+ if (y == null) {
+ return {
+ container: container,
+ width: container.style.pixelWidth || container.offsetWidth,
+ height: container.style.pixelHeight || container.offsetHeight
+ };
+ } else {
+ return {
+ container: container,
+ width: y,
+ height: w
+ };
+ }
+ }
+ return {
+ container: 1,
+ x: x,
+ y: y,
+ width: w,
+ height: h
+ };
+ };
+
+ /*\
+ * Raphael.pathToRelative
+ [ method ]
+ **
+ * Utility method
+ **
+ * Converts path to relative form
+ > Parameters
+ - pathString (string|array) path string or array of segments
+ = (array) array of segments.
+ \*/
+ R.pathToRelative = pathToRelative;
+ R._engine = {};
+
+ /*\
+ * Raphael.path2curve
+ [ method ]
+ **
+ * Utility method
+ **
+ * Converts path to a new path where all segments are cubic bezier curves.
+ > Parameters
+ - pathString (string|array) path string or array of segments
+ = (array) array of segments.
+ \*/
+ R.path2curve = path2curve;
+
+ /*\
+ * Raphael.matrix
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns matrix based on given parameters.
+ > Parameters
+ - a (number)
+ - b (number)
+ - c (number)
+ - d (number)
+ - e (number)
+ - f (number)
+ = (object) @Matrix
+ \*/
+ R.matrix = function(a, b, c, d, e, f) {
+ return new Matrix(a, b, c, d, e, f);
+ };
+
+ function Matrix(a, b, c, d, e, f) {
+ if (a != null) {
+ this.a = +a;
+ this.b = +b;
+ this.c = +c;
+ this.d = +d;
+ this.e = +e;
+ this.f = +f;
+ } else {
+ this.a = 1;
+ this.b = 0;
+ this.c = 0;
+ this.d = 1;
+ this.e = 0;
+ this.f = 0;
+ }
+ }
+ (function(matrixproto) {
+
+ /*\
+ * Matrix.add
+ [ method ]
+ **
+ * Adds given matrix to existing one.
+ > Parameters
+ - a (number)
+ - b (number)
+ - c (number)
+ - d (number)
+ - e (number)
+ - f (number)
+ or
+ - matrix (object) @Matrix
+ \*/
+ matrixproto.add = function(a, b, c, d, e, f) {
+ var out = [[], [], []],
+ m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
+ matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
+ x, y, z, res;
+
+ if (a && a instanceof Matrix) {
+ matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
+ }
+
+ for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++) {
+ res = 0;
+ for (z = 0; z < 3; z++) {
+ res += m[x][z] * matrix[z][y];
+ }
+ out[x][y] = res;
+ }
+ }
+ this.a = out[0][0];
+ this.b = out[1][0];
+ this.c = out[0][1];
+ this.d = out[1][1];
+ this.e = out[0][2];
+ this.f = out[1][2];
+ };
+
+ /*\
+ * Matrix.invert
+ [ method ]
+ **
+ * Returns inverted version of the matrix
+ = (object) @Matrix
+ \*/
+ matrixproto.invert = function() {
+ var me = this,
+ x = me.a * me.d - me.b * me.c;
+ return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x);
+ };
+
+ /*\
+ * Matrix.clone
+ [ method ]
+ **
+ * Returns copy of the matrix
+ = (object) @Matrix
+ \*/
+ matrixproto.clone = function() {
+ return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
+ };
+
+ /*\
+ * Matrix.translate
+ [ method ]
+ **
+ * Translate the matrix
+ > Parameters
+ - x (number)
+ - y (number)
+ \*/
+ matrixproto.translate = function(x, y) {
+ this.add(1, 0, 0, 1, x, y);
+ };
+
+ /*\
+ * Matrix.scale
+ [ method ]
+ **
+ * Scales the matrix
+ > Parameters
+ - x (number)
+ - y (number) #optional
+ - cx (number) #optional
+ - cy (number) #optional
+ \*/
+ matrixproto.scale = function(x, y, cx, cy) {
+ y == null && (y = x);
+ (cx || cy) && this.add(1, 0, 0, 1, cx, cy);
+ this.add(x, 0, 0, y, 0, 0);
+ (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
+ };
+
+ /*\
+ * Matrix.rotate
+ [ method ]
+ **
+ * Rotates the matrix
+ > Parameters
+ - a (number)
+ - x (number)
+ - y (number)
+ \*/
+ matrixproto.rotate = function(a, x, y) {
+ a = R.rad(a);
+ x = x || 0;
+ y = y || 0;
+ var cos = +mathCos(a).toFixed(9),
+ sin = + mathSin(a).toFixed(9);
+ this.add(cos, sin, -sin, cos, x, y);
+ this.add(1, 0, 0, 1, -x, -y);
+ };
+
+ /*\
+ * Matrix.x
+ [ method ]
+ **
+ * Return x coordinate for given point after transformation described by the matrix. See also @Matrix.y
+ > Parameters
+ - x (number)
+ - y (number)
+ = (number) x
+ \*/
+ matrixproto.x = function(x, y) {
+ return x * this.a + y * this.c + this.e;
+ };
+
+ /*\
+ * Matrix.y
+ [ method ]
+ **
+ * Return y coordinate for given point after transformation described by the matrix. See also @Matrix.x
+ > Parameters
+ - x (number)
+ - y (number)
+ = (number) y
+ \*/
+ matrixproto.y = function(x, y) {
+ return x * this.b + y * this.d + this.f;
+ };
+ matrixproto.get = function(i) {
+ return +this[Str.fromCharCode(97 + i)].toFixed(4);
+ };
+ matrixproto.toString = function() {
+ return R.svg ?
+ "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" :
+ [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join();
+ };
+ matrixproto.toMatrixString = function() {
+ return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")";
+ };
+ matrixproto.toFilter = function() {
+ return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) +
+ ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) +
+ ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')";
+ };
+ matrixproto.offset = function() {
+ return [this.e.toFixed(4), this.f.toFixed(4)];
+ };
+ function norm(a) {
+ return a[0] * a[0] + a[1] * a[1];
+ }
+ function normalize(a) {
+ var mag = mathSqrt(norm(a));
+ a[0] && (a[0] /= mag);
+ a[1] && (a[1] /= mag);
+ }
+
+ /*\
+ * Matrix.split
+ [ method ]
+ **
+ * Splits matrix into primitive transformations
+ = (object) in format:
+ o dx (number) translation by x
+ o dy (number) translation by y
+ o scalex (number) scale by x
+ o scaley (number) scale by y
+ o shear (number) shear
+ o rotate (number) rotation in deg
+ o isSimple (boolean) could it be represented via simple transformations
+ \*/
+ matrixproto.split = function() {
+ var out = {};
+ // translation
+ out.dx = this.e;
+ out.dy = this.f;
+
+ // scale and shear
+ var row = [[this.a, this.c], [this.b, this.d]];
+ out.scalex = mathSqrt(norm(row[0]));
+ normalize(row[0]);
+
+ out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
+ row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
+
+ out.scaley = mathSqrt(norm(row[1]));
+ normalize(row[1]);
+ out.shear /= out.scaley;
+
+ // rotation
+ var sin = -row[0][1],
+ cos = row[1][1];
+ if (cos < 0) {
+ out.rotate = R.deg(math.acos(cos));
+ if (sin < 0) {
+ out.rotate = 360 - out.rotate;
+ }
+ } else {
+ out.rotate = R.deg(math.asin(sin));
+ }
+
+ out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
+ out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
+ out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
+ return out;
+ };
+
+ /*\
+ * Matrix.toTransformString
+ [ method ]
+ **
+ * Return transform string that represents given matrix
+ = (string) transform string
+ \*/
+ matrixproto.toTransformString = function(shorter) {
+ var s = shorter || this[split]();
+ if (s.isSimple) {
+ s.scalex = +s.scalex.toFixed(4);
+ s.scaley = +s.scaley.toFixed(4);
+ s.rotate = +s.rotate.toFixed(4);
+ return (s.dx || s.dy ? "t" + [s.dx, s.dy] : E) +
+ (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) +
+ (s.rotate ? "r" + [s.rotate, 0, 0] : E);
+ } else {
+ return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
+ }
+ };
+ })(Matrix.prototype);
+
+ // WebKit rendering bug workaround method
+ var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/);
+ if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") ||
+ (navigator.vendor == "Google Inc." && version && version[1] < 8)) {
+
+ /*\
+ * Paper.safari
+ [ method ]
+ **
+ * There is an inconvenient rendering bug in Safari (WebKit):
+ * sometimes the rendering should be forced.
+ * This method should help with dealing with this bug.
+ \*/
+ paperproto.safari = function() {
+ var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({
+ stroke: "none"
+ });
+ setTimeout(function() {
+ rect.remove();
+ });
+ return true;
+ };
+ } else {
+ paperproto.safari = fun;
+ }
+
+ var preventDefault = function() {
+ this.returnValue = false;
+ },
+ preventTouch = function() {
+ return this.originalEvent.preventDefault();
+ },
+ stopPropagation = function() {
+ this.cancelBubble = true;
+ },
+ stopTouch = function() {
+ return this.originalEvent.stopPropagation();
+ },
+ addEvent = R.addEvent = (function() {
+ if (g.doc.addEventListener) {
+ return function(obj, type, fn, element) {
+ var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
+ f = function(e) {
+ var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
+ if (supportsTouch && touchMap[has](type)) {
+ for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
+ if (e.targetTouches[i].target == obj) {
+ var olde = e;
+ e = e.targetTouches[i];
+ e.originalEvent = olde;
+ e.preventDefault = preventTouch;
+ e.stopPropagation = stopTouch;
+ break;
+ }
+ }
+ }
+ return fn.call(element, e, e.clientX + scrollX, e.clientY + scrollY);
+ };
+ obj.addEventListener(realName, f, false);
+ return function() {
+ obj.removeEventListener(realName, f, false);
+ return true;
+ };
+ };
+ } else if (g.doc.attachEvent) {
+ return function(obj, type, fn, element) {
+ var f = function(e) {
+ e = e || g.win.event;
+ var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
+ x = e.clientX + scrollX,
+ y = e.clientY + scrollY;
+ e.preventDefault = e.preventDefault || preventDefault;
+ e.stopPropagation = e.stopPropagation || stopPropagation;
+ return fn.call(element, e, x, y);
+ };
+ obj.attachEvent("on" + type, f);
+ var detacher = function() {
+ obj.detachEvent("on" + type, f);
+ return true;
+ };
+ return detacher;
+ };
+ }
+ })(),
+ drag = [],
+ dragMove = function(e) {
+ var x = e.clientX,
+ y = e.clientY,
+ scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
+ dragi,
+ j = drag.length;
+ while (j--) {
+ dragi = drag[j];
+ if (supportsTouch) {
+ var i = e.touches.length,
+ touch;
+ while (i--) {
+ touch = e.touches[i];
+ if (touch.identifier == dragi.el._drag.id) {
+ x = touch.clientX;
+ y = touch.clientY;
+ (e.originalEvent ? e.originalEvent : e).preventDefault();
+ break;
+ }
+ }
+ } else {
+ e.preventDefault();
+ }
+ var node = dragi.el.node,
+ o,
+ next = node.nextSibling,
+ parent = node.parentNode,
+ display = node.style.display;
+ g.win.opera && parent.removeChild(node);
+ node.style.display = "none";
+ o = dragi.el.paper.getElementByPoint(x, y);
+ node.style.display = display;
+ g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
+ o && eve("raphael.drag.over." + dragi.el.id, dragi.el, o);
+ x += scrollX;
+ y += scrollY;
+ eve("raphael.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
+ }
+ },
+ dragUp = function(e) {
+ R.unmousemove(dragMove).unmouseup(dragUp);
+ var i = drag.length,
+ dragi;
+ while (i--) {
+ dragi = drag[i];
+ dragi.el._drag = {};
+ eve("raphael.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
+ }
+ drag = [];
+ },
+
+ /*\
+ * Raphael.el
+ [ property (object) ]
+ **
+ * You can add your own method to elements. This is usefull when you want to hack default functionality or
+ * want to wrap some common transformation or attributes in one method. In difference to canvas methods,
+ * you can redefine element method at any time. Expending element methods wouldn’t affect set.
+ > Usage
+ | Raphael.el.red = function () {
+ | this.attr({fill: "#f00"});
+ | };
+ | // then use it
+ | paper.circle(100, 100, 20).red();
+ \*/
+ elproto = R.el = {};
+
+ /*\
+ * Element.click
+ [ method ]
+ **
+ * Adds event handler for click for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unclick
+ [ method ]
+ **
+ * Removes event handler for click for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.dblclick
+ [ method ]
+ **
+ * Adds event handler for double click for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.undblclick
+ [ method ]
+ **
+ * Removes event handler for double click for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mousedown
+ [ method ]
+ **
+ * Adds event handler for mousedown for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmousedown
+ [ method ]
+ **
+ * Removes event handler for mousedown for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mousemove
+ [ method ]
+ **
+ * Adds event handler for mousemove for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmousemove
+ [ method ]
+ **
+ * Removes event handler for mousemove for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseout
+ [ method ]
+ **
+ * Adds event handler for mouseout for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseout
+ [ method ]
+ **
+ * Removes event handler for mouseout for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseover
+ [ method ]
+ **
+ * Adds event handler for mouseover for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseover
+ [ method ]
+ **
+ * Removes event handler for mouseover for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseup
+ [ method ]
+ **
+ * Adds event handler for mouseup for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseup
+ [ method ]
+ **
+ * Removes event handler for mouseup for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchstart
+ [ method ]
+ **
+ * Adds event handler for touchstart for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchstart
+ [ method ]
+ **
+ * Removes event handler for touchstart for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchmove
+ [ method ]
+ **
+ * Adds event handler for touchmove for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchmove
+ [ method ]
+ **
+ * Removes event handler for touchmove for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchend
+ [ method ]
+ **
+ * Adds event handler for touchend for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchend
+ [ method ]
+ **
+ * Removes event handler for touchend for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchcancel
+ [ method ]
+ **
+ * Adds event handler for touchcancel for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchcancel
+ [ method ]
+ **
+ * Removes event handler for touchcancel for the element.
+ > Parameters
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ for (var i = events.length; i--; ) {
+ (function(eventName) {
+ R[eventName] = elproto[eventName] = function(fn, scope) {
+ if (R.is(fn, "function")) {
+ this.events = this.events || [];
+ this.events.push({
+ name: eventName,
+ f: fn,
+ unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)
+ });
+ }
+ return this;
+ };
+ R["un" + eventName] = elproto["un" + eventName] = function(fn) {
+ var events = this.events || [],
+ l = events.length;
+ while (l--)
+ if (events[l].name == eventName && events[l].f == fn) {
+ events[l].unbind();
+ events.splice(l, 1);
+ !events.length && delete this.events;
+ return this;
+ }
+ return this;
+ };
+ })(events[i]);
+ }
+
+ /*\
+ * Element.data
+ [ method ]
+ **
+ * Adds or retrieves given value asociated with given key.
+ **
+ * See also @Element.removeData
+ > Parameters
+ - key (string) key to store data
+ - value (any) #optional value to store
+ = (object) @Element
+ * or, if value is not specified:
+ = (any) value
+ > Usage
+ | for (var i = 0, i < 5, i++) {
+ | paper.circle(10 + 15 * i, 10, 10)
+ | .attr({fill: "#000"})
+ | .data("i", i)
+ | .click(function () {
+ | alert(this.data("i"));
+ | });
+ | }
+ \*/
+ elproto.data = function(key, value) {
+ var data = eldata[this.id] = eldata[this.id] || {};
+ if (arguments.length == 1) {
+ if (R.is(key, object)) {
+ for (var i in key)
+ if (key[has](i)) {
+ this.data(i, key[i]);
+ }
+ return this;
+ }
+ eve("raphael.data.get." + this.id, this, data[key], key);
+ return data[key];
+ }
+ data[key] = value;
+ eve("raphael.data.set." + this.id, this, value, key);
+ return this;
+ };
+
+ /*\
+ * Element.removeData
+ [ method ]
+ **
+ * Removes value associated with an element by given key.
+ * If key is not provided, removes all the data of the element.
+ > Parameters
+ - key (string) #optional key
+ = (object) @Element
+ \*/
+ elproto.removeData = function(key) {
+ if (key == null) {
+ eldata[this.id] = {};
+ } else {
+ eldata[this.id] && delete eldata[this.id][key];
+ }
+ return this;
+ };
+
+ /*\
+ * Element.getData
+ [ method ]
+ **
+ * Retrieves the element data
+ = (object) data
+ \*/
+ elproto.getData = function () {
+ return clone(eldata[this.id] || {});
+ };
+
+ var downables = [],
+ mouseDown = function () {
+ this.untrack = addEvent(g.doc, 'mouseup', mouseUp, this);
+ },
+ mouseUp = function () {
+ this.untrack();
+ this.untrack = null;
+ return this.fn && this.fn.apply(this.scope || this.el, arguments);
+
+ };
+ elproto.mouseup = function (fn, scope, track) {
+ if (!track) {
+ return R.mouseup.apply(this, arguments);
+ }
+ downables.push(track = {
+ el: this,
+ fn: fn,
+ scope: scope
+ });
+ track.unbind = addEvent(this.shape || this.node || g.doc,
+ 'mousedown', mouseDown, track);
+
+ return this;
+ };
+
+ elproto.unmouseup = function (fn) {
+ var i = downables.length,
+ undowned;
+ while (i--) {
+ if (downables[i].el === this && downables[i].fn === fn) {
+ undowned = downables[i];
+ undowned.unbind();
+ undowned.untrack && undowned.untrack();
+ downables.splice(i, 1);
+ }
+ }
+ return undowned ? this : R.unmouseup.apply(this, arguments);
+ };
+
+ /*\
+ * Element.hover
+ [ method ]
+ **
+ * Adds event handlers for hover for the element.
+ > Parameters
+ - f_in (function) handler for hover in
+ - f_out (function) handler for hover out
+ - icontext (object) #optional context for hover in handler
+ - ocontext (object) #optional context for hover out handler
+ = (object) @Element
+ \*/
+ elproto.hover = function(f_in, f_out, scope_in, scope_out) {
+ return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
+ };
+
+ /*\
+ * Element.unhover
+ [ method ]
+ **
+ * Removes event handlers for hover for the element.
+ > Parameters
+ - f_in (function) handler for hover in
+ - f_out (function) handler for hover out
+ = (object) @Element
+ \*/
+ elproto.unhover = function(f_in, f_out) {
+ return this.unmouseover(f_in).unmouseout(f_out);
+ };
+ var draggable = [];
+
+ /*\
+ * Element.drag
+ [ method ]
+ **
+ * Adds event handlers for drag of the element.
+ > Parameters
+ - onmove (function) handler for moving
+ - onstart (function) handler for drag start
+ - onend (function) handler for drag end
+ - mcontext (object) #optional context for moving handler
+ - scontext (object) #optional context for drag start handler
+ - econtext (object) #optional context for drag end handler
+ * Additionaly following `drag` events will be triggered: `drag.start.` on start,
+ * `drag.end.` on end and `drag.move.` on every move. When element will be dragged over another element
+ * `drag.over.` will be fired as well.
+ *
+ * Start event and start handler will be called in specified context or in context of the element with following parameters:
+ o x (number) x position of the mouse
+ o y (number) y position of the mouse
+ o event (object) DOM event object
+ * Move event and move handler will be called in specified context or in context of the element with following parameters:
+ o dx (number) shift by x from the start point
+ o dy (number) shift by y from the start point
+ o x (number) x position of the mouse
+ o y (number) y position of the mouse
+ o event (object) DOM event object
+ * End event and end handler will be called in specified context or in context of the element with following parameters:
+ o event (object) DOM event object
+ = (object) @Element
+ \*/
+ elproto.drag = function(onmove, onstart, onend, move_scope, start_scope, end_scope) {
+ function start(e) {
+ (e.originalEvent || e).preventDefault();
+ var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+ scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
+ this._drag.x = e.clientX + scrollX;
+ this._drag.y = e.clientY + scrollY;
+ this._drag.id = e.identifier;
+ !drag.length && R.mousemove(dragMove).mouseup(dragUp);
+ drag.push({
+ el: this,
+ move_scope: move_scope,
+ start_scope: start_scope,
+ end_scope: end_scope
+ });
+ onstart && eve.on("raphael.drag.start." + this.id, onstart);
+ onmove && eve.on("raphael.drag.move." + this.id, onmove);
+ onend && eve.on("raphael.drag.end." + this.id, onend);
+ eve("raphael.drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
+ }
+ this._drag = {};
+ draggable.push({
+ el: this,
+ start: start
+ });
+ this.mousedown(start);
+ return this;
+ };
+
+ /*\
+ * Element.onDragOver
+ [ method ]
+ **
+ * Shortcut for assigning event handler for `drag.over.` event, where id is id of the element (see @Element.id).
+ > Parameters
+ - f (function) handler for event, first argument would be the element you are dragging over
+ \*/
+ elproto.onDragOver = function(f) {
+ f ? eve.on("raphael.drag.over." + this.id, f) : eve.unbind("raphael.drag.over." + this.id);
+ };
+
+ /*\
+ * Element.undrag
+ [ method ]
+ **
+ * Removes all drag event handlers from given element.
+ \*/
+ elproto.undrag = function() {
+ var i = draggable.length;
+ while (i--)
+ if (draggable[i].el == this) {
+ this.unmousedown(draggable[i].start);
+ draggable.splice(i, 1);
+ eve.unbind("raphael.drag.*." + this.id);
+ }
+ !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp);
+ };
+
+ elproto.follow = function(el, callback, stalk) {
+ if (el.removed || el.constructor !== R.el.constructor) {
+ return this;
+ }
+ el.followers.push({
+ el: this,
+ stalk: (stalk = {before: 'insertBefore', after: 'insertAfter'}[stalk]),
+ cb: callback
+ });
+
+ stalk && this[stalk](el);
+ return this;
+ };
+
+ elproto.unfollow = function(el) {
+ if (el.removed || el.constructor !== R.el.constructor) {
+ return this;
+ }
+ for (var i = 0, ii = el.followers.length; i < ii; i++) {
+ if (el.followers[i].el === this) {
+ el.followers.splice(i, 1);
+ break;
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Paper.hide
+ [ method ]
+ **
+ * Hides a paper
+ **
+ > Usage
+ | paper.hide();
+ \*/
+ paperproto.hide = function () {
+ var paper = this;
+ paper.canvas.style.visibility = "hidden";
+ return paper;
+ };
+
+ /*\
+ * Paper.show
+ [ method ]
+ **
+ * Shows a hidden paper
+ **
+ > Usage
+ | paper.show();
+ \*/
+ paperproto.show = function () {
+ var paper = this;
+ paper.canvas.style.visibility = E;
+ return paper;
+ };
+
+ /*\
+ * Paper.group
+ [ method ]
+ **
+ * Creates a group
+ **
+ > Parameters
+ **
+ - id (number) id of the group
+ = (object) Raphaël element object with type “group”
+ **
+ > Usage
+ | var g = paper.group();
+ \*/
+ paperproto.group = function () { // id
+ var paper = this,
+ out,
+ args = arguments,
+ group = lastArgIfGroup(args, true);
+
+ out = R._engine.group(paper, args[0], group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.circle
+ [ method ]
+ **
+ * Draws a circle.
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the centre
+ - y (number) y coordinate of the centre
+ - r (number) radius
+ = (object) Raphaël element object with type “circle”
+ **
+ > Usage
+ | var c = paper.circle(50, 50, 40);
+ \*/
+ paperproto.circle = function () { // x, y, r
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.circle(paper, args[0] || 0, args[1] || 0,
+ args[2] || 0, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+
+ /*\
+ * Paper.rect
+ [ method ]
+ *
+ * Draws a rectangle.
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the top left corner
+ - y (number) y coordinate of the top left corner
+ - width (number) width
+ - height (number) height
+ - r (number) #optional radius for rounded corners, default is 0
+ = (object) Raphaël element object with type “rect”
+ **
+ > Usage
+ | // regular rectangle
+ | var c = paper.rect(10, 10, 50, 50);
+ | // rectangle with rounded corners
+ | var c = paper.rect(40, 40, 50, 50, 10);
+ \*/
+ paperproto.rect = function () {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.rect(paper, args[0] || 0, args[1] || 0, args[2] || 0,
+ args[3] || 0, args[4] || 0, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.ellipse
+ [ method ]
+ **
+ * Draws an ellipse.
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the centre
+ - y (number) y coordinate of the centre
+ - rx (number) horizontal radius
+ - ry (number) vertical radius
+ = (object) Raphaël element object with type “ellipse”
+ **
+ > Usage
+ | var c = paper.ellipse(50, 50, 40, 20);
+ \*/
+ paperproto.ellipse = function () {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.ellipse(this, args[0] || 0, args[1] || 0,
+ args[2] || 0, args[3] || 0, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.path
+ [ method ]
+ **
+ * Creates a path element by given path data string.
+ > Parameters
+ - pathString (string) #optional path string in SVG format.
+ * Path string consists of one-letter commands, followed by comma seprarated arguments in numercal form. Example:
+ | "M10,20L30,40"
+ * Here we can see two commands: “M”, with arguments `(10, 20)` and “L” with arguments `(30, 40)`. Upper case letter mean command is absolute, lower case—relative.
+ *
+ # Here is short list of commands available, for more details see SVG path string format .
+ # Command Name Parameters
+ # M moveto (x y)+
+ # Z closepath (none)
+ # L lineto (x y)+
+ # H horizontal lineto x+
+ # V vertical lineto y+
+ # C curveto (x1 y1 x2 y2 x y)+
+ # S smooth curveto (x2 y2 x y)+
+ # Q quadratic Bézier curveto (x1 y1 x y)+
+ # T smooth quadratic Bézier curveto (x y)+
+ # A elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
+ # R Catmull-Rom curveto *x1 y1 (x y)+
+ * * “Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier.
+ * Note: there is a special case when path consist of just three commands: “M10,10R…z”. In this case path will smoothly connects to its beginning.
+ > Usage
+ | var c = paper.path("M10 10L90 90");
+ | // draw a diagonal line:
+ | // move to 10,10, line to 90,90
+ * For example of path strings, check out these icons: http://raphaeljs.com/icons/
+ \*/
+ paperproto.path = function () {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ pathString,
+ out;
+
+ pathString = args[0];
+ pathString && !R.is(pathString, string) &&
+ !R.is(pathString[0], array) && (pathString += E);
+
+ out = R._engine.path(R.format[apply](R, arguments), paper, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.image
+ [ method ]
+ **
+ * Embeds an image into the surface.
+ **
+ > Parameters
+ **
+ - src (string) URI of the source image
+ - x (number) x coordinate position
+ - y (number) y coordinate position
+ - width (number) width of the image
+ - height (number) height of the image
+ = (object) Raphaël element object with type “image”
+ **
+ > Usage
+ | var c = paper.image("apple.png", 10, 10, 80, 80);
+ \*/
+ paperproto.image = function () {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.image(paper, args[0] || "about:blank", args[1] || 0,
+ args[2] || 0, args[3] || 0, args[4] || 0, group);
+
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.text
+ [ method ]
+ **
+ * Draws a text string. If you need line breaks, put “\n” in the string.
+ **
+ > Parameters
+ **
+ - x (number) x coordinate position
+ - y (number) y coordinate position
+ - text (string) The text string to draw
+ = (object) Raphaël element object with type “text”
+ **
+ > Usage
+ | var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!");
+ \*/
+ paperproto.text = function() {
+ var paper = this,
+ args = arguments,
+ group = lastArgIfGroup(args, true),
+ out;
+
+ out = R._engine.text(paper, args[0] || 0, args[1] || 0, Str(args[2] || E),
+ group);
+ paper.__set__ && paper.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.set
+ [ method ]
+ **
+ * Creates array-like object to keep and operate several elements at once.
+ * Warning: it doesn’t create any elements for itself in the page, it just groups existing elements.
+ * Sets act as pseudo elements — all methods available to an element can be used on a set.
+ = (object) array-like object that represents set of elements
+ **
+ > Usage
+ | var st = paper.set();
+ | st.push(
+ | paper.circle(10, 10, 5),
+ | paper.circle(30, 10, 5)
+ | );
+ | st.attr({fill: "red"}); // changes the fill of both circles
+ \*/
+ paperproto.set = function(itemsArray) {
+ !R.is(itemsArray, "array") && (itemsArray = arraySplice.call(arguments, 0, arguments.length));
+ var out = new Set(itemsArray);
+ this.__set__ && this.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Paper.setStart
+ [ method ]
+ **
+ * Creates @Paper.set. All elements that will be created after calling this method and before calling
+ * @Paper.setFinish will be added to the set.
+ **
+ > Usage
+ | paper.setStart();
+ | paper.circle(10, 10, 5),
+ | paper.circle(30, 10, 5)
+ | var st = paper.setFinish();
+ | st.attr({fill: "red"}); // changes the fill of both circles
+ \*/
+ paperproto.setStart = function(set) {
+ this.__set__ = set || this.set();
+ };
+
+ /*\
+ * Paper.setFinish
+ [ method ]
+ **
+ * See @Paper.setStart. This method finishes catching and returns resulting set.
+ **
+ = (object) set
+ \*/
+ paperproto.setFinish = function(set) {
+ var out = this.__set__;
+ delete this.__set__;
+ return out;
+ };
+
+ /*\
+ * Paper.setSize
+ [ method ]
+ **
+ * If you need to change dimensions of the canvas call this method
+ **
+ > Parameters
+ **
+ - width (number) new width of the canvas
+ - height (number) new height of the canvas
+ \*/
+ paperproto.setSize = function(width, height) {
+ return R._engine.setSize.call(this, width, height);
+ };
+
+ /*\
+ * Paper.setViewBox
+ [ method ]
+ **
+ * Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by
+ * specifying new boundaries.
+ **
+ > Parameters
+ **
+ - x (number) new x position, default is `0`
+ - y (number) new y position, default is `0`
+ - w (number) new width of the canvas
+ - h (number) new height of the canvas
+ - fit (boolean) `true` if you want graphics to fit into new boundary box
+ \*/
+ paperproto.setViewBox = function(x, y, w, h, fit) {
+ return R._engine.setViewBox.call(this, x, y, w, h, fit);
+ };
+
+ /*\
+ * Paper.top
+ [ property ]
+ **
+ * Points to the topmost element on the paper
+ \*/
+ /*\
+ * Paper.bottom
+ [ property ]
+ **
+ * Points to the bottom element on the paper
+ \*/
+ paperproto.top = paperproto.bottom = null;
+
+ /*\
+ * Paper.raphael
+ [ property ]
+ **
+ * Points to the @Raphael object/function
+ \*/
+ paperproto.raphael = R;
+
+ var getOffset = function(elem) {
+ var box = elem.getBoundingClientRect(),
+ doc = elem.ownerDocument,
+ body = doc.body,
+ docElem = doc.documentElement,
+ clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop) - clientTop,
+ left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
+ return {
+ y: top,
+ x: left
+ };
+ };
+
+ /*\
+ * Paper.getElementByPoint
+ [ method ]
+ **
+ * Returns you topmost element under given point.
+ **
+ = (object) Raphaël element object
+ > Parameters
+ **
+ - x (number) x coordinate from the top left corner of the window
+ - y (number) y coordinate from the top left corner of the window
+ > Usage
+ | paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
+ \*/
+ paperproto.getElementByPoint = function(x, y) {
+ var paper = this,
+ svg = paper.canvas,
+ target = g.doc.elementFromPoint(x, y);
+ if (g.win.opera && target.tagName == "svg") {
+ var so = getOffset(svg),
+ sr = svg.createSVGRect();
+ sr.x = x - so.x;
+ sr.y = y - so.y;
+ sr.width = sr.height = 1;
+ var hits = svg.getIntersectionList(sr, null);
+ if (hits.length) {
+ target = hits[hits.length - 1];
+ }
+ }
+ if (!target) {
+ return null;
+ }
+ while (target.parentNode && target != svg.parentNode && !target.raphael) {
+ target = target.parentNode;
+ }
+ target == paper.canvas.parentNode && (target = svg);
+ target = target && target.raphael ? paper.getById(target.raphaelid) : null;
+ return target;
+ };
+
+ /*\
+ * Paper.getElementsByBBox
+ [ method ]
+ **
+ * Returns set of elements that have an intersecting bounding box
+ **
+ > Parameters
+ **
+ - bbox (object) bbox to check with
+ = (object) @Set
+ \*/
+ paperproto.getElementsByBBox = function (bbox) {
+ var set = this.set();
+ this.forEach(function (el) {
+ if (R.isBBoxIntersect(el.getBBox(), bbox)) {
+ set.push(el);
+ }
+ });
+ return set;
+ };
+
+ paperproto.getById = function(id) {
+ var bot = this.bottom;
+ while (bot) {
+ if (bot.id == id) {
+ return bot;
+ }
+ bot = bot.next;
+ }
+ return null;
+ };
+
+ /*\
+ * Paper.forEach
+ [ method ]
+ **
+ * Executes given function for each element on the paper
+ *
+ * If callback function returns `false` it will stop loop running.
+ **
+ > Parameters
+ **
+ - callback (function) function to run
+ - thisArg (object) context object for the callback
+ = (object) Paper object
+ > Usage
+ | paper.forEach(function (el) {
+ | el.attr({ stroke: "blue" });
+ | });
+ \*/
+ paperproto.forEach = function(callback, thisArg) {
+ var bot = this.bottom;
+ while (bot) {
+ if (callback.call(thisArg, bot) === false) {
+ return this;
+ }
+ bot = bot.next;
+ }
+ return this;
+ };
+
+ /*\
+ * Paper.getElementsByPoint
+ [ method ]
+ **
+ * Returns set of elements that have common point inside
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the point
+ - y (number) y coordinate of the point
+ = (object) @Set
+ \*/
+ paperproto.getElementsByPoint = function(x, y) {
+ var set = this.set();
+ this.forEach(function(el) {
+ if (el.isPointInside(x, y)) {
+ set.push(el);
+ }
+ });
+ return set;
+ };
+ function x_y() {
+ return this.x + S + this.y;
+ }
+ function x_y_w_h() {
+ return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
+ }
+
+ /*\
+ * Element.isPointInside
+ [ method ]
+ **
+ * Determine if given point is inside this element’s shape
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the point
+ - y (number) y coordinate of the point
+ = (boolean) `true` if point inside the shape
+ \*/
+ elproto.isPointInside = function(x, y) {
+ var rp = this.realPath = this.realPath || getPath[this.type](this),
+ tr;
+ return R.isPointInsidePath(((tr = this.attr('transform')) &&
+ tr.length && R.transformPath(rp, tr)) || rp, x, y);
+ };
+
+ /*\
+ * Element.getBBox
+ [ method ]
+ **
+ * Return bounding box for a given element
+ **
+ > Parameters
+ **
+ - isWithoutTransform (boolean) flag, `true` if you want to have bounding box before transformations. Default is `false`.
+ = (object) Bounding box object:
+ o {
+ o x: (number) top left corner x
+ o y: (number) top left corner y
+ o x2: (number) bottom right corner x
+ o y2: (number) bottom right corner y
+ o width: (number) width
+ o height: (number) height
+ o }
+ \*/
+ elproto.getBBox = function(isWithoutTransform) {
+ if (this.removed) {
+ return {};
+ }
+ var _ = this._;
+ if (isWithoutTransform) {
+ if (_.dirty || !_.bboxwt) {
+ this.realPath = getPath[this.type](this);
+ _.bboxwt = pathDimensions(this.realPath);
+ _.bboxwt.toString = x_y_w_h;
+ _.dirty = 0;
+ }
+ return _.bboxwt;
+ }
+ if (_.dirty || _.dirtyT || !_.bbox) {
+ if (_.dirty || !this.realPath) {
+ _.bboxwt = 0;
+ this.realPath = getPath[this.type](this);
+ }
+ _.bbox = pathDimensions(mapPath(this.realPath, this.matrix));
+ _.bbox.toString = x_y_w_h;
+ _.dirty = _.dirtyT = 0;
+ }
+ return _.bbox;
+ };
+
+ /*\
+ * Element.clone
+ [ method ]
+ **
+ = (object) clone of a given element
+ **
+ \*/
+ elproto.clone = function() {
+ if (this.removed) {
+ return null;
+ }
+ var o = this,
+ out = o.paper[o.type]().attr(o.attr());
+ o.__set__ && o.__set__.push(out);
+ return out;
+ };
+
+ /*\
+ * Element.glow
+ [ method ]
+ **
+ * Return set of elements that create glow-like effect around given element. See @Paper.set.
+ *
+ * Note: Glow is not connected to the element. If you change element attributes it won’t adjust itself.
+ **
+ > Parameters
+ **
+ - glow (object) #optional parameters object with all properties optional:
+ o {
+ o width (number) size of the glow, default is `10`
+ o fill (boolean) will it be filled, default is `false`
+ o opacity (number) opacity, default is `0.5`
+ o offsetx (number) horizontal offset, default is `0`
+ o offsety (number) vertical offset, default is `0`
+ o color (string) glow colour, default is `black`
+ o }
+ = (object) @Paper.set of elements that represents glow
+ \*/
+ elproto.glow = function(glow) {
+ if (this.type == "text") {
+ return null;
+ }
+ glow = glow || {};
+ var s = {
+ width: (glow.width || 10) + (+this.attr("stroke-width") || 1),
+ fill: glow.fill || false,
+ opacity: glow.opacity || .5,
+ offsetx: glow.offsetx || 0,
+ offsety: glow.offsety || 0,
+ color: glow.color || "#000"
+ },
+ c = s.width / 2,
+ r = this.paper,
+ out = r.set(),
+ path = this.realPath || getPath[this.type](this);
+ path = this.matrix ? mapPath(path, this.matrix) : path;
+ for (var i = 1; i < c + 1; i++) {
+ out.push(r.path(path).attr({
+ stroke: s.color,
+ fill: s.fill ? s.color : "none",
+ "stroke-linejoin": "round",
+ "stroke-linecap": "round",
+ "stroke-width": +(s.width / c * i).toFixed(3),
+ opacity: +(s.opacity / c).toFixed(3)
+ }));
+ }
+ return out.insertBefore(this).translate(s.offsetx, s.offsety);
+ };
+ var curveslengths = {},
+ getPointAtSegmentLength = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
+ if (length == null) {
+ return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
+ } else {
+ return R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, getTatLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length));
+ }
+ },
+ getLengthFactory = function(istotal, subpath) {
+ return function(path, length, onlystart) {
+ path = path2curve(path);
+ var x, y, p, l, sp = "", subpaths = {}, point,
+ len = 0;
+ for (var i = 0, ii = path.length; i < ii; i++) {
+ p = path[i];
+ if (p[0] == "M") {
+ x = +p[1];
+ y = +p[2];
+ } else {
+ l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+ if (len + l > length) {
+ if (subpath && !subpaths.start) {
+ point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
+ sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];
+ if (onlystart) {
+ return sp;
+ }
+ subpaths.start = sp;
+ sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join();
+ len += l;
+ x = +p[5];
+ y = +p[6];
+ continue;
+ }
+ if (!istotal && !subpath) {
+ point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
+ return {
+ x: point.x,
+ y: point.y,
+ alpha: point.alpha
+ };
+ }
+ }
+ len += l;
+ x = +p[5];
+ y = +p[6];
+ }
+ sp += p.shift() + p;
+ }
+ subpaths.end = sp;
+ point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
+ point.alpha && (point = {
+ x: point.x,
+ y: point.y,
+ alpha: point.alpha
+ });
+ return point;
+ };
+ };
+ var getTotalLength = getLengthFactory(1),
+ getPointAtLength = getLengthFactory(),
+ getSubpathsAtLength = getLengthFactory(0, 1);
+
+ R.getTotalLength = getTotalLength;
+
+ R.getPointAtLength = getPointAtLength;
+
+ R.getSubpath = function(path, from, to) {
+ if (this.getTotalLength(path) - to < 1e-6) {
+ return getSubpathsAtLength(path, from).end;
+ }
+ var a = getSubpathsAtLength(path, to, 1);
+ return from ? getSubpathsAtLength(a, from).end : a;
+ };
+
+ /*\
+ * Raphael.getTotalLength
+ [ method ]
+ **
+ * Returns length of the given path in pixels.
+ **
+ > Parameters
+ **
+ - path (string) SVG path string.
+ **
+ = (number) length.
+ \*/
+ elproto.getTotalLength = function() {
+ if (this.type != "path") {
+ return;
+ }
+ if (this.node.getTotalLength) {
+ return this.node.getTotalLength();
+ }
+ return getTotalLength(this.attrs.path);
+ };
+
+ /*\
+ * Raphael.getPointAtLength
+ [ method ]
+ **
+ * Return coordinates of the point located at the given length on the given path.
+ **
+ > Parameters
+ **
+ - path (string) SVG path string
+ - length (number)
+ **
+ = (object) representation of the point:
+ o {
+ o x: (number) x coordinate
+ o y: (number) y coordinate
+ o alpha: (number) angle of derivative
+ o }
+ \*/
+ elproto.getPointAtLength = function(length) {
+ if (this.type != "path") {
+ return;
+ }
+ return getPointAtLength(this.attrs.path, length);
+ };
+
+ /*\
+ * Raphael.getSubpath
+ [ method ]
+ **
+ * Return subpath of a given path from given length to given length.
+ **
+ > Parameters
+ **
+ - path (string) SVG path string
+ - from (number) position of the start of the segment
+ - to (number) position of the end of the segment
+ **
+ = (string) pathstring for the segment
+ \*/
+ elproto.getSubpath = function(from, to) {
+ if (this.type != "path") {
+ return;
+ }
+ return R.getSubpath(this.attrs.path, from, to);
+ };
+
+ /*\
+ * Raphael.easing_formulas
+ [ property ]
+ **
+ * Object that contains easing formulas for animation. You could extend it with your own. By default it has following list of easing:
+ #
+ # “linear”
+ # “<” or “easeIn” or “ease-in”
+ # “>” or “easeOut” or “ease-out”
+ # “<>” or “easeInOut” or “ease-in-out”
+ # “backIn” or “back-in”
+ # “backOut” or “back-out”
+ # “elastic”
+ # “bounce”
+ #
+ # See also Easing demo .
+ \*/
+ var ef = R.easing_formulas = {
+ linear: function(n) {
+ return n;
+ },
+ "<": function(n) {
+ return pow(n, 1.7);
+ },
+ ">": function(n) {
+ return pow(n, .48);
+ },
+ "<>": function(n) {
+ var q = .48 - n / 1.04,
+ Q = mathSqrt(.1734 + q * q),
+ x = Q - q,
+ X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
+ y = -Q - q,
+ Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
+ t = X + Y + .5;
+ return (1 - t) * 3 * t * t + t * t * t;
+ },
+ backIn: function(n) {
+ var s = 1.70158;
+ return n * n * ((s + 1) * n - s);
+ },
+ backOut: function(n) {
+ n = n - 1;
+ var s = 1.70158;
+ return n * n * ((s + 1) * n + s) + 1;
+ },
+ elastic: function(n) {
+ if (n == !!n) {
+ return n;
+ }
+ return pow(2, -10 * n) * mathSin((n - .075) * (2 * PI) / .3) + 1;
+ },
+ bounce: function(n) {
+ var s = 7.5625,
+ p = 2.75,
+ l;
+ if (n < (1 / p)) {
+ l = s * n * n;
+ } else {
+ if (n < (2 / p)) {
+ n -= (1.5 / p);
+ l = s * n * n + .75;
+ } else {
+ if (n < (2.5 / p)) {
+ n -= (2.25 / p);
+ l = s * n * n + .9375;
+ } else {
+ n -= (2.625 / p);
+ l = s * n * n + .984375;
+ }
+ }
+ }
+ return l;
+ }
+ };
+ ef.easeIn = ef["ease-in"] = ef["<"];
+ ef.easeOut = ef["ease-out"] = ef[">"];
+ ef.easeInOut = ef["ease-in-out"] = ef["<>"];
+ ef["back-in"] = ef.backIn;
+ ef["back-out"] = ef.backOut;
+
+ var animationElements = [],
+ requestAnimFrame = window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback) {
+ setTimeout(callback, 16);
+ },
+ animation = function() {
+ var Now = +new Date,
+ l = 0;
+ for (; l < animationElements.length; l++) {
+ var e = animationElements[l];
+ if (e.el.removed || e.paused) {
+ continue;
+ }
+ var time = Now - e.start,
+ ms = e.ms,
+ easing = e.easing,
+ from = e.from,
+ diff = e.diff,
+ to = e.to,
+ t = e.t,
+ that = e.el,
+ set = {},
+ now,
+ init = {},
+ key;
+ if (e.initstatus) {
+ time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms;
+ e.status = e.initstatus;
+ delete e.initstatus;
+ e.stop && animationElements.splice(l--, 1);
+ } else {
+ e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top;
+ }
+ if (time < 0) {
+ continue;
+ }
+ if (time < ms) {
+ var pos = easing(time / ms);
+ for (var attr in from)
+ if (from[has](attr)) {
+ switch (availableAnimAttrs[attr]) {
+ case nu:
+ now = +from[attr] + pos * ms * diff[attr];
+ break;
+ case "colour":
+ now = "rgb(" + [
+ upto255(round(from[attr].r + pos * ms * diff[attr].r)),
+ upto255(round(from[attr].g + pos * ms * diff[attr].g)),
+ upto255(round(from[attr].b + pos * ms * diff[attr].b))
+ ].join(",") + ")";
+ break;
+ case "path":
+ now = [];
+ for (var i = 0, ii = from[attr].length; i < ii; i++) {
+ now[i] = [from[attr][i][0]];
+ for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
+ now[i][j] = (+from[attr][i][j] + pos * ms * diff[attr][i][j]).toFixed(4);
+ }
+ now[i] = now[i].join(S);
+ }
+ now = now.join(S);
+ break;
+ case "transform":
+ if (diff[attr].real) {
+ now = [];
+ for (i = 0, ii = from[attr].length; i < ii; i++) {
+ now[i] = [from[attr][i][0]];
+ for (j = 1, jj = from[attr][i].length; j < jj; j++) {
+ now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j];
+ }
+ }
+ } else {
+ var get = function(i) {
+ return +from[attr][i] + pos * ms * diff[attr][i];
+ };
+ // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]];
+ now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]];
+ }
+ break;
+ case "csv":
+ if (attr == "clip-rect") {
+ now = [];
+ i = 4;
+ while (i--) {
+ now[i] = +from[attr][i] + pos * ms * diff[attr][i];
+ }
+ }
+ break;
+ default:
+ var from2 = [][concat](from[attr]);
+ now = [];
+ i = that.ca[attr].length;
+ while (i--) {
+ now[i] = +from2[i] + pos * ms * diff[attr][i];
+ }
+ break;
+ }
+ set[attr] = now;
+ }
+ that.attr(set);
+ (function(id, that, anim) {
+ setTimeout(function() {
+ eve("raphael.anim.frame." + id, that, anim);
+ });
+ })(that.id, that, e.anim);
+ } else {
+ (function(f, el, a) {
+ setTimeout(function() {
+ eve("raphael.anim.frame." + el.id, el, a);
+ eve("raphael.anim.finish." + el.id, el, a);
+ R.is(f, "function") && f.call(el);
+ });
+ })(e.callback, that, e.anim);
+ that.attr(to);
+ animationElements.splice(l--, 1);
+ if (e.repeat > 1 && !e.next) {
+ for (key in to)
+ if (to[has](key)) {
+ init[key] = e.totalOrigin[key];
+ }
+ e.el.attr(init);
+ runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1);
+ }
+ if (e.next && !e.stop) {
+ runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat);
+ }
+ }
+ }
+ R.svg && that && that.paper && that.paper.safari();
+ animationElements.length && requestAnimFrame(animation);
+ },
+ upto255 = function(color) {
+ return color > 255 ? 255 : color < 0 ? 0 : color;
+ };
+
+ /*\
+ * Element.animateWith
+ [ method ]
+ **
+ * Acts similar to @Element.animate, but ensure that given animation runs in sync with another given element.
+ **
+ > Parameters
+ **
+ - el (object) element to sync with
+ - anim (object) animation to sync with
+ - params (object) #optional final attributes for the element, see also @Element.attr
+ - ms (number) #optional number of milliseconds for animation to run
+ - easing (string) #optional easing type. Accept on of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)`
+ - callback (function) #optional callback function. Will be called at the end of animation.
+ * or
+ - element (object) element to sync with
+ - anim (object) animation to sync with
+ - animation (object) #optional animation object, see @Raphael.animation
+ **
+ = (object) original element
+ \*/
+ elproto.animateWith = function(el, anim, params, ms, easing, callback) {
+ var element = this;
+ if (element.removed) {
+ callback && callback.call(element);
+ return element;
+ }
+ var a = params instanceof Animation ? params : R.animation(params, ms, easing, callback),
+ x, y;
+ runAnimation(a, element, a.percents[0], null, element.attr());
+ for (var i = 0, ii = animationElements.length; i < ii; i++) {
+ if (animationElements[i].anim == anim && animationElements[i].el == el) {
+ animationElements[ii - 1].start = animationElements[i].start;
+ break;
+ }
+ }
+ return element;
+ //
+ //
+ // var a = params ? R.animation(params, ms, easing, callback) : anim,
+ // status = element.status(anim);
+ // return this.animate(a).status(a, status * anim.ms / a.ms);
+ };
+ function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) {
+ var cx = 3 * p1x,
+ bx = 3 * (p2x - p1x) - cx,
+ ax = 1 - cx - bx,
+ cy = 3 * p1y,
+ by = 3 * (p2y - p1y) - cy,
+ ay = 1 - cy - by;
+ function sampleCurveX(t) {
+ return ((ax * t + bx) * t + cx) * t;
+ }
+ function solve(x, epsilon) {
+ var t = solveCurveX(x, epsilon);
+ return ((ay * t + by) * t + cy) * t;
+ }
+ function solveCurveX(x, epsilon) {
+ var t0, t1, t2, x2, d2, i;
+ for (t2 = x, i = 0; i < 8; i++) {
+ x2 = sampleCurveX(t2) - x;
+ if (abs(x2) < epsilon) {
+ return t2;
+ }
+ d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
+ if (abs(d2) < 1e-6) {
+ break;
+ }
+ t2 = t2 - x2 / d2;
+ }
+ t0 = 0;
+ t1 = 1;
+ t2 = x;
+ if (t2 < t0) {
+ return t0;
+ }
+ if (t2 > t1) {
+ return t1;
+ }
+ while (t0 < t1) {
+ x2 = sampleCurveX(t2);
+ if (abs(x2 - x) < epsilon) {
+ return t2;
+ }
+ if (x > x2) {
+ t0 = t2;
+ } else {
+ t1 = t2;
+ }
+ t2 = (t1 - t0) / 2 + t0;
+ }
+ return t2;
+ }
+ return solve(t, 1 / (200 * duration));
+ }
+ elproto.onAnimation = function(f) {
+ f ? eve.on("raphael.anim.frame." + this.id, f) : eve.unbind("raphael.anim.frame." + this.id);
+ return this;
+ };
+ function Animation(anim, ms) {
+ var percents = [],
+ newAnim = {};
+ this.ms = ms;
+ this.times = 1;
+ if (anim) {
+ for (var attr in anim)
+ if (anim[has](attr)) {
+ newAnim[toFloat(attr)] = anim[attr];
+ percents.push(toFloat(attr));
+ }
+ percents.sort(sortByNumber);
+ }
+ this.anim = newAnim;
+ this.top = percents[percents.length - 1];
+ this.percents = percents;
+ }
+
+ /*\
+ * Animation.delay
+ [ method ]
+ **
+ * Creates a copy of existing animation object with given delay.
+ **
+ > Parameters
+ **
+ - delay (number) number of ms to pass between animation start and actual animation
+ **
+ = (object) new altered Animation object
+ | var anim = Raphael.animation({cx: 10, cy: 20}, 2e3);
+ | circle1.animate(anim); // run the given animation immediately
+ | circle2.animate(anim.delay(500)); // run the given animation after 500 ms
+ \*/
+ Animation.prototype.delay = function(delay) {
+ var a = new Animation(this.anim, this.ms);
+ a.times = this.times;
+ a.del = +delay || 0;
+ return a;
+ };
+
+ /*\
+ * Animation.repeat
+ [ method ]
+ **
+ * Creates a copy of existing animation object with given repetition.
+ **
+ > Parameters
+ **
+ - repeat (number) number iterations of animation. For infinite animation pass `Infinity`
+ **
+ = (object) new altered Animation object
+ \*/
+ Animation.prototype.repeat = function(times) {
+ var a = new Animation(this.anim, this.ms);
+ a.del = this.del;
+ a.times = math.floor(mmax(times, 0)) || 1;
+ return a;
+ };
+ function runAnimation(anim, element, percent, status, totalOrigin, times) {
+ percent = toFloat(percent);
+ var params,
+ isInAnim,
+ isInAnimSet,
+ percents = [],
+ next,
+ prev,
+ timestamp,
+ ms = anim.ms,
+ from = {},
+ to = {},
+ diff = {};
+ if (status) {
+ for (i = 0, ii = animationElements.length; i < ii; i++) {
+ var e = animationElements[i];
+ if (e.el.id == element.id && e.anim == anim) {
+ if (e.percent != percent) {
+ animationElements.splice(i, 1);
+ isInAnimSet = 1;
+ } else {
+ isInAnim = e;
+ }
+ element.attr(e.totalOrigin);
+ break;
+ }
+ }
+ } else {
+ status = +to; // NaN
+ }
+ for (var i = 0, ii = anim.percents.length; i < ii; i++) {
+ if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) {
+ percent = anim.percents[i];
+ prev = anim.percents[i - 1] || 0;
+ ms = ms / anim.top * (percent - prev);
+ next = anim.percents[i + 1];
+ params = anim.anim[percent];
+ break;
+ } else if (status) {
+ element.attr(anim.anim[anim.percents[i]]);
+ }
+ }
+ if (!params) {
+ return;
+ }
+ if (!isInAnim) {
+ for (var attr in params)
+ if (params[has](attr)) {
+ if (availableAnimAttrs[has](attr) || element.ca[attr]) {
+ from[attr] = element.attr(attr);
+ (from[attr] == null) && (from[attr] = availableAttrs[attr]);
+ to[attr] = params[attr];
+ switch (availableAnimAttrs[attr]) {
+ case nu:
+ diff[attr] = (to[attr] - from[attr]) / ms;
+ break;
+ case "colour":
+ from[attr] = R.getRGB(from[attr]);
+ var toColour = R.getRGB(to[attr]);
+ diff[attr] = {
+ r: (toColour.r - from[attr].r) / ms,
+ g: (toColour.g - from[attr].g) / ms,
+ b: (toColour.b - from[attr].b) / ms
+ };
+ break;
+ case "path":
+ var pathes = path2curve(from[attr], to[attr]),
+ toPath = pathes[1];
+ from[attr] = pathes[0];
+ diff[attr] = [];
+ for (i = 0, ii = from[attr].length; i < ii; i++) {
+ diff[attr][i] = [0];
+ for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
+ diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;
+ }
+ }
+ break;
+ case "transform":
+ var _ = element._,
+ eq = equaliseTransform(_[attr], to[attr]);
+ if (eq) {
+ from[attr] = eq.from;
+ to[attr] = eq.to;
+ diff[attr] = [];
+ diff[attr].real = true;
+ for (i = 0, ii = from[attr].length; i < ii; i++) {
+ diff[attr][i] = [from[attr][i][0]];
+ for (j = 1, jj = from[attr][i].length; j < jj; j++) {
+ diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms;
+ }
+ }
+ } else {
+ var m = (element.matrix || new Matrix),
+ to2 = {
+ _: {
+ transform: _.transform
+ },
+ getBBox: function() {
+ return element.getBBox(1);
+ }
+ };
+ from[attr] = [
+ m.a,
+ m.b,
+ m.c,
+ m.d,
+ m.e,
+ m.f
+ ];
+ extractTransform(to2, to[attr]);
+ to[attr] = to2._.transform;
+ diff[attr] = [
+ (to2.matrix.a - m.a) / ms,
+ (to2.matrix.b - m.b) / ms,
+ (to2.matrix.c - m.c) / ms,
+ (to2.matrix.d - m.d) / ms,
+ (to2.matrix.e - m.e) / ms,
+ (to2.matrix.f - m.f) / ms
+ ];
+ // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
+ // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
+ // extractTransform(to2, to[attr]);
+ // diff[attr] = [
+ // (to2._.sx - _.sx) / ms,
+ // (to2._.sy - _.sy) / ms,
+ // (to2._.deg - _.deg) / ms,
+ // (to2._.dx - _.dx) / ms,
+ // (to2._.dy - _.dy) / ms
+ // ];
+ }
+ break;
+ case "csv":
+ var values = Str(params[attr])[split](separator),
+ from2 = Str(from[attr])[split](separator);
+ if (attr == "clip-rect") {
+ from[attr] = from2;
+ diff[attr] = [];
+ i = from2.length;
+ while (i--) {
+ diff[attr][i] = (values[i] - from[attr][i]) / ms;
+ }
+ }
+ to[attr] = values;
+ break;
+ default:
+ values = [][concat](params[attr]);
+ from2 = [][concat](from[attr]);
+ diff[attr] = [];
+ i = element.ca[attr].length;
+ while (i--) {
+ diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms;
+ }
+ break;
+ }
+ }
+ }
+ var easing = params.easing,
+ easyeasy = R.easing_formulas[easing];
+ if (!easyeasy) {
+ easyeasy = Str(easing).match(bezierrg);
+ if (easyeasy && easyeasy.length == 5) {
+ var curve = easyeasy;
+ easyeasy = function(t) {
+ return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms);
+ };
+ } else {
+ easyeasy = pipe;
+ }
+ }
+ timestamp = params.start || anim.start || +new Date;
+ e = {
+ anim: anim,
+ percent: percent,
+ timestamp: timestamp,
+ start: timestamp + (anim.del || 0),
+ status: 0,
+ initstatus: status || 0,
+ stop: false,
+ ms: ms,
+ easing: easyeasy,
+ from: from,
+ diff: diff,
+ to: to,
+ el: element,
+ callback: params.callback,
+ prev: prev,
+ next: next,
+ repeat: times || anim.times,
+ origin: element.attr(),
+ totalOrigin: totalOrigin
+ };
+ animationElements.push(e);
+ if (status && !isInAnim && !isInAnimSet) {
+ e.stop = true;
+ e.start = new Date - ms * status;
+ if (animationElements.length == 1) {
+ return animation();
+ }
+ }
+ if (isInAnimSet) {
+ e.start = new Date - e.ms * status;
+ }
+ animationElements.length == 1 && requestAnimFrame(animation);
+ } else {
+ isInAnim.initstatus = status;
+ isInAnim.start = new Date - isInAnim.ms * status;
+ }
+ eve("raphael.anim.start." + element.id, element, anim);
+ }
+
+ /*\
+ * Raphael.animation
+ [ method ]
+ **
+ * Creates an animation object that can be passed to the @Element.animate or @Element.animateWith methods.
+ * See also @Animation.delay and @Animation.repeat methods.
+ **
+ > Parameters
+ **
+ - params (object) final attributes for the element, see also @Element.attr
+ - ms (number) number of milliseconds for animation to run
+ - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)`
+ - callback (function) #optional callback function. Will be called at the end of animation.
+ **
+ = (object) @Animation
+ \*/
+ R.animation = function(params, ms, easing, callback) {
+ if (params instanceof Animation) {
+ return params;
+ }
+ if (R.is(easing, "function") || !easing) {
+ callback = callback || easing || null;
+ easing = null;
+ }
+ params = Object(params);
+ ms = +ms || 0;
+ var p = {},
+ json,
+ attr;
+ for (attr in params)
+ if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) {
+ json = true;
+ p[attr] = params[attr];
+ }
+ if (!json) {
+ return new Animation(params, ms);
+ } else {
+ easing && (p.easing = easing);
+ callback && (p.callback = callback);
+ return new Animation({
+ 100: p
+ }, ms);
+ }
+ };
+
+ /*\
+ * Element.animate
+ [ method ]
+ **
+ * Creates and starts animation for given element.
+ **
+ > Parameters
+ **
+ - params (object) final attributes for the element, see also @Element.attr
+ - ms (number) number of milliseconds for animation to run
+ - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)`
+ - callback (function) #optional callback function. Will be called at the end of animation.
+ * or
+ - animation (object) animation object, see @Raphael.animation
+ **
+ = (object) original element
+ \*/
+ elproto.animate = function(params, ms, easing, callback) {
+ var element = this;
+ if (element.removed) {
+ callback && callback.call(element);
+ return element;
+ }
+ var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback);
+ runAnimation(anim, element, anim.percents[0], null, element.attr());
+ return element;
+ };
+
+ /*\
+ * Element.setTime
+ [ method ]
+ **
+ * Sets the status of animation of the element in milliseconds. Similar to @Element.status method.
+ **
+ > Parameters
+ **
+ - anim (object) animation object
+ - value (number) number of milliseconds from the beginning of the animation
+ **
+ = (object) original element if `value` is specified
+ * Note, that during animation following events are triggered:
+ *
+ * On each animation frame event `anim.frame.`, on start `anim.start.` and on end `anim.finish.`.
+ \*/
+ elproto.setTime = function(anim, value) {
+ if (anim && value != null) {
+ this.status(anim, mmin(value, anim.ms) / anim.ms);
+ }
+ return this;
+ };
+
+ /*\
+ * Element.status
+ [ method ]
+ **
+ * Gets or sets the status of animation of the element.
+ **
+ > Parameters
+ **
+ - anim (object) #optional animation object
+ - value (number) #optional 0 – 1. If specified, method works like a setter and sets the status of a given animation to the value. This will cause animation to jump to the given position.
+ **
+ = (number) status
+ * or
+ = (array) status if `anim` is not specified. Array of objects in format:
+ o {
+ o anim: (object) animation object
+ o status: (number) status
+ o }
+ * or
+ = (object) original element if `value` is specified
+ \*/
+ elproto.status = function(anim, value) {
+ var out = [],
+ i = 0,
+ len,
+ e;
+ if (value != null) {
+ runAnimation(anim, this, -1, mmin(value, 1));
+ return this;
+ } else {
+ len = animationElements.length;
+ for (; i < len; i++) {
+ e = animationElements[i];
+ if (e.el.id == this.id && (!anim || e.anim == anim)) {
+ if (anim) {
+ return e.status;
+ }
+ out.push({
+ anim: e.anim,
+ status: e.status
+ });
+ }
+ }
+ if (anim) {
+ return 0;
+ }
+ return out;
+ }
+ };
+
+ /*\
+ * Element.pause
+ [ method ]
+ **
+ * Stops animation of the element with ability to resume it later on.
+ **
+ > Parameters
+ **
+ - anim (object) #optional animation object
+ **
+ = (object) original element
+ \*/
+ elproto.pause = function(anim) {
+ for (var i = 0; i < animationElements.length; i++)
+ if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+ if (eve("raphael.anim.pause." + this.id, this, animationElements[i].anim) !== false) {
+ animationElements[i].paused = true;
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Element.resume
+ [ method ]
+ **
+ * Resumes animation if it was paused with @Element.pause method.
+ **
+ > Parameters
+ **
+ - anim (object) #optional animation object
+ **
+ = (object) original element
+ \*/
+ elproto.resume = function(anim) {
+ for (var i = 0; i < animationElements.length; i++)
+ if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+ var e = animationElements[i];
+ if (eve("raphael.anim.resume." + this.id, this, e.anim) !== false) {
+ delete e.paused;
+ this.status(e.anim, e.status);
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Element.stop
+ [ method ]
+ **
+ * Stops animation of the element.
+ **
+ > Parameters
+ **
+ - anim (object) #optional animation object
+ **
+ = (object) original element
+ \*/
+ elproto.stop = function(anim) {
+ for (var i = 0; i < animationElements.length; i++)
+ if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+ if (eve("raphael.anim.stop." + this.id, this, animationElements[i].anim) !== false) {
+ animationElements.splice(i--, 1);
+ }
+ }
+ return this;
+ };
+ function stopAnimation(paper) {
+ for (var i = 0; i < animationElements.length; i++)
+ if (animationElements[i].el.paper == paper) {
+ animationElements.splice(i--, 1);
+ }
+ }
+ eve.on("raphael.remove", stopAnimation);
+ eve.on("raphael.clear", stopAnimation);
+ elproto.toString = function() {
+ return "Rapha\xebl\u2019s object";
+ };
+
+ elproto.toFront = function() {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = R._engine.getNode(o),
+ parent = o.parent,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (R._tofront(o, parent)) {
+ parent.canvas.appendChild(thisNode);
+ }
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk && follower.el[follower.stalk](o);
+ }
+ return o;
+ };
+
+ elproto.toBack = function() {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = R._engine.getNode(o),
+ parent = o.parent,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (R._toback(o, parent)) {
+ parent.canvas.insertBefore(thisNode, parent.canvas.firstChild);
+ }
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk && follower.el[follower.stalk](o);
+ }
+ return o;
+ };
+
+ elproto.insertAfter = function(element) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = R._engine.getNode(o),
+ thatNode = R._engine.getLastNode(element),
+ parentNode = element.parent.canvas,
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ if (thatNode.nextSibling) {
+ parentNode.insertBefore(thisNode, thatNode.nextSibling);
+ }
+ else {
+ parentNode.appendChild(thisNode);
+ }
+ R._insertafter(o, element, o.parent, element.parent);
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+ return o;
+ };
+
+ elproto.insertBefore = function(element) {
+ if (this.removed) {
+ return this;
+ }
+
+ var o = this,
+ thisNode = R._engine.getNode(o),
+ thatNode = R._engine.getNode(element),
+ followers = o.followers,
+ follower,
+ i,
+ ii;
+
+ element.parent.canvas.insertBefore(thisNode, thatNode);
+ R._insertbefore(o, element, o.parent, element.parent);
+ o.parent = element.parent;
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+ return this;
+ };
+
+ elproto.appendChild = function (element) {
+ if (this.removed || this.type !== 'group') {
+ return this;
+ }
+
+ var group = this,
+ followers = group.followers,
+ follower,
+ thatNode,
+ i,
+ ii;
+
+ // If appending in same group, simply perform toFront().
+ if (element.parent === group) {
+ element.toFront();
+ return group;
+ }
+
+ thatNode = R._engine.getNode(element);
+
+ // first remove from own group
+ R._tear(element, element.parent);
+
+ group.canvas.appendChild(thatNode);
+ element.parent = group;
+
+ !group.bottom && (group.bottom = element);
+ element.prev = group.top;
+ element.next = null;
+ group.top && (group.top.next = element);
+ group.top = element;
+
+ for (i = 0, ii = followers.length; i < ii; i++) {
+ (follower = followers[i]).stalk &&
+ follower.el[follower.stalk](element);
+ }
+
+ return group;
+ };
+
+ elproto.removeChild = function (element) {
+ if (this.removed || this.type !== 'group' || element.parent !== this) {
+ return this;
+ }
+
+ var o = this,
+ thatNode = R._engine.getNode(element),
+ paper = o.paper;
+
+ R._tear(element, o);
+ paper.canvas.appendChild(thatNode);
+
+ o.parent = paper;
+ !paper.bottom && (paper.bottom = o);
+
+ o.prev = paper.top;
+ paper.top && (paper.top.next = o);
+ paper.top = o;
+ o.next = null;
+
+ return o;
+ };
+
+ // Set
+ var Set = function(items) {
+ this.items = [];
+ this.length = 0;
+ this.type = "set";
+ if (items) {
+ for (var i = 0, ii = items.length; i < ii; i++) {
+ if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) {
+ this[this.items.length] = this.items[this.items.length] = items[i];
+ this.length++;
+ }
+ }
+ }
+ },
+ setproto = Set.prototype;
+
+ /*\
+ * Set.push
+ [ method ]
+ **
+ * Adds each argument to the current set.
+ = (object) original element
+ \*/
+ setproto.push = function() {
+ var item,
+ len;
+ for (var i = 0, ii = arguments.length; i < ii; i++) {
+ item = arguments[i];
+ if (item && (item.constructor == elproto.constructor || item.constructor == Set)) {
+ len = this.items.length;
+ this[len] = this.items[len] = item;
+ this.length++;
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Set.pop
+ [ method ]
+ **
+ * Removes last element and returns it.
+ = (object) element
+ \*/
+ setproto.pop = function() {
+ this.length && delete this[this.length--];
+ return this.items.pop();
+ };
+
+ /*\
+ * Set.forEach
+ [ method ]
+ **
+ * Executes given function for each element in the set.
+ *
+ * If function returns `false` it will stop loop running.
+ **
+ > Parameters
+ **
+ - callback (function) function to run
+ - thisArg (object) context object for the callback
+ = (object) Set object
+ \*/
+ setproto.forEach = function(callback, thisArg) {
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ if (callback.call(thisArg, this.items[i], i) === false) {
+ return this;
+ }
+ }
+ return this;
+ };
+ for (var method in elproto)
+ if (elproto[has](method)) {
+ setproto[method] = (function(methodname) {
+ return function() {
+ var arg = arguments;
+ return this.forEach(function(el) {
+ el[methodname][apply](el, arg);
+ });
+ };
+ })(method);
+ }
+ setproto.attr = function(name, value) {
+ if (name && R.is(name, array) && R.is(name[0], object)) {
+ for (var j = 0, jj = name.length; j < jj; j++) {
+ this.items[j].attr(name[j]);
+ }
+ } else {
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ this.items[i].attr(name, value);
+ }
+ }
+ return this;
+ };
+
+ /*\
+ * Set.clear
+ [ method ]
+ **
+ * Removeds all elements from the set
+ \*/
+ setproto.clear = function() {
+ while (this.length) {
+ this.pop();
+ }
+ };
+
+ /*\
+ * Set.splice
+ [ method ]
+ **
+ * Removes given element from the set
+ **
+ > Parameters
+ **
+ - index (number) position of the deletion
+ - count (number) number of element to remove
+ - insertion… (object) #optional elements to insert
+ = (object) set elements that were deleted
+ \*/
+ setproto.splice = function(index, count, insertion) {
+ index = index < 0 ? mmax(this.length + index, 0) : index;
+ count = mmax(0, mmin(this.length - index, isNaN(count) && this.length || count));
+ var tail = [],
+ todel = [],
+ args = [],
+ i;
+ for (i = 2; i < arguments.length; i++) {
+ args.push(arguments[i]);
+ }
+ for (i = 0; i < count; i++) {
+ todel.push(this[index + i]);
+ }
+ for (; i < this.length - index; i++) {
+ tail.push(this[index + i]);
+ }
+ var arglen = args.length;
+ for (i = 0; i < arglen + tail.length; i++) {
+ this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
+ }
+ i = this.items.length = this.length -= count - arglen;
+ while (this[i]) {
+ delete this[i++];
+ }
+ return new Set(todel);
+ };
+
+ /*\
+ * Set.exclude
+ [ method ]
+ **
+ * Removes given element from the set
+ **
+ > Parameters
+ **
+ - element (object) element to remove
+ = (boolean) `true` if object was found & removed from the set
+ \*/
+ setproto.exclude = function(el) {
+ for (var i = 0, ii = this.length; i < ii; i++)
+ if (this[i] == el) {
+ this.splice(i, 1);
+ return true;
+ }
+ };
+ setproto.animate = function(params, ms, easing, callback) {
+ (R.is(easing, "function") || !easing) && (callback = easing || null);
+ var len = this.items.length,
+ i = len,
+ item,
+ set = this,
+ collector;
+ if (!len) {
+ return this;
+ }
+ callback && (collector = function() {
+ !--len && callback.call(set);
+ });
+ easing = R.is(easing, string) ? easing : collector;
+ var anim = R.animation(params, ms, easing, collector);
+ item = this.items[--i].animate(anim);
+ while (i--) {
+ this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim, anim);
+ }
+ return this;
+ };
+ setproto.insertAfter = function(el) {
+ var i = this.items.length;
+ while (i--) {
+ this.items[i].insertAfter(el);
+ }
+ return this;
+ };
+ setproto.getBBox = function() {
+ var x = [],
+ y = [],
+ x2 = [],
+ y2 = [];
+ for (var i = this.items.length; i--; )
+ if (!this.items[i].removed) {
+ var box = this.items[i].getBBox();
+ x.push(box.x);
+ y.push(box.y);
+ x2.push(box.x + box.width);
+ y2.push(box.y + box.height);
+ }
+ x = mmin[apply](0, x);
+ y = mmin[apply](0, y);
+ x2 = mmax[apply](0, x2);
+ y2 = mmax[apply](0, y2);
+ return {
+ x: x,
+ y: y,
+ x2: x2,
+ y2: y2,
+ width: x2 - x,
+ height: y2 - y
+ };
+ };
+ setproto.clone = function(s) {
+ s = new Set;
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ s.push(this.items[i].clone());
+ }
+ return s;
+ };
+ setproto.toString = function() {
+ return "Rapha\xebl\u2018s set";
+ };
+
+ setproto.glow = function(glowConfig) {
+ var ret = this.paper.set();
+ this.forEach(function(shape, index){
+ var g = shape.glow(glowConfig);
+ if(g != null){
+ g.forEach(function(shape2, index2){
+ ret.push(shape2);
+ });
+ }
+ });
+ return ret;
+ };
+
+ /*\
+ * Raphael.registerFont
+ [ method ]
+ **
+ * Adds given font to the registered set of fonts for Raphaël. Should be used as an internal call from within Cufón’s font file.
+ * Returns original parameter, so it could be used with chaining.
+ # More about Cufón and how to convert your font form TTF, OTF, etc to JavaScript file.
+ **
+ > Parameters
+ **
+ - font (object) the font to register
+ = (object) the font you passed in
+ > Usage
+ | Cufon.registerFont(Raphael.registerFont({…}));
+ \*/
+ R.registerFont = function(font) {
+ if (!font.face) {
+ return font;
+ }
+ this.fonts = this.fonts || {};
+ var fontcopy = {
+ w: font.w,
+ face: {},
+ glyphs: {}
+ },
+ family = font.face["font-family"];
+ for (var prop in font.face)
+ if (font.face[has](prop)) {
+ fontcopy.face[prop] = font.face[prop];
+ }
+ if (this.fonts[family]) {
+ this.fonts[family].push(fontcopy);
+ } else {
+ this.fonts[family] = [fontcopy];
+ }
+ if (!font.svg) {
+ fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10);
+ for (var glyph in font.glyphs)
+ if (font.glyphs[has](glyph)) {
+ var path = font.glyphs[glyph];
+ fontcopy.glyphs[glyph] = {
+ w: path.w,
+ k: {},
+ d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function(command) {
+ return {
+ l: "L",
+ c: "C",
+ x: "z",
+ t: "m",
+ r: "l",
+ v: "c"
+ }
+ [command] || "M";
+ }) + "z"
+ };
+ if (path.k) {
+ for (var k in path.k)
+ if (path[has](k)) {
+ fontcopy.glyphs[glyph].k[k] = path.k[k];
+ }
+ }
+ }
+ }
+ return font;
+ };
+
+ /*\
+ * Paper.getFont
+ [ method ]
+ **
+ * Finds font object in the registered fonts by given parameters. You could specify only one word from the font name, like “Myriad” for “Myriad Pro”.
+ **
+ > Parameters
+ **
+ - family (string) font family name or any word from it
+ - weight (string) #optional font weight
+ - style (string) #optional font style
+ - stretch (string) #optional font stretch
+ = (object) the font object
+ > Usage
+ | paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30);
+ \*/
+ paperproto.getFont = function(family, weight, style, stretch) {
+ stretch = stretch || "normal";
+ style = style || "normal";
+ weight = +weight || {
+ normal: 400,
+ bold: 700,
+ lighter: 300,
+ bolder: 800
+ }
+ [weight] || 400;
+ if (!R.fonts) {
+ return;
+ }
+ var font = R.fonts[family];
+ if (!font) {
+ var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i");
+ for (var fontName in R.fonts)
+ if (R.fonts[has](fontName)) {
+ if (name.test(fontName)) {
+ font = R.fonts[fontName];
+ break;
+ }
+ }
+ }
+ var thefont;
+ if (font) {
+ for (var i = 0, ii = font.length; i < ii; i++) {
+ thefont = font[i];
+ if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) {
+ break;
+ }
+ }
+ }
+ return thefont;
+ };
+
+ /*\
+ * Paper.print
+ [ method ]
+ **
+ * Creates path that represent given text written using given font at given position with given size.
+ * Result of the method is path element that contains whole text as a separate path.
+ **
+ > Parameters
+ **
+ - x (number) x position of the text
+ - y (number) y position of the text
+ - string (string) text to print
+ - font (object) font object, see @Paper.getFont
+ - size (number) #optional size of the font, default is `16`
+ - origin (string) #optional could be `"baseline"` or `"middle"`, default is `"middle"`
+ - letter_spacing (number) #optional number in range `-1..1`, default is `0`
+ = (object) resulting path element, which consist of all letters
+ > Usage
+ | var txt = r.print(10, 50, "print", r.getFont("Museo"), 30).attr({fill: "#fff"});
+ \*/
+ paperproto.print = function(x, y, string, font, size, origin, letter_spacing) {
+ origin = origin || "middle"; // baseline|middle
+ letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1);
+ var letters = Str(string)[split](E),
+ shift = 0,
+ notfirst = 0,
+ path = E,
+ scale;
+ R.is(font, string) && (font = this.getFont(font));
+ if (font) {
+ scale = (size || 16) / font.face["units-per-em"];
+ var bb = font.face.bbox[split](separator),
+ top = +bb[0],
+ lineHeight = bb[3] - bb[1],
+ shifty = 0,
+ height = + bb[1] + (origin == "baseline" ? lineHeight + ( + font.face.descent) : lineHeight / 2);
+ for (var i = 0, ii = letters.length; i < ii; i++) {
+ if (letters[i] == "\n") {
+ shift = 0;
+ curr = 0;
+ notfirst = 0;
+ shifty += lineHeight;
+ } else {
+ var prev = notfirst && font.glyphs[letters[i - 1]] || {},
+ curr = font.glyphs[letters[i]];
+ shift += notfirst ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0;
+ notfirst = 1;
+ }
+ if (curr && curr.d) {
+ path += R.transformPath(curr.d, ["t", shift * scale, shifty * scale, "s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]);
+ }
+ }
+ }
+ return this.path(path).attr({
+ fill: "#000",
+ stroke: "none"
+ });
+ };
+
+ /*\
+ * Paper.add
+ [ method ]
+ **
+ * Imports elements in JSON array in format `{type: type, }`
+ **
+ > Parameters
+ **
+ - json (array)
+ = (object) resulting set of imported elements
+ > Usage
+ | paper.add([
+ | {
+ | type: "circle",
+ | cx: 10,
+ | cy: 10,
+ | r: 5
+ | },
+ | {
+ | type: "rect",
+ | x: 10,
+ | y: 10,
+ | width: 10,
+ | height: 10,
+ | fill: "#fc0"
+ | }
+ | ]);
+ \*/
+ paperproto.add = function(json) {
+ if (R.is(json, "array")) {
+ var res = this.set(),
+ i = 0,
+ ii = json.length,
+ j;
+ for (; i < ii; i++) {
+ j = json[i] || {};
+ elements[has](j.type) && res.push(this[j.type]().attr(j));
+ }
+ }
+ return res;
+ };
+
+ /*\
+ * Raphael.format
+ [ method ]
+ **
+ * Simple format function. Replaces construction of type “`{}`” to the corresponding argument.
+ **
+ > Parameters
+ **
+ - token (string) string to format
+ - … (string) rest of arguments will be treated as parameters for replacement
+ = (string) formated string
+ > Usage
+ | var x = 10,
+ | y = 20,
+ | width = 40,
+ | height = 50;
+ | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
+ | paper.path(Raphael.format("M{0},{1}h{2}v{3}h{4}z", x, y, width, height, -width));
+ \*/
+ R.format = function(token, params) {
+ var args = R.is(params, array) ? [0][concat](params) : arguments;
+ token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function(str, i) {
+ return args[++i] == null ? E : args[i];
+ }));
+ return token || E;
+ };
+
+ /*\
+ * Raphael.fullfill
+ [ method ]
+ **
+ * A little bit more advanced format function than @Raphael.format. Replaces construction of type “`{}`” to the corresponding argument.
+ **
+ > Parameters
+ **
+ - token (string) string to format
+ - json (object) object which properties will be used as a replacement
+ = (string) formated string
+ > Usage
+ | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
+ | paper.path(Raphael.fullfill("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
+ | x: 10,
+ | y: 20,
+ | dim: {
+ | width: 40,
+ | height: 50,
+ | "negative width": -40
+ | }
+ | }));
+ \*/
+ R.fullfill = (function() {
+ var tokenRegex = /\{([^\}]+)\}/g,
+ objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
+ replacer = function(all, key, obj) {
+ var res = obj;
+ key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
+ name = name || quotedName;
+ if (res) {
+ if (name in res) {
+ res = res[name];
+ }
+ typeof res == "function" && isFunc && (res = res());
+ }
+ });
+ res = (res == null || res == obj ? all : res) + "";
+ return res;
+ };
+ return function(str, obj) {
+ return String(str).replace(tokenRegex, function(all, key) {
+ return replacer(all, key, obj);
+ });
+ };
+ })();
+
+ /*\
+ * Raphael.ninja
+ [ method ]
+ **
+ * If you want to leave no trace of Raphaël (Well, Raphaël creates only one global variable `Raphael`, but anyway.) You can use `ninja` method.
+ * Beware, that in this case plugins could stop working, because they are depending on global variable existance.
+ **
+ = (object) Raphael object
+ > Usage
+ | (function (local_raphael) {
+ | var paper = local_raphael(10, 10, 320, 200);
+ | …
+ | })(Raphael.ninja());
+ \*/
+ R.ninja = function() {
+ oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael;
+ return R;
+ };
+
+ var crispFixer = (R.vml && 0.5 || 0);
+
+ R.crispBound = cacher(function (x, y, w, h, s) {
+ var at = {},
+ normalizer;
+
+ x = x || 0;
+ y = y || 0;
+ w = w || 0;
+ h = h || 0;
+ s = s || 0;
+ normalizer = s % 2 / 2 + crispFixer;
+
+ // normalize for crisp edges
+ at.x = round(x + normalizer) - normalizer;
+ at.y = round(y + normalizer) - normalizer;
+ at.width = round(x + w + normalizer) - normalizer - at.x;
+ at.height = round(y + h + normalizer) - normalizer - at.y;
+ at['stroke-width'] = s;
+
+ // adjust to single pixel if resultant dimension is zero.
+ (at.width === 0 && w !== 0) && (at.width = 1);
+ (at.height === 0 && h !== 0) && (at.height = 1);
+
+ return at;
+ }, R);
+
+ elproto.crisp = function () {
+ var o = this,
+ attrs = o.attrs,
+ key,
+ attr = {},
+ values = o.attr(['x', 'y', 'width', 'height', 'stroke-width']);
+
+ values = R.crispBound(values.x, values.y, values.width, values.height,
+ values['stroke-width']);
+
+ for (key in values) {
+ if (attrs[key] === values[key]) { // only set attribute if changed
+ delete values[key];
+ }
+ }
+
+ return o.attr(values);
+ };
+
+ /*\
+ * Raphael.st
+ [ property (object) ]
+ **
+ * You can add your own method to elements and sets. It is wise to add a set method for each element method
+ * you added, so you will be able to call the same method on sets too.
+ **
+ * See also @Raphael.el.
+ > Usage
+ | Raphael.el.red = function () {
+ | this.attr({fill: "#f00"});
+ | };
+ | Raphael.st.red = function () {
+ | this.forEach(function (el) {
+ | el.red();
+ | });
+ | };
+ | // then use it
+ | paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red();
+ \*/
+ R.st = setproto;
+
+ /*\
+ * Raphael.define
+ [ method ]
+ **
+ * Allows a unified definition of composite shapes and other behaviours using
+ * simple directives.
+ **
+ > Parameters
+ **
+ - definition (object) the shape definition
+ \*/
+ R.define = function (name, init, ca, fn, e) {
+ var i,
+ ii;
+
+ // multi definition
+ if (R.is(name, array)) {
+ for (i = 0, ii = name.length; i < ii; i++) {
+ R.define(name[i]);
+ }
+ return;
+ }
+ // object definition
+ else if (R.is(name, object)) {
+ R.define(name.name, name[name.name], name.ca, name.fn, name.e);
+ return;
+ }
+ // invalid or duplicate definition
+ else if (!name || R.fn[name]) {
+ return;
+ }
+
+ R.fn[name] = function () {
+ var args = arguments,
+ element = init.apply(this, args),
+ key;
+
+ if (fn && R.is(fn, object)) {
+ for (key in fn) {
+ element[key] = fn[key];
+ }
+ }
+
+ if (e && R.is(e, object)) {
+ for (key in e) {
+ element[key] && element[key](e[key]);
+ }
+ }
+
+ if (ca) {
+ if (R.is(ca, 'function')) {
+ element.ca[name] = ca;
+ }
+ else {
+ for (key in ca) {
+ element.ca[key] = ca[key];
+ }
+ }
+
+ // Check if namesake ca exists and apply it
+ if (element.ca[name]) {
+ R._lastArgIfGroup(args, true); // purge group
+ element.attr(name, arraySlice.call(args))
+ }
+ }
+
+ return element;
+ };
+
+ if (ca) { R.fn[name].ca = ca; }
+ if (fn) { R.fn[name].fn = fn; }
+ if (e) { R.fn[name].e = e; }
+
+ return R.fn[name];
+ };
+ // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
+ (function(doc, loaded, f) {
+ if (doc.readyState == null && doc.addEventListener) {
+ doc.addEventListener(loaded, f = function() {
+ doc.removeEventListener(loaded, f, false);
+ doc.readyState = "complete";
+ }, false);
+ doc.readyState = "loading";
+ }
+ function isLoaded() {
+ (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("raphael.DOMload");
+ }
+ isLoaded();
+ })(document, "DOMContentLoaded");
+
+ eve.on("raphael.DOMload", function() {
+ loaded = true;
+ });
+
+
+
+ // EXPOSE
+ // SVG and VML are appended just before the EXPOSE line
+ // Even with AMD, Raphael should be defined globally
+ oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
+
+ return R;
+}));
\ No newline at end of file
diff --git a/source/raphael.svg.js b/source/raphael.svg.js
new file mode 100644
index 0000000..3797b27
--- /dev/null
+++ b/source/raphael.svg.js
@@ -0,0 +1,1598 @@
+/**!
+* RedRaphael 1.0.0 - JavaScript Vector Library SVG Module
+* Copyright (c) 2012-2013 FusionCharts Technologies
+*
+* Raphael 2.1.0 - JavaScript Vector Library SVG Module
+* Copyright (c) 2008-2012 Dmitry Baranovskiy
+* Copyright © 2008-2012 Sencha Labs
+*
+* Licensed under the MIT license.
+*/
+window.Raphael && window.Raphael.svg && function(R) {
+ var has = "hasOwnProperty",
+ Str = String,
+ toFloat = parseFloat,
+ toInt = parseInt,
+ math = Math,
+ mmax = math.max,
+ abs = math.abs,
+ pow = math.pow,
+ sqrt = math.sqrt,
+ separator = /[, ]+/,
+ zeroStrokeFix = !!(/AppleWebKit/.test(R._g.win.navigator.userAgent) &&
+ (!/Chrome/.test(R._g.win.navigator.userAgent) ||
+ R._g.win.navigator.appVersion.match(/Chrome\/(\d+)\./)[1] < 29)),
+ eve = R.eve,
+ E = "",
+ S = " ",
+ xlink = "http://www.w3.org/1999/xlink",
+ markers = {
+ block: "M5,0 0,2.5 5,5z",
+ classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
+ diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
+ open: "M6,1 1,3.5 6,6",
+ oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
+ },
+ markerCounter = {},
+ updateReferenceUrl = function () {
+ return R._url = R._g.win.location.href.replace(/#.*?$/, E);
+ };
+
+ R.toString = function() {
+ return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
+ };
+
+ // Automatic gradient and other reference update on state change
+ R._url = (/msie/i.test(navigator.userAgent) && !window.opera) ?
+ E : updateReferenceUrl();
+ if (R._url && R._g.win.history.pushState) {
+ R._g.win.history.pushState = (function () {
+ var fn = R._g.win.history.pushState;
+ return function () {
+ var ret = fn.apply(R._g.win.history, arguments);
+ return updateReferenceUrl(), ret;
+ };
+ }());
+ R._g.win.addEventListener("popstate", updateReferenceUrl, false);
+ }
+
+ var $ = R._createNode = function(el, attr) {
+ if (attr) {
+ if (typeof el == "string") {
+ el = $(el);
+ }
+ for (var key in attr)
+ if (attr[has](key)) {
+ if (key.substring(0, 6) == "xlink:") {
+ el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
+ } else {
+ el.setAttribute(key, Str(attr[key]));
+ }
+ }
+ } else {
+ el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
+ }
+ return el;
+ },
+ gradientUnitNames = {
+ userSpaceOnUse: 'userSpaceOnUse',
+ objectBoundingBox: 'objectBoundingBox'
+ },
+ gradientSpreadNames = {
+ pad: 'pad',
+ redlect: 'reflect',
+ repeat: 'repeat'
+ },
+ addGradientFill = function(element, gradient) {
+ var type = "linear",
+ id = element.id + gradient,
+ fx = .5, fy = .5, r, cx, cy, units, spread,
+ o = element.node,
+ SVG = element.paper,
+ s = o.style,
+ el = R._g.doc.getElementById(id);
+ if (!el && SVG.defs) {
+ gradient = Str(gradient).replace(R._radial_gradient, function(all, opts) {
+ type = "radial";
+ opts = opts && opts.split(',') || [];
+ units = opts[5];
+ spread = opts[6];
+
+ var _fx = opts[0],
+ _fy = opts[1],
+ _r = opts[2],
+ _cx = opts[3],
+ _cy = opts[4],
+ shifted = (_fx && _fy),
+ dir,
+ sqx;
+
+ if (_r) {
+ r = /\%/.test(_r) ? _r : toFloat(_r);
+ }
+
+ if (units === gradientUnitNames.userSpaceOnUse) {
+ if (shifted) {
+ fx = _fx;
+ fy = _fy;
+ }
+ if (_cx && _cy) {
+ cx = _cx;
+ cy = _cy;
+ if (!shifted) {
+ fx = cx;
+ fy = cy;
+ }
+ }
+ return E;
+ }
+
+ if (shifted) {
+ fx = toFloat(_fx);
+ fy = toFloat(_fy);
+ dir = ((fy > .5) * 2 - 1);
+ (sqx = pow(fx - .5, 2)) + pow(fy - .5, 2) > .25 &&
+ (sqx < .25) && (fy = sqrt(.25 - sqx) * dir + .5) &&
+ fy !== .5 &&
+ (fy = fy.toFixed(5) - 1e-5 * dir);
+ }
+ if (_cx && _cy) {
+ cx = toFloat(_cx);
+ cy = toFloat(_cy);
+ dir = ((cy > .5) * 2 - 1);
+
+ (sqx = pow(cx - .5, 2)) + pow(cy - .5, 2) > .25 &&
+ (sqx < .25) && (cy = sqrt(.25 - sqx) * dir + .5) &&
+ cy !== .5 &&
+ (cy = cy.toFixed(5) - 1e-5 * dir);
+
+ if (!shifted) {
+ fx = cx;
+ fy = cy;
+ }
+ }
+
+ return E;
+ });
+ gradient = gradient.split(/\s*\-\s*/);
+ if (type == "linear") {
+ var angle = gradient.shift(),
+ specs = angle.match(/\((.*)\)/),
+ vector,
+ max;
+
+ specs = specs && specs[1] && specs[1].split(/\s*\,\s*/);
+ angle = -toFloat(angle);
+ if (isNaN(angle)) {
+ return null;
+ }
+ if (specs && specs.length) {
+ if (specs[0] in gradientUnitNames) {
+ units = specs.shift();
+ (specs[0] in gradientSpreadNames) &&
+ (spread = specs.shift());
+ }
+ else {
+ specs[4] && (units = specs[4]);
+ specs[5] && (spread = specs[5]);
+ }
+
+ /* @todo apply angle rotation and validation */
+ vector = [
+ specs[0] || "0%", specs[1] || "0%",
+ specs[2] || "100%", specs[3] || "0%"
+ ];
+ }
+ else {
+ vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))];
+ max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
+ vector[2] *= max;
+ vector[3] *= max;
+ if (vector[2] < 0) {
+ vector[0] = -vector[2];
+ vector[2] = 0;
+ }
+ if (vector[3] < 0) {
+ vector[1] = -vector[3];
+ vector[3] = 0;
+ }
+ }
+ }
+ var dots = R._parseDots(gradient);
+ if (!dots) {
+ return null;
+ }
+ id = id.replace(/[\(\)\s,\xb0#]/g, "_");
+
+ if (element.gradient && id !== element.gradient.id) {
+ SVG.defs.removeChild(element.gradient);
+ delete element.gradient;
+ }
+
+ if (!element.gradient) {
+ el = $(type + "Gradient", {
+ id: id
+ });
+ element.gradient = el;
+ (units in gradientUnitNames) &&
+ el.setAttribute('gradientUnits', Str(units));
+ (spread in gradientSpreadNames) &&
+ el.setAttribute('spreadMethod', Str(spread));
+ if (type === "radial") {
+ (r !== undefined) && el.setAttribute('r', Str(r));
+
+ if (cx !== undefined && cy !== undefined) {
+ el.setAttribute('cx', Str(cx));
+ el.setAttribute('cy', Str(cy));
+ }
+ el.setAttribute('fx', Str(fx));
+ el.setAttribute('fy', Str(fy));
+ }
+ else {
+ $(el, {
+ x1: vector[0],
+ y1: vector[1],
+ x2: vector[2],
+ y2: vector[3],
+ gradientTransform: element.matrix.invert()
+ });
+ }
+ SVG.defs.appendChild(el);
+ for (var i = 0, ii = dots.length; i < ii; i++) {
+ el.appendChild($("stop", {
+ offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
+ "stop-color": dots[i].color || "#fff",
+ //add stop opacity information
+ "stop-opacity": dots[i].opacity === undefined ? 1 : dots[i].opacity
+ }));
+ }
+ }
+ }
+ $(o, {
+ fill: "url('" + R._url + "#" + id + "')",
+ opacity: 1,
+ "fill-opacity": 1
+ });
+ s.fill = E;
+ s.opacity = 1;
+ s.fillOpacity = 1;
+ return 1;
+ },
+ updatePosition = function(o) {
+ var bbox = o.getBBox(1);
+ $(o.pattern, {
+ patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"
+ });
+ },
+ addArrow = function(o, value, isEnd) {
+ if (o.type == "path") {
+ var values = Str(value).toLowerCase().split("-"),
+ p = o.paper,
+ se = isEnd ? "end" : "start",
+ node = o.node,
+ attrs = o.attrs,
+ stroke = attrs["stroke-width"],
+ i = values.length,
+ type = "classic",
+ from,
+ to,
+ dx,
+ refX,
+ attr,
+ w = 3,
+ h = 3,
+ t = 5;
+ while (i--) {
+ switch (values[i]) {
+ case "block":
+ case "classic":
+ case "oval":
+ case "diamond":
+ case "open":
+ case "none":
+ type = values[i];
+ break;
+ case "wide":
+ h = 5;
+ break;
+ case "narrow":
+ h = 2;
+ break;
+ case "long":
+ w = 5;
+ break;
+ case "short":
+ w = 2;
+ break;
+ }
+ }
+ if (type == "open") {
+ w += 2;
+ h += 2;
+ t += 2;
+ dx = 1;
+ refX = isEnd ? 4 : 1;
+ attr = {
+ fill: "none",
+ stroke: attrs.stroke
+ };
+ } else {
+ refX = dx = w / 2;
+ attr = {
+ fill: attrs.stroke,
+ stroke: "none"
+ };
+ }
+ if (o._.arrows) {
+ if (isEnd) {
+ o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
+ o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
+ } else {
+ o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
+ o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
+ }
+ } else {
+ o._.arrows = {};
+ }
+ if (type != "none") {
+ var pathId = "raphael-marker-" + type,
+ markerId = "raphael-marker-" + se + type + w + h + "-obj" + o.id;
+ if (!R._g.doc.getElementById(pathId)) {
+ p.defs.appendChild($($("path"), {
+ "stroke-linecap": "round",
+ d: markers[type],
+ id: pathId
+ }));
+ markerCounter[pathId] = 1;
+ } else {
+ markerCounter[pathId]++;
+ }
+ var marker = R._g.doc.getElementById(markerId),
+ use;
+ if (!marker) {
+ marker = $($("marker"), {
+ id: markerId,
+ markerHeight: h,
+ markerWidth: w,
+ orient: "auto",
+ refX: refX,
+ refY: h / 2
+ });
+ use = $($("use"), {
+ "xlink:href": "#" + pathId,
+ transform: (isEnd ? "rotate(180 " + w / 2 + " " + h / 2 + ") " : E) + "scale(" + w / t + "," + h / t + ")",
+ "stroke-width": (1 / ((w / t + h / t) / 2)).toFixed(4)
+ });
+ marker.appendChild(use);
+ p.defs.appendChild(marker);
+ markerCounter[markerId] = 1;
+ } else {
+ markerCounter[markerId]++;
+ use = marker.getElementsByTagName("use")[0];
+ }
+ $(use, attr);
+ var delta = dx * (type != "diamond" && type != "oval");
+ if (isEnd) {
+ from = o._.arrows.startdx * stroke || 0;
+ to = R.getTotalLength(attrs.path) - delta * stroke;
+ } else {
+ from = delta * stroke;
+ to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
+ }
+ attr = {};
+ attr["marker-" + se] = "url('" + R._url + "#" + markerId + "')";
+ if (to || from) {
+ attr.d = Raphael.getSubpath(attrs.path, from, to);
+ }
+ $(node, attr);
+ o._.arrows[se + "Path"] = pathId;
+ o._.arrows[se + "Marker"] = markerId;
+ o._.arrows[se + "dx"] = delta;
+ o._.arrows[se + "Type"] = type;
+ o._.arrows[se + "String"] = value;
+ } else {
+ if (isEnd) {
+ from = o._.arrows.startdx * stroke || 0;
+ to = R.getTotalLength(attrs.path) - from;
+ } else {
+ from = 0;
+ to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
+ }
+ o._.arrows[se + "Path"] && $(node, {
+ d: Raphael.getSubpath(attrs.path, from, to)
+ });
+ delete o._.arrows[se + "Path"];
+ delete o._.arrows[se + "Marker"];
+ delete o._.arrows[se + "dx"];
+ delete o._.arrows[se + "Type"];
+ delete o._.arrows[se + "String"];
+ }
+ for (attr in markerCounter)
+ if (markerCounter[has](attr) && !markerCounter[attr]) {
+ var item = R._g.doc.getElementById(attr);
+ item && item.parentNode.removeChild(item);
+ }
+ }
+ },
+ dasharray = {
+ "": [0],
+ "none": [0],
+ "-": [3, 1],
+ ".": [1, 1],
+ "-.": [3, 1, 1, 1],
+ "-..": [3, 1, 1, 1, 1, 1],
+ ". ": [1, 3],
+ "- ": [4, 3],
+ "--": [8, 3],
+ "- .": [4, 3, 1, 3],
+ "--.": [8, 3, 1, 3],
+ "--..": [8, 3, 1, 3, 1, 3]
+ },
+ addDashes = function(o, value, params) {
+ var predefValue = dasharray[Str(value).toLowerCase()];
+ value = predefValue || ((value !== undefined) && [].concat(value));
+ if (value) {
+ var width = o.attrs["stroke-width"] || "1",
+ butt = {
+ round: width,
+ square: width,
+ butt: 0
+ }[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
+ i,
+ l = i = value.length;
+ if (predefValue) {
+ while (i--) {
+ value[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
+ }
+ }
+ else {
+ for (i = 0; i < l; i += 2) {
+ value[i] -= butt;
+ value[i + 1] && (value[i + 1] += butt);
+ if (value[i] <= 0) {
+ value[i] = 0.1;
+ }
+ }
+ }
+ if (R.is(value, 'array')) {
+ $(o.node, {
+ "stroke-dasharray": value.join(",")
+ });
+ }
+ }
+ },
+ setFillAndStroke = R._setFillAndStroke = function(o, params) {
+ if (!o.paper.canvas) {
+ return;
+ }
+ var node = o.node,
+ attrs = o.attrs,
+ paper = o.paper,
+ s = node.style,
+ vis = s.visibility;
+
+ s.visibility = "hidden";
+ for (var att in params) {
+ if (params[has](att)) {
+ if (!R._availableAttrs[has](att)) {
+ continue;
+ }
+ var value = params[att];
+ attrs[att] = value;
+ switch (att) {
+ case "blur":
+ o.blur(value);
+ break;
+ case "href":
+ case "title":
+ case "target":
+ var pn = node.parentNode;
+ if (pn.tagName.toLowerCase() != "a") {
+ if (value == E) { break; }
+ var hl = $("a");
+ pn.insertBefore(hl, node);
+ hl.appendChild(node);
+ pn = hl;
+ }
+ if (att == "target") {
+ pn.setAttributeNS(xlink, "show", value == "blank" ? "new" : value);
+ } else {
+ pn.setAttributeNS(xlink, att, value);
+ }
+ node.titleNode = pn;
+ break;
+ case "cursor":
+ s.cursor = value;
+ break;
+ case "transform":
+ o.transform(value);
+ break;
+ case "rotation":
+ if (R.is(value, "array")) {
+ o.rotate.apply(o, value);
+ }
+ else {
+ o.rotate(value);
+ }
+ break;
+ case "arrow-start":
+ addArrow(o, value);
+ break;
+ case "arrow-end":
+ addArrow(o, value, 1);
+ break;
+ case "clip-path":
+ var pathClip = true;
+ case "clip-rect":
+ var rect = !pathClip && Str(value).split(separator);
+ o._.clipispath = !!pathClip;
+ if (pathClip || rect.length == 4) {
+ o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
+ var el = $("clipPath"),
+ rc = $(pathClip ? "path" : "rect");
+ el.id = R.createUUID();
+ $(rc, pathClip ? {
+ d: value ? attrs['clip-path'] = R._pathToAbsolute(value) : R._availableAttrs.path,
+ fill: 'none'
+ } : {
+ x: rect[0],
+ y: rect[1],
+ width: rect[2],
+ height: rect[3],
+ transform: o.matrix.invert()
+ });
+ el.appendChild(rc);
+ paper.defs.appendChild(el);
+ $(node, {
+ "clip-path": "url('" + R._url +"#" + el.id + "')"
+ });
+ o.clip = rc;
+ }
+ if (!value) {
+ var path = node.getAttribute("clip-path");
+ if (path) {
+ var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E));
+ clip && clip.parentNode.removeChild(clip);
+ $(node, {
+ "clip-path": E
+ });
+ delete o.clip;
+ }
+ }
+ break;
+ case "path":
+ if (o.type == "path") {
+ $(node, {
+ d: value ? attrs.path = R._pathToAbsolute(value) : R._availableAttrs.path
+ });
+ o._.dirty = 1;
+ if (o._.arrows) {
+ "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+ "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+ }
+ }
+ break;
+ case "width":
+ node.setAttribute(att, value);
+ o._.dirty = 1;
+ if (attrs.fx) {
+ att = "x";
+ value = attrs.x;
+ } else {
+ break;
+ }
+ case "x":
+ if (attrs.fx) {
+ value = -attrs.x - (attrs.width || 0);
+ }
+ case "rx":
+ if (att == "rx" && o.type == "rect") {
+ break;
+ }
+ case "cx":
+ node.setAttribute(att, value);
+ o.pattern && updatePosition(o);
+ o._.dirty = 1;
+ break;
+ case "height":
+ node.setAttribute(att, value);
+ o._.dirty = 1;
+ if (attrs.fy) {
+ att = "y";
+ value = attrs.y;
+ } else {
+ break;
+ }
+ case "y":
+ if (attrs.fy) {
+ value = -attrs.y - (attrs.height || 0);
+ }
+ case "ry":
+ if (att == "ry" && o.type == "rect") {
+ break;
+ }
+ case "cy":
+ node.setAttribute(att, value);
+ o.pattern && updatePosition(o);
+ o._.dirty = 1;
+ break;
+ case "r":
+ if (o.type == "rect") {
+ $(node, {
+ rx: value,
+ ry: value
+ });
+ } else {
+ node.setAttribute(att, value);
+ }
+ o._.dirty = 1;
+ break;
+ case "src":
+ if (o.type == "image") {
+ node.setAttributeNS(xlink, "href", value);
+ }
+ break;
+ case "stroke-width":
+ if (o._.sx != 1 || o._.sy != 1) {
+ value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
+ }
+ if (paper._vbSize) {
+ value *= paper._vbSize;
+ }
+ if (zeroStrokeFix && value === 0) {
+ value = 0.000001;
+ }
+ node.setAttribute(att, value);
+ if (attrs["stroke-dasharray"]) {
+ addDashes(o, attrs["stroke-dasharray"], params);
+ }
+ if (o._.arrows) {
+ "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+ "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+ }
+ break;
+ case "stroke-dasharray":
+ addDashes(o, value, params);
+ break;
+ case "fill":
+ var isURL = Str(value).match(R._ISURL);
+ if (isURL) {
+ el = $("pattern");
+ var ig = $("image");
+ el.id = R.createUUID();
+ $(el, {
+ x: 0,
+ y: 0,
+ patternUnits: "userSpaceOnUse",
+ height: 1,
+ width: 1
+ });
+ $(ig, {
+ x: 0,
+ y: 0,
+ "xlink:href": isURL[1]
+ });
+ el.appendChild(ig);
+
+ (function(el) {
+ R._preload(isURL[1], function() {
+ var w = this.offsetWidth,
+ h = this.offsetHeight;
+ $(el, {
+ width: w,
+ height: h
+ });
+ $(ig, {
+ width: w,
+ height: h
+ });
+ paper.safari();
+ });
+ })(el);
+ paper.defs.appendChild(el);
+ $(node, {
+ fill: "url('" + R._url + "#" + el.id + "')"
+ });
+ o.pattern = el;
+ o.pattern && updatePosition(o);
+ break;
+ }
+ var clr = R.getRGB(value);
+ if (!clr.error) {
+ delete params.gradient;
+ delete attrs.gradient;
+ !R.is(attrs.opacity, "undefined") &&
+ R.is(params.opacity, "undefined") &&
+ $(node, {
+ opacity: attrs.opacity
+ });
+ !R.is(attrs["fill-opacity"], "undefined") &&
+ R.is(params["fill-opacity"], "undefined") &&
+ $(node, {
+ "fill-opacity": attrs["fill-opacity"]
+ });
+ } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
+ if ("opacity" in attrs || "fill-opacity" in attrs) {
+ var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
+ if (gradient) {
+ var stops = gradient.getElementsByTagName("stop");
+ $(stops[stops.length - 1], {
+ "stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)
+ });
+ }
+ }
+ attrs.gradient = value;
+ attrs.fill = "none";
+ break;
+ }
+ if (clr[has]("opacity")) {
+ $(node, {
+ "fill-opacity": (s.fillOpacity =
+ (clr.opacity > 1 ? clr.opacity / 100 : clr.opacity))
+ });
+ o._.opacitydirty = true;
+ }
+ else if (o._.opacitydirty && R.is(attrs['fill-opacity'], "undefined") &&
+ R.is(params["fill-opacity"], "undefined")) {
+ node.removeAttribute('fill-opacity');
+ s.fillOpacity = E;
+ delete o._.opacitydirty;
+ }
+ case "stroke":
+ clr = R.getRGB(value);
+ node.setAttribute(att, clr.hex);
+ att == "stroke" && clr[has]("opacity") && $(node, {
+ "stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity
+ });
+ if (att == "stroke" && o._.arrows) {
+ "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+ "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+ }
+ break;
+ case "gradient":
+ (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
+ break;
+ case 'line-height': // do not apply
+ case 'vertical-align': // do not apply
+ break;
+ case "visibility":
+ value === 'hidden' ? o.hide() : o.show();
+ break;
+ case "opacity":
+ if (attrs.gradient && !attrs[has]("stroke-opacity")) {
+ $(node, {
+ "stroke-opacity": value > 1 ? value / 100 : value
+ });
+ }
+ // fall
+ case "fill-opacity":
+ if (attrs.gradient) {
+ gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
+ if (gradient) {
+ stops = gradient.getElementsByTagName("stop");
+ $(stops[stops.length - 1], {
+ "stop-opacity": value
+ });
+ }
+ break;
+ }
+ default:
+ att == "font-size" && (value = toInt(value, 10) + "px");
+ var cssrule = att.replace(/(\-.)/g, function(w) {
+ return w.substring(1).toUpperCase();
+ });
+ s[cssrule] = value;
+ o._.dirty = 1;
+ node.setAttribute(att, value);
+ break;
+ }
+ }
+ }
+
+ tuneText(o, params);
+ s.visibility = vis;
+ },
+ leading = 1.2,
+ tuneText = function(el, params) {
+ if (el.type != "text" || !(params[has]("text") || params[has]("font") ||
+ params[has]("font-size") || params[has]("x") || params[has]("y") ||
+ params[has]("line-height") || params[has]("vertical-align"))) {
+ return;
+ }
+ var a = el.attrs,
+ node = el.node,
+ computedStyle = node.firstChild && R._g.doc.defaultView.getComputedStyle(node.firstChild, E),
+ fontSize = computedStyle ? toFloat(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size")) : 10,
+ lineHeight = toFloat(params['line-height'] || a['line-height']) || fontSize * leading,
+ valign = a[has]("vertical-align") ? a["vertical-align"] : "middle";
+
+ if (isNaN(lineHeight)) {
+ lineHeight = fontSize * leading;
+ }
+
+ valign = valign === 'top' ? -0.5 : (valign === 'bottom' ? 0.5 : 0);
+
+ if (params[has]("text") && (params.text !== a.text || el._textdirty)) {
+ a.text = params.text;
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ var texts = Str(params.text).split(/\n| /ig),
+ tspans = [],
+ tspan;
+ for (var i = 0, ii = texts.length; i < ii; i++) {
+ tspan = $("tspan");
+ if (i) {
+ $(tspan, {
+ dy: lineHeight,
+ x: a.x
+ });
+ } else {
+ $(tspan, {
+ dy: lineHeight * texts.length * valign,
+ x: a.x
+ });
+ }
+ if (!texts[i]) { // preserve blank lines
+ tspan.setAttributeNS("http://www.w3.org/XML/1998/namespace",
+ "xml:space","preserve");
+ texts[i] = " ";
+ }
+ tspan.appendChild(R._g.doc.createTextNode(texts[i]));
+ node.appendChild(tspan);
+ tspans[i] = tspan;
+ }
+ el._textdirty = false;
+ } else {
+ tspans = node.getElementsByTagName("tspan");
+ for (i = 0, ii = tspans.length; i < ii; i++)
+ if (i) {
+ $(tspans[i], {
+ dy: lineHeight,
+ x: a.x
+ });
+ } else {
+ $(tspans[0], {
+ dy: lineHeight * tspans.length * valign,
+ x: a.x
+ });
+ }
+ }
+ $(node, {
+ x: a.x,
+ y: a.y
+ });
+ el._.dirty = 1;
+ var bb = el._getBBox(),
+ dif = a.y - (bb.y + bb.height / 2);
+
+ // If the bbox is calculated then we need to make additional adjustments,
+ // to account for the fact that the calculated bbox already has the
+ // text alignment, both horizontal and vertical, included in the calculation.
+ if (bb.isCalculated) {
+ switch (a['vertical-align']) {
+ case "top":
+ dif = bb.height * .75;
+ break;
+ case "bottom":
+ dif = - (bb.height * .25);
+ break;
+ default:
+ dif = a.y - (bb.y + bb.height * .25);
+ break;
+ };
+ }
+
+ dif && R.is(dif, "finite") && tspans[0] && $(tspans[0], {
+ dy: dif
+ });
+ },
+ Element = function(node, svg, group) {
+ var o = this,
+ parent = group || svg;
+
+ o.node = o[0] = node;
+ node.raphael = true;
+ node.raphaelid = o.id = R._oid++;
+
+ o.matrix = R.matrix();
+ o.realPath = null;
+
+ o.attrs = o.attrs || {};
+ o.styles = o.styles || {};
+ o.followers = o.followers || [];
+
+ o.paper = svg;
+ o.ca = o.customAttributes = o.customAttributes ||
+ new svg._CustomAttributes();
+
+ o._ = {
+ transform: [],
+ sx: 1,
+ sy: 1,
+ deg: 0,
+ dx: 0,
+ dy: 0,
+ dirty: 1
+ };
+
+ o.parent = parent;
+ !parent.bottom && (parent.bottom = o);
+
+ o.prev = parent.top;
+ parent.top && (parent.top.next = o);
+ parent.top = o;
+ o.next = null;
+ },
+ elproto = R.el;
+
+ Element.prototype = elproto;
+ elproto.constructor = Element;
+
+ R._engine.getNode = function (el) {
+ var node = el.node || el[0].node;
+ return node.titleNode || node;
+ };
+ R._engine.getLastNode = function (el) {
+ var node = el.node || el[el.length - 1].node;
+ return node.titleNode || node;
+ };
+
+ R._engine.path = function(pathString, SVG, group) {
+ var el = $("path");
+
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (SVG.canvas && SVG.canvas.appendChild(el));
+
+ var p = new Element(el, SVG, group);
+ p.type = "path";
+ setFillAndStroke(p, {
+ fill: "none",
+ stroke: "#000",
+ path: pathString
+ });
+ return p;
+ };
+
+ elproto.rotate = function(deg, cx, cy) {
+ var o = this,
+ bbox;
+ if (o.removed) {
+ return o;
+ }
+ deg = Str(deg).split(separator);
+ if (deg.length - 1) {
+ cx = toFloat(deg[1]);
+ cy = toFloat(deg[2]);
+ }
+ deg = toFloat(deg[0]);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ bbox = o.getBBox(1);
+ cx = bbox.x + bbox.width / 2;
+ cy = bbox.y + bbox.height / 2;
+ }
+ o.transform(o._.transform.concat([["r", deg, cx, cy]]));
+ return o;
+ };
+
+ elproto.scale = function(sx, sy, cx, cy) {
+ var o = this,
+ bbox;
+ if (o.removed) {
+ return o;
+ }
+ sx = Str(sx).split(separator);
+ if (sx.length - 1) {
+ sy = toFloat(sx[1]);
+ cx = toFloat(sx[2]);
+ cy = toFloat(sx[3]);
+ }
+ sx = toFloat(sx[0]);
+ (sy == null) && (sy = sx);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ bbox = o.getBBox(1);
+ }
+ cx = cx == null ? bbox.x + bbox.width / 2 : cx;
+ cy = cy == null ? bbox.y + bbox.height / 2 : cy;
+ o.transform(o._.transform.concat([["s", sx, sy, cx, cy]]));
+ return o;
+ };
+
+ elproto.translate = function(dx, dy) {
+ var o = this;
+ if (o.removed) {
+ return o;
+ }
+ dx = Str(dx).split(separator);
+ if (dx.length - 1) {
+ dy = toFloat(dx[1]);
+ }
+ dx = toFloat(dx[0]) || 0;
+ dy = +dy || 0;
+ o.transform(o._.transform.concat([["t", dx, dy]]));
+ return o;
+ };
+
+ elproto.transform = function(tstr) {
+ var o = this,
+ _ = o._,
+ sw;
+
+ if (tstr == null) {
+ return _.transform;
+ }
+ R._extractTransform(o, tstr);
+
+ o.clip && !_.clipispath && $(o.clip, {
+ transform: o.matrix.invert()
+ });
+ o.pattern && updatePosition(o);
+ o.node && $(o.node, {
+ transform: o.matrix
+ });
+
+ if (_.sx != 1 || _.sy != 1) {
+ sw = o.attrs[has]("stroke-width") ? o.attrs["stroke-width"] : 1;
+ o.attr({
+ "stroke-width": sw
+ });
+ }
+
+ return o;
+ };
+
+ elproto.hide = function() {
+ var o = this;
+ !o.removed && o.paper.safari(o.node.style.display = "none");
+ return o;
+ };
+
+ elproto.show = function() {
+ var o = this;
+ !o.removed && o.paper.safari(o.node.style.display = E);
+ return o;
+ };
+
+ elproto.remove = function() {
+ if (this.removed || !this.parent.canvas) {
+ return;
+ }
+
+ var o = this,
+ node = R._engine.getNode(o),
+ paper = o.paper,
+ defs = paper.defs,
+ i;
+
+
+ paper.__set__ && paper.__set__.exclude(o);
+ eve.unbind("raphael.*.*." + o.id);
+
+ if (o.gradient && defs) {
+ defs.removeChild(o.gradient);
+ }
+ while (i = o.followers.pop()) {
+ i.el.remove();
+ }
+ o.parent.canvas.removeChild(node);
+ R._tear(o, paper);
+ for (i in o) {
+ o[i] = typeof o[i] === "function" ? R._removedFactory(i) : null;
+ }
+ o.removed = true;
+ };
+ elproto._getBBox = function() {
+ var o = this,
+ node = o.node,
+ bbox = {},
+ a = o.attrs,
+ align,
+ hide;
+
+ if (node.style.display === "none") {
+ o.show();
+ hide = true;
+ }
+
+ try {
+ bbox = node.getBBox();
+
+ if (o.type == "text") {
+ // If bbox does not have x / y, which is possible in certain
+ // environments, we mathematically calculate these values by
+ // using x, y (adjusted using the values of text-anchor, and
+ // vertical-align attributes), of the element along with the
+ // width and height provided by the getBBox().
+ if (bbox.x === undefined) {
+ bbox.isCalculated = true;
+ align = a['text-anchor'];
+ bbox.x = (a.x || 0) - (bbox.width * ((align === "start") ?
+ 0 : (align === "middle") ? 0.5 : 1));
+ }
+
+ if (bbox.y === undefined) {
+ bbox.isCalculated = true;
+ align = a['vertical-align'];
+ bbox.y = (a.y || 0) - (bbox.height * ((align === "bottom") ?
+ 1 : (align === "middle") ? 0.5 : 0));
+ }
+ }
+
+ } catch (e) {
+ // Firefox 3.0.x plays badly here
+ } finally {
+ bbox = bbox || {};
+ }
+ hide && o.hide();
+ return bbox;
+ };
+
+ elproto.css = function (name, value) {
+ // do not parse css in case element is removed.
+ if (this.removed) {
+ return this;
+ }
+
+ // process as getter when a single key is sent as parameter.
+ if (value == null && R.is(name, "string")) {
+ var names = name.split(separator),
+ out = {};
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in this.styles) {
+ out[name] = this.styles[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+ // process as getter when multiple keys are pre-sent as array.
+ if (value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = this.styles(name[i]);
+ }
+ return out;
+ }
+ // convert single key-value setter into object style standard.
+ if (value != null) {
+ var params = {};
+ params[name] = value;
+ } else if (name != null && R.is(name, "object")) {
+ params = name;
+ }
+ // iterate on keys and set style or raise events.
+ var otherkey, doattrs = {};
+ for (var key in params) {
+ otherkey = key.replace(/\B([A-Z]{1})/g, "-$1").toLowerCase();
+
+ // If keys are supported via attr then use attr instead of css.
+ if (R._availableAttrs[has](otherkey) || otherkey === 'color') {
+ // Replace "color" with fill
+ (otherkey === 'color' && this.type === 'text') && (otherkey = 'fill');
+
+ doattrs[otherkey] = params[key];
+ doattrs.dirty = true;
+ continue;
+ }
+ eve("raphael.css." + otherkey + "." + this.id, this, params[key], otherkey);
+ this.node.style[otherkey] = params[key];
+ this.styles[otherkey] = params[key];
+ }
+ // run on followers
+ for (i = 0, ii = this.followers.length; i < ii; i++) {
+ this.followers[i].el.css(params);
+ }
+ // apply css via attrs
+ if (doattrs[has]("dirty")) {
+ delete doattrs.dirty;
+ this.attr(doattrs);
+ }
+ return this;
+ };
+
+ elproto.attr = function(name, value) {
+ if (this.removed) {
+ return this;
+ }
+ if (name == null) {
+ var res = {};
+ for (var a in this.attrs)
+ if (this.attrs[has](a)) {
+ res[a] = this.attrs[a];
+ }
+ res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
+ res.transform = this._.transform;
+ res.visibility = this.node.style.display === "none" ? "hidden" : "visible";
+ return res;
+ }
+ if (value == null && R.is(name, "string")) {
+ if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
+ return this.attrs.gradient;
+ }
+ if (name == "transform") {
+ return this._.transform;
+ }
+ if (name == "visibility") {
+ return this.node.style.display === "none" ? "hidden" : "visible";
+ }
+ var names = name.split(separator),
+ out = {};
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in this.attrs) {
+ out[name] = this.attrs[name];
+ } else if (R.is(this.ca[name], "function")) {
+ out[name] = this.ca[name].def;
+ } else {
+ out[name] = R._availableAttrs[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+ if (value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = this.attr(name[i]);
+ }
+ return out;
+ }
+ if (value != null) {
+ var params = {};
+ params[name] = value;
+ } else if (name != null && R.is(name, "object")) {
+ params = name;
+ }
+ for (var key in params) {
+ eve("raphael.attr." + key + "." + this.id, this, params[key], key);
+ }
+ var todel = {};
+ for (key in this.ca) {
+ if (this.ca[key] && params[has](key) && R.is(this.ca[key], "function") && !this.ca['_invoked' + key]) {
+
+ this.ca['_invoked'+key] = true; // prevent recursion
+ var par = this.ca[key].apply(this, [].concat(params[key]));
+ delete this.ca['_invoked'+key];
+
+ for (var subkey in par) {
+ if (par[has](subkey)) {
+ params[subkey] = par[subkey];
+ }
+ }
+ this.attrs[key] = params[key];
+ if (par === false) {
+ todel[key] = params[key];
+ delete params[key];
+ }
+ }
+ }
+
+ setFillAndStroke(this, params);
+
+ var follower;
+ for (i = 0, ii = this.followers.length; i < ii; i++) {
+ follower = this.followers[i];
+ (follower.cb && !follower.cb.call(follower.el, params, this)) ||
+ follower.el.attr(params);
+ }
+
+ for (subkey in todel) {
+ params[subkey] = todel[subkey];
+ }
+ return this;
+ };
+
+ elproto.blur = function(size) {
+ // Experimental. No Safari support. Use it on your own risk.
+ var t = this;
+ if (+size !== 0) {
+ var fltr = $("filter"),
+ blur = $("feGaussianBlur");
+ t.attrs.blur = size;
+ fltr.id = R.createUUID();
+ $(blur, {
+ stdDeviation: +size || 1.5
+ });
+ fltr.appendChild(blur);
+ t.paper.defs.appendChild(fltr);
+ t._blur = fltr;
+ $(t.node, {
+ filter: "url('" + R._url + "#" + fltr.id + "')"
+ });
+ } else {
+ if (t._blur) {
+ t._blur.parentNode.removeChild(t._blur);
+ delete t._blur;
+ delete t.attrs.blur;
+ }
+ t.node.removeAttribute("filter");
+ }
+ };
+
+ elproto.on = function(eventType, handler) {
+ if (this.removed) {
+ return this;
+ }
+
+ var fn = handler;
+ if (R.supportsTouch) {
+ eventType = R._touchMap[eventType] ||
+ (eventType === 'click' && 'touchstart') || eventType;
+ fn = function(e) {
+ e.preventDefault();
+ handler();
+ };
+ }
+ this.node['on'+ eventType] = fn;
+ return this;
+ };
+
+
+ R._engine.group = function(svg, id, group) {
+ var el = $("g");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var g = new Element(el, svg, group);
+ g.type = "group";
+ g.canvas = g.node;
+ g.top = null;
+ g.bottom = null;
+ id && el.setAttribute('class', ['red', id, g.id].join('-'));
+
+ return g;
+ };
+
+ R._engine.circle = function(svg, x, y, r, group) {
+ var el = $("circle");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ cx: x,
+ cy: y,
+ r: r,
+ fill: "none",
+ stroke: "#000"
+ };
+ res.type = "circle";
+ $(el, res.attrs);
+ return res;
+ };
+ R._engine.rect = function(svg, x, y, w, h, r, group) {
+ var el = $("rect");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ x: x,
+ y: y,
+ width: w,
+ height: h,
+ r: r || 0,
+ rx: r || 0,
+ ry: r || 0,
+ fill: "none",
+ stroke: "#000"
+ };
+ res.type = "rect";
+ $(el, res.attrs);
+ return res;
+ };
+ R._engine.ellipse = function(svg, x, y, rx, ry, group) {
+ var el = $("ellipse");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ cx: x,
+ cy: y,
+ rx: rx,
+ ry: ry,
+ fill: "none",
+ stroke: "#000"
+ };
+ res.type = "ellipse";
+ $(el, res.attrs);
+ return res;
+ };
+ R._engine.image = function(svg, src, x, y, w, h, group) {
+ var el = $("image");
+ $(el, {
+ x: x,
+ y: y,
+ width: w,
+ height: h,
+ preserveAspectRatio: "none"
+ });
+ el.setAttributeNS(xlink, "href", src);
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ x: x,
+ y: y,
+ width: w,
+ height: h,
+ src: src
+ };
+ res.type = "image";
+ return res;
+ };
+ R._engine.text = function(svg, x, y, text, group) {
+ var el = $("text");
+ (group && group.canvas && group.canvas.appendChild(el)) ||
+ (svg.canvas && svg.canvas.appendChild(el));
+
+ var res = new Element(el, svg, group);
+ res.attrs = {
+ x: x,
+ y: y,
+ "text-anchor": "middle",
+ "vertical-align": "middle",
+ text: text,
+ //font: R._availableAttrs.font,
+ stroke: "none",
+ fill: "#000"
+ };
+ res.type = "text";
+ res._textdirty = true;
+ setFillAndStroke(res, res.attrs);
+ return res;
+ };
+ /* @diffend */
+
+ R._engine.setSize = function(width, height) {
+ this.width = width || this.width;
+ this.height = height || this.height;
+ this.canvas.setAttribute("width", this.width);
+ this.canvas.setAttribute("height", this.height);
+ if (this._viewBox) {
+ this.setViewBox.apply(this, this._viewBox);
+ }
+ return this;
+ };
+ R._engine.create = function() {
+ var con = R._getContainer.apply(0, arguments),
+ container = con && con.container,
+ x = con.x,
+ y = con.y,
+ width = con.width,
+ height = con.height;
+ if (!container) {
+ throw new Error("SVG container not found.");
+ }
+ var cnvs = $("svg"),
+ css = "overflow:hidden;-webkit-tap-highlight-color:rgba(0,0,0,0);"+
+ "-webkit-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;"+
+ "-ms-user-select:none;user-select:none;-o-user-select:none;cursor:default;",
+ isFloating;
+ x = x || 0;
+ y = y || 0;
+ width = width || 512;
+ height = height || 342;
+ $(cnvs, {
+ height: height,
+ version: 1.1,
+ width: width,
+ xmlns: "http://www.w3.org/2000/svg"
+ });
+ if (container == 1) {
+ cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
+ R._g.doc.body.appendChild(cnvs);
+ isFloating = 1;
+ } else {
+ cnvs.style.cssText = css + "position:relative";
+ if (container.firstChild) {
+ container.insertBefore(cnvs, container.firstChild);
+ } else {
+ container.appendChild(cnvs);
+ }
+ }
+ container = new R._Paper;
+ container.width = width;
+ container.height = height;
+ container.canvas = cnvs;
+ container.clear();
+ container._left = container._top = 0;
+ isFloating && (container.renderfix = function() {
+ });
+ container.renderfix();
+ return container;
+ };
+ R._engine.setViewBox = function(x, y, w, h, fit) {
+ eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]);
+ var size = mmax(w / this.width, h / this.height),
+ top = this.top,
+ aspectRatio = fit ? "meet" : "xMinYMin",
+ vb,
+ sw;
+ if (x == null) {
+ if (this._vbSize) {
+ size = 1;
+ }
+ delete this._vbSize;
+ vb = "0 0 " + this.width + S + this.height;
+ } else {
+ this._vbSize = size;
+ vb = x + S + y + S + w + S + h;
+ }
+ $(this.canvas, {
+ viewBox: vb,
+ preserveAspectRatio: aspectRatio
+ });
+ while (size && top) {
+ sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
+ top.attr({
+ "stroke-width": sw
+ });
+ top._.dirty = 1;
+ top._.dirtyT = 1;
+ top = top.prev;
+ }
+ this._viewBox = [x, y, w, h, !!fit];
+ return this;
+ };
+
+ R.prototype.renderfix = function() {
+ var cnvs = this.canvas,
+ s = cnvs.style,
+ pos;
+ try {
+ pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix();
+ } catch (e) {
+ pos = cnvs.createSVGMatrix();
+ }
+ var left = -pos.e % 1,
+ top = - pos.f % 1;
+ if (left || top) {
+ if (left) {
+ this._left = (this._left + left) % 1;
+ s.left = this._left + "px";
+ }
+ if (top) {
+ this._top = (this._top + top) % 1;
+ s.top = this._top + "px";
+ }
+ }
+ };
+
+ R.prototype.clear = function() {
+ eve("raphael.clear", this);
+ var c = this.canvas;
+ while (c.firstChild) {
+ c.removeChild(c.firstChild);
+ }
+ this.bottom = this.top = null;
+ (this.desc = $("desc")).appendChild(R._g.doc.createTextNode(R.is(R.desc, "string") && R.desc ||
+ "Created with Red Rapha\xebl " + R.version));
+ c.appendChild(this.desc);
+ c.appendChild(this.defs = $("defs"));
+ };
+
+ R.prototype.remove = function() {
+ eve("raphael.remove", this);
+ this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
+ for (var i in this) {
+ this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+ }
+ this.removed = true;
+ };
+ var setproto = R.st;
+ for (var method in elproto)
+ if (elproto[has](method) && !setproto[has](method)) {
+ setproto[method] = (function(methodname) {
+ return function() {
+ var arg = arguments;
+ return this.forEach(function(el) {
+ el[methodname].apply(el, arg);
+ });
+ };
+ })(method);
+ }
+}(window.Raphael);
diff --git a/source/raphael.vml.js b/source/raphael.vml.js
new file mode 100644
index 0000000..ca081fc
--- /dev/null
+++ b/source/raphael.vml.js
@@ -0,0 +1,1257 @@
+/**!
+* RedRaphael 1.0.0 - JavaScript Vector Library VML Module
+* Copyright (c) 2012-2013 FusionCharts Technologies
+*
+* Raphael 2.1.0 - JavaScript Vector Library VML Module
+* Copyright (c) 2008-2012 Dmitry Baranovskiy
+* Copyright © 2008-2012 Sencha Labs
+*
+* Licensed under the MIT license.
+*/
+
+window.Raphael && window.Raphael.vml && function(R) {
+ var has = "hasOwnProperty",
+ Str = String,
+ toFloat = parseFloat,
+ math = Math,
+ round = math.round,
+ mmax = math.max,
+ mmin = math.min,
+ sqrt = math.sqrt,
+ abs = math.abs,
+ fillString = "fill",
+ separator = /[, ]+/,
+ eve = R.eve,
+ ms = " progid:DXImageTransform.Microsoft",
+ S = " ",
+ E = "",
+ map = {
+ M: "m",
+ L: "l",
+ C: "c",
+ Z: "x",
+ m: "t",
+ l: "r",
+ c: "v",
+ z: "x"
+ },
+ bites = /([clmz]),?([^clmz]*)/gi,
+ blurregexp = / progid:\S+Blur\([^\)]+\)/g,
+ val = /-?[^,\s-]+/g,
+ cssDot = "position:absolute;left:0;top:0;width:1px;height:1px",
+ zoom = 21600,
+ pathTypes = {
+ path: 1,
+ rect: 1,
+ image: 1
+ },
+ ovalTypes = {
+ circle: 1,
+ ellipse: 1
+ },
+ path2vml = function(path) {
+ var total = /[ahqstv]/ig,
+ command = R._pathToAbsolute;
+ Str(path).match(total) && (command = R._path2curve);
+ total = /[clmz]/g;
+ if (command == R._pathToAbsolute && !Str(path).match(total)) {
+ var res = Str(path).replace(bites, function(all, command, args) {
+ var vals = [],
+ isMove = command.toLowerCase() == "m",
+ res = map[command];
+ args.replace(val, function(value) {
+ if (isMove && vals.length == 2) {
+ res += vals + map[command == "m" ? "l" : "L"];
+ vals = [];
+ }
+ vals.push(round(value * zoom));
+ });
+ return res + vals;
+ });
+
+ return res || 'm0,0';
+ }
+ var pa = command(path), p, r;
+ res = [];
+ for (var i = 0, ii = pa.length; i < ii; i++) {
+ p = pa[i];
+ r = pa[i][0].toLowerCase();
+ r == "z" && (r = "x");
+ for (var j = 1, jj = p.length; j < jj; j++) {
+ r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
+ }
+ res.push(r);
+ }
+ return res.length ? res.join(S) : 'm0,0';
+ },
+ compensation = function(deg, dx, dy) {
+ var m = R.matrix();
+ m.rotate(-deg, .5, .5);
+ return {
+ dx: m.x(dx, dy),
+ dy: m.y(dx, dy)
+ };
+ },
+ setCoords = function(p, sx, sy, dx, dy, deg) {
+ var _ = p._,
+ m = p.matrix,
+ fillpos = _.fillpos,
+ o = p.node,
+ s = o.style,
+ y = 1,
+ flip = "",
+ dxdy,
+ kx = zoom / sx,
+ ky = zoom / sy;
+ s.visibility = "hidden";
+ if (!sx || !sy) {
+ return;
+ }
+ o.coordsize = abs(kx) + S + abs(ky);
+ s.rotation = deg * (sx * sy < 0 ? -1 : 1);
+ if (deg) {
+ var c = compensation(deg, dx, dy);
+ dx = c.dx;
+ dy = c.dy;
+ }
+ sx < 0 && (flip += "x");
+ sy < 0 && (flip += " y") && (y = -1);
+ s.flip = flip;
+ o.coordorigin = (dx * -kx) + S + (dy * -ky);
+ if (fillpos || _.fillsize) {
+ var fill = o.getElementsByTagName(fillString);
+ fill = fill && fill[0];
+ o.removeChild(fill);
+ if (fillpos) {
+ c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1]));
+ fill.position = c.dx * y + S + c.dy * y;
+ }
+ if (_.fillsize) {
+ fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy);
+ }
+ o.appendChild(fill);
+ }
+ s.visibility = "visible";
+ };
+ R._url = E;
+ R.toString = function() {
+ return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
+ };
+ var addArrow = function(o, value, isEnd) {
+ var values = Str(value).toLowerCase().split("-"),
+ se = isEnd ? "end" : "start",
+ i = values.length,
+ type = "classic",
+ w = "medium",
+ h = "medium";
+ while (i--) {
+ switch (values[i]) {
+ case "block":
+ case "classic":
+ case "oval":
+ case "diamond":
+ case "open":
+ case "none":
+ type = values[i];
+ break;
+ case "wide":
+ case "narrow":
+ h = values[i];
+ break;
+ case "long":
+ case "short":
+ w = values[i];
+ break;
+ }
+ }
+ var stroke = o.node.getElementsByTagName("stroke")[0];
+ stroke[se + "arrow"] = type;
+ stroke[se + "arrowlength"] = w;
+ stroke[se + "arrowwidth"] = h;
+ },
+ setFillAndStroke = R._setFillAndStroke = function(o, params) {
+ if (!o.paper.canvas) return;
+ // o.paper.canvas.style.display = "none";
+ o.attrs = o.attrs || {};
+ var node = o.node,
+ a = o.attrs,
+ s = node.style,
+ xy,
+ newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r),
+ isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry),
+ isGroup = o.type === 'group',
+ res = o;
+
+
+ for (var par in params)
+ if (params[has](par)) {
+ a[par] = params[par];
+ }
+ if (newpath) {
+ a.path = R._getPath[o.type](o);
+ o._.dirty = 1;
+ }
+ params.href && (node.href = params.href);
+ params.title && (node.title = params.title);
+ params.target && (node.target = params.target);
+ params.cursor && (s.cursor = params.cursor);
+ "blur" in params && o.blur(params.blur);
+ if (params.path && o.type == "path" || newpath) {
+ node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path);
+ if (o.type == "image") {
+ o._.fillpos = [a.x, a.y];
+ o._.fillsize = [a.width, a.height];
+ setCoords(o, 1, 1, 0, 0, 0);
+ }
+ }
+ "transform" in params && o.transform(params.transform);
+ if ("rotation" in params) {
+ var rotation = params.rotation;
+ if (R.is(rotation, "array")) {
+ o.rotate.apply(o, rotation);
+ }
+ else {
+ o.rotate(rotation);
+ }
+ }
+ if ("visibility" in params) {
+ params.visibility === 'hidden' ? o.hide() : o.show();
+ }
+ if (isOval) {
+ var cx = +a.cx,
+ cy = +a.cy,
+ rx = +a.rx || +a.r || 0,
+ ry = + a.ry || + a.r || 0;
+ node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom));
+ }
+ if ("clip-rect" in params) {
+ var rect = Str(params["clip-rect"]).split(separator);
+
+ if (rect.length == 4) {
+ rect[0] = +rect[0];
+ rect[1] = +rect[1];
+ rect[2] = +rect[2] + rect[0];
+ rect[3] = +rect[3] + rect[1];
+
+ /* @todo create separate element for group clip-rect to
+ * avoid unclipping issue */
+ var div = isGroup ? node : (node.clipRect ||
+ R._g.doc.createElement("div")),
+ offset,
+ dstyle = div.style;
+
+ if (isGroup) {
+ o.clip = rect.slice(); // copy param
+ offset = o.matrix.offset();
+ offset = [toFloat(offset[0]), toFloat(offset[1])];
+ // invert matrix calculation
+ rect[0] -= offset[0];
+ rect[1] -= offset[1];
+ rect[2] -= offset[0];
+ rect[3] -= offset[1];
+ // Fix for bug in ie clip-auto when height/width is not defined
+ /* @todo set dynamic w/h based on clip bounds or find
+ * another workaround fix */
+ dstyle.width = "10800px";
+ dstyle.height = "10800px";
+ }
+ else if (!node.clipRect) {
+ dstyle.top = "0";
+ dstyle.left = "0";
+ dstyle.width = o.paper.width + "px";
+ dstyle.height = o.paper.height + "px";
+ node.parentNode.insertBefore(div, node);
+ div.appendChild(node);
+ node.clipRect = div;
+ }
+ dstyle.position = "absolute";
+ dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
+ }
+ if (!params["clip-rect"]) {
+ if (isGroup && o.clip) {
+ node.style.clip = "rect(auto auto auto auto)";
+ delete o.clip;
+ }
+ else if (node.clipRect) {
+ node.clipRect.style.clip = "rect(auto auto auto auto)";
+ }
+ }
+ }
+ if (o.textpath) {
+ var textpathStyle = o.textpath.style;
+ params.font && (textpathStyle.font = params.font);
+ params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"');
+ params["font-size"] && (textpathStyle.fontSize = params["font-size"]);
+ params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]);
+ params["font-style"] && (textpathStyle.fontStyle = params["font-style"]);
+ }
+ if ("arrow-start" in params) {
+ addArrow(res, params["arrow-start"]);
+ }
+ if ("arrow-end" in params) {
+ addArrow(res, params["arrow-end"], 1);
+ }
+ if (params.opacity != null ||
+ params["stroke-width"] != null ||
+ params.fill != null ||
+ params.src != null ||
+ params.stroke != null ||
+ params["stroke-width"] != null ||
+ params["stroke-opacity"] != null ||
+ params["fill-opacity"] != null ||
+ params["stroke-dasharray"] != null ||
+ params["stroke-miterlimit"] != null ||
+ params["stroke-linejoin"] != null ||
+ params["stroke-linecap"] != null) {
+ var fill = node.getElementsByTagName(fillString),
+ newfill = false,
+ fillOpacity = -1;
+ fill = fill && fill[0];
+ !fill && (newfill = fill = createNode(fillString));
+ if (o.type == "image" && params.src) {
+ fill.src = params.src;
+ }
+ params.fill && (fill.on = true);
+ if (fill.on == null || params.fill == "none" || params.fill === null) {
+ fill.on = false;
+ }
+ if (fill.on && params.fill) {
+ var isURL = Str(params.fill).match(R._ISURL);
+ if (isURL) {
+ fill.parentNode == node && node.removeChild(fill);
+ fill.rotate = true;
+ fill.src = isURL[1];
+ fill.type = "tile";
+ var bbox = o.getBBox(1);
+ fill.position = bbox.x + S + bbox.y;
+ o._.fillpos = [bbox.x, bbox.y];
+
+ R._preload(isURL[1], function() {
+ o._.fillsize = [this.offsetWidth, this.offsetHeight];
+ });
+ } else {
+ var color = R.getRGB(params.fill);
+ fill.color = color.hex;
+ fill.src = E;
+ fill.type = "solid";
+ if (color.error && (res.type in {
+ circle: 1,
+ ellipse: 1
+ } || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) {
+ a.fill = "none";
+ a.gradient = params.fill;
+ fill.rotate = false;
+ }
+ else if ("opacity" in color && !("fill-opacity" in params)) {
+ fillOpacity = color.opacity;
+ }
+ }
+ }
+ if (fillOpacity !== -1 || "fill-opacity" in params || "opacity" in params) {
+ var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+fillOpacity + 1 || 2) - 1);
+ opacity = mmin(mmax(opacity, 0), 1);
+ fill.opacity = opacity;
+ if (fill.src) {
+ fill.color = "none";
+ }
+ }
+ node.appendChild(fill);
+ var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
+ newstroke = false;
+ !stroke && (newstroke = stroke = createNode("stroke"));
+ if ((params.stroke && params.stroke != "none") ||
+ params["stroke-width"] ||
+ params["stroke-opacity"] != null ||
+ params["stroke-dasharray"] ||
+ params["stroke-miterlimit"] ||
+ params["stroke-linejoin"] ||
+ params["stroke-linecap"]) {
+ stroke.on = true;
+ }
+ (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
+ var strokeColor = R.getRGB(('stroke' in params) ? params.stroke : a.stroke);
+ stroke.on && params.stroke && (stroke.color = strokeColor.hex);
+ opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.opacity + 1 || 2) - 1);
+ var width = (toFloat(params["stroke-width"]) || 1) * .75;
+ opacity = mmin(mmax(opacity, 0), 1);
+ params["stroke-width"] == null && (width = a["stroke-width"]);
+ params["stroke-width"] && (stroke.weight = width);
+ width && width < 1 && (opacity *= width) && (stroke.weight = 1);
+ stroke.opacity = opacity;
+
+ params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"]) || newstroke && (newstroke.joinstyle = 'miter');
+ stroke.miterlimit = params["stroke-miterlimit"] || 8;
+ params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
+ if (params["stroke-dasharray"]) {
+ var dasharray = {
+ "-": "shortdash",
+ ".": "shortdot",
+ "-.": "shortdashdot",
+ "-..": "shortdashdotdot",
+ ". ": "dot",
+ "- ": "dash",
+ "--": "longdash",
+ "- .": "dashdot",
+ "--.": "longdashdot",
+ "--..": "longdashdotdot"
+ };
+ stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] :
+ ((params["stroke-dasharray"].join && params["stroke-dasharray"].join(' ')) || E);
+ }
+ newstroke && node.appendChild(stroke);
+ }
+ if (res.type == "text") {
+ res.paper.canvas.style.display = E;
+ var span = res.paper.span,
+ m = 100,
+ fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/),
+ lineHeight = a['line-height'] && (a['line-height']+E).match(/\d+(?:\.\d*)?(?=px)/);
+ s = span.style;
+ a.font && (s.font = a.font);
+ a["font-family"] && (s.fontFamily = a["font-family"]);
+ a["font-weight"] && (s.fontWeight = a["font-weight"]);
+ a["font-style"] && (s.fontStyle = a["font-style"]);
+ fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10;
+ s.fontSize = fontSize * m + "px";
+ lineHeight = toFloat(a["line-height"] || lineHeight && lineHeight[0]) || 12;
+ a["line-height"] && (s.lineHeight = lineHeight * m + 'px');
+ res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/"));
+ var brect = span.getBoundingClientRect();
+ res.W = a.w = (brect.right - brect.left) / m;
+ res.H = a.h = (brect.bottom - brect.top) / m;
+ // res.paper.canvas.style.display = "none";
+ res.X = a.x;
+ res.Y = a.y;
+ var leading = lineHeight - fontSize;
+ switch(a["vertical-align"]) {
+ case "top":
+ res.bby = res.H / 2; // + leading;
+ break;
+ case "bottom":
+ res.bby = -res.H / 2; // - leading;
+ break;
+ default:
+ res.bby = 0;
+ }
+
+ ("x" in params || "y" in params || res.bby !== undefined) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round((a.y + (res.bby || 0)) * zoom), round(a.x * zoom) + 1));
+ var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size", "line-height"];
+ for (var d = 0, dd = dirtyattrs.length; d < dd; d++)
+ if (dirtyattrs[d] in params) {
+ res._.dirty = 1;
+ break;
+ }
+
+ // text-anchor emulation
+ switch (a["text-anchor"]) {
+ case "start":
+ res.textpath.style["v-text-align"] = "left";
+ res.bbx = res.W / 2;
+ break;
+ case "end":
+ res.textpath.style["v-text-align"] = "right";
+ res.bbx = -res.W / 2;
+ break;
+ default:
+ res.textpath.style["v-text-align"] = "center";
+ res.bbx = 0;
+ break;
+ }
+ res.textpath.style["v-text-kern"] = true;
+ }
+ // res.paper.canvas.style.display = E;
+ },
+ addGradientFill = function(o, gradient, fill) {
+ o.attrs = o.attrs || {};
+ var attrs = o.attrs,
+ pow = Math.pow,
+ opacity,
+ oindex,
+ type = "linear",
+ fxfy = ".5 .5";
+ o.attrs.gradient = gradient;
+ gradient = Str(gradient).replace(R._radial_gradient, function(all, opts) {
+ type = "radial";
+ opts = opts && opts.split(',') || [];
+
+ // fx,fy of vml is cx,cy of svg
+ var cx = opts[0],
+ cy = opts[1],
+ r = opts[2],
+ fx = opts[3],
+ fy = opts[4],
+ units = opts[5];
+ if (fx && fy) {
+ fx = toFloat(fx);
+ fy = toFloat(fy);
+ pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
+ fxfy = fx + S + fy;
+ }
+ return E;
+ });
+ gradient = gradient.split(/\s*\-\s*/);
+ if (type == "linear") {
+ var angle = gradient.shift();
+ angle = -toFloat(angle);
+ if (isNaN(angle)) {
+ return null;
+ }
+ }
+ var dots = R._parseDots(gradient);
+ if (!dots) {
+ return null;
+ }
+ o = o.shape || o.node;
+ if (dots.length) {
+ o.removeChild(fill);
+ fill.on = true;
+ fill.method = "none";
+ fill.color = dots[0].color;
+ fill.color2 = dots[dots.length - 1].color;
+ //For VML use first and last available alpha
+ var clrs = [],
+ opacity1 = 1,
+ opacity2 = dots[0].opacity === undefined ? 1 : dots[0].opacity;
+ for (var i = 0, ii = dots.length; i < ii; i++) {
+ dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color);
+ if (dots[i].opacity !== undefined) {
+ opacity1 = dots[i].opacity;//update with latest avaible opacity
+ }
+ }
+ fill.colors = clrs.length ? clrs.join() : "0% " + fill.color;
+ //set opacity1 & opacity2
+ fill.opacity = opacity1;
+ fill['o:opacity2'] = opacity2;
+ if (type == "radial") {
+ fill.type = "gradientTitle";
+ fill.focus = "100%";
+ fill.focussize = "0 0";
+ fill.focusposition = fxfy;
+ fill.angle = 0;
+ } else {
+ // fill.rotate= true;
+ fill.type = "gradient";
+ fill.angle = (270 - angle) % 360;
+ }
+ o.appendChild(fill);
+ }
+ return 1;
+ },
+ Element = function(node, vml, group) {
+ var o = this,
+ parent = group || vml;
+
+ o.node = o[0] = node;
+ node.raphael = true;
+ node.raphaelid = o.id = R._oid++;
+
+ o.X = 0;
+ o.Y = 0;
+
+ o.attrs = o.attrs || {};
+ o.styles = o.styles || {};
+ o.followers = o.followers || [];
+
+ o.paper = vml;
+ o.ca = o.customAttributes = o.customAttributes ||
+ new vml._CustomAttributes();
+
+ o.matrix = R.matrix();
+ o._ = {
+ transform: [],
+ sx: 1,
+ sy: 1,
+ dx: 0,
+ dy: 0,
+ deg: 0,
+ dirty: 1,
+ dirtyT: 1
+ };
+
+ o.parent = parent;
+ !parent.bottom && (parent.bottom = o);
+
+ o.prev = parent.top;
+ parent.top && (parent.top.next = o);
+ parent.top = o;
+ o.next = null;
+ };
+ var elproto = R.el;
+
+ Element.prototype = elproto;
+ elproto.constructor = Element;
+
+ elproto.transform = function(tstr) {
+ if (tstr == null) {
+ return this._.transform;
+ }
+ var vbs = this.paper._viewBoxShift,
+ vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
+ oldt;
+
+ if (vbs) {
+ oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E);
+ }
+
+ R._extractTransform(this, vbt + tstr);
+
+ var matrix = this.matrix.clone(),
+ skew = this.skew,
+ o = this.node,
+ split,
+ isGrad = ~Str(this.attrs.fill).indexOf("-"),
+ isPatt = !Str(this.attrs.fill).indexOf("url(");
+ matrix.translate(-.5, -.5);
+ if (isPatt || isGrad || this.type == "image") {
+ skew.matrix = "1 0 0 1";
+ skew.offset = "0 0";
+ split = matrix.split();
+ if ((isGrad && split.noRotation) || !split.isSimple) {
+ o.style.filter = matrix.toFilter();
+ var bb = this.getBBox(),
+ bbt = this.getBBox(1),
+ xget = bb.x2 && bbt.x2 && 'x2' || 'x',
+ yget = bb.y2 && bbt.y2 && 'y2' || 'y',
+ dx = bb[xget] - bbt[xget],
+ dy = bb[yget] - bbt[yget];
+ o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
+ setCoords(this, 1, 1, dx, dy, 0);
+ } else {
+ o.style.filter = E;
+ setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
+ }
+ } else {
+ o.style.filter = E;
+ skew.matrix = Str(matrix);
+ skew.offset = matrix.offset();
+ }
+ oldt && (this._.transform = oldt);
+
+ return this;
+ };
+ elproto.rotate = function(deg, cx, cy) {
+ if (this.removed) {
+ return this;
+ }
+ if (deg == null) {
+ return;
+ }
+ deg = Str(deg).split(separator);
+ if (deg.length - 1) {
+ cx = toFloat(deg[1]);
+ cy = toFloat(deg[2]);
+ }
+ deg = toFloat(deg[0]);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ var bbox = this.getBBox(1);
+ cx = bbox.x + bbox.width / 2;
+ cy = bbox.y + bbox.height / 2;
+ }
+ this._.dirtyT = 1;
+ this.transform(this._.transform.concat([["r", deg, cx, cy]]));
+ return this;
+ };
+ elproto.translate = function(dx, dy) {
+ if (this.removed) {
+ return this;
+ }
+ dx = Str(dx).split(separator);
+ if (dx.length - 1) {
+ dy = toFloat(dx[1]);
+ }
+ dx = toFloat(dx[0]) || 0;
+ dy = +dy || 0;
+ if (this._.bbox) {
+ this._.bbox.x += dx;
+ this._.bbox.y += dy;
+ }
+ this.transform(this._.transform.concat([["t", dx, dy]]));
+ return this;
+ };
+ elproto.scale = function(sx, sy, cx, cy) {
+ if (this.removed) {
+ return this;
+ }
+ sx = Str(sx).split(separator);
+ if (sx.length - 1) {
+ sy = toFloat(sx[1]);
+ cx = toFloat(sx[2]);
+ cy = toFloat(sx[3]);
+ isNaN(cx) && (cx = null);
+ isNaN(cy) && (cy = null);
+ }
+ sx = toFloat(sx[0]);
+ (sy == null) && (sy = sx);
+ (cy == null) && (cx = cy);
+ if (cx == null || cy == null) {
+ var bbox = this.getBBox(1);
+ }
+ cx = cx == null ? bbox.x + bbox.width / 2 : cx;
+ cy = cy == null ? bbox.y + bbox.height / 2 : cy;
+
+ this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
+ this._.dirtyT = 1;
+ return this;
+ };
+ elproto.hide = function(soft) {
+ var o = this;
+ !o.removed && (o.node.style.display = "none");
+ return o;
+ };
+
+ elproto.show = function(soft) {
+ var o = this;
+ !o.removed && (o.node.style.display = E);
+ return o;
+ };
+ elproto._getBBox = function() {
+ if (this.removed) {
+ return {};
+ }
+ return {
+ x: this.X + (this.bbx || 0) - this.W / 2,
+ y: this.Y + (this.bby || 0) - this.H / 2,
+ width: this.W,
+ height: this.H
+ };
+ };
+ elproto.remove = function() {
+ if (this.removed || !this.parent.canvas) {
+ return;
+ }
+ var i,
+ thisNode = R._engine.getNode(this);
+ this.paper.__set__ && this.paper.__set__.exclude(this);
+ eve.unbind("raphael.*.*." + this.id);
+ while (i = this.followers.pop()) {
+ i.el.remove();
+ }
+ this.shape && this.shape.parentNode.removeChild(this.shape);
+ thisNode.parentNode.removeChild(thisNode);
+ R._tear(this, this.paper);
+ for (var i in this) {
+ this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+ }
+ this.removed = true;
+ };
+ elproto.css = function (name, value) {
+ // do not parse css in case element is removed.
+ if (this.removed) {
+ return this;
+ }
+
+ // process as getter when a single key is sent as parameter.
+ if (value == null && R.is(name, "string")) {
+ var names = name.split(separator),
+ out = {};
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in this.styles) {
+ out[name] = this.styles[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+ // process as getter when multiple keys are pre-sent as array.
+ if (value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = this.styles(name[i]);
+ }
+ return out;
+ }
+ // convert single key-value setter into object style standard.
+ if (value != null) {
+ var params = {};
+ params[name] = value;
+ } else if (name != null && R.is(name, "object")) {
+ params = name;
+ }
+ // iterate on keys and set style or raise events.
+ var otherkey, doattrs = {};
+ for (var key in params) {
+ otherkey = key.replace(/\B([A-Z]{1})/g, "-$1").toLowerCase();
+ // Replace "color" with fill
+ (otherkey === 'color' && this.type === 'text') && (otherkey = 'fill');
+ // If keys are supported via attr then use attr instead of css.
+ if (R._availableAttrs[has](otherkey)) {
+ doattrs[otherkey] = params[key];
+ doattrs.dirty = true;
+ continue;
+ }
+ eve("raphael.css." + otherkey + "." + this.id, this, params[key], otherkey);
+ (params[key] != undefined) && (this.node.style[otherkey] = params[key]);
+ this.styles[otherkey] = params[key];
+ }
+
+ for (i = 0, ii = this.followers.length; i < ii; i++) {
+ this.followers[i].el.css(params);
+ }
+
+ // apply css via attrs
+ if (doattrs[has]("dirty")) {
+ delete doattrs.dirty;
+ this.attr(doattrs);
+ }
+
+ return this;
+ };
+ elproto.attr = function(name, value) {
+ if (this.removed) {
+ return this;
+ }
+ if (name == null) {
+ var res = {};
+ for (var a in this.attrs)
+ if (this.attrs[has](a)) {
+ res[a] = this.attrs[a];
+ }
+ res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
+ res.transform = this._.transform;
+ res.visibility = this.node.style.display === "none" ? "hidden" : "visible";
+ return res;
+ }
+ if (value == null && R.is(name, "string")) {
+ if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
+ return this.attrs.gradient;
+ }
+ if (name == "visibility") {
+ return this.node.style.display === "none" ? "hidden" : "visible";
+ }
+ var names = name.split(separator),
+ out = {};
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ name = names[i];
+ if (name in this.attrs) {
+ out[name] = this.attrs[name];
+ } else if (R.is(this.ca[name], "function")) {
+ out[name] = this.ca[name].def;
+ } else {
+ out[name] = R._availableAttrs[name];
+ }
+ }
+ return ii - 1 ? out : out[names[0]];
+ }
+ if (this.attrs && value == null && R.is(name, "array")) {
+ out = {};
+ for (i = 0, ii = name.length; i < ii; i++) {
+ out[name[i]] = this.attr(name[i]);
+ }
+ return out;
+ }
+ var params;
+ if (value != null) {
+ params = {};
+ params[name] = value;
+ }
+ value == null && R.is(name, "object") && (params = name);
+ for (var key in params) {
+ eve("raphael.attr." + key + "." + this.id, this, params[key], key);
+ }
+ if (params) {
+ var todel = {};
+ for (key in this.ca)
+ if (this.ca[key] && params[has](key) && R.is(this.ca[key], "function") && !this.ca['_invoked' + key]) {
+ this.ca['_invoked' + key] = true; // prevent recursion
+ var par = this.ca[key].apply(this, [].concat(params[key]));
+ delete this.ca['_invoked' + key];
+
+ for (var subkey in par) {
+ if (par[has](subkey)) {
+ params[subkey] = par[subkey];
+ }
+ }
+ this.attrs[key] = params[key];
+ if (par === false) {
+ todel[key] = params[key];
+ delete params[key];
+ }
+ }
+ // this.paper.canvas.style.display = "none";
+ if ('text' in params && this.type == "text") {
+ this.textpath.string = params.text.replace(/ /ig, '\n');
+ }
+ setFillAndStroke(this, params);
+ var follower;
+ for (i = 0, ii = this.followers.length; i < ii; i++) {
+ follower = this.followers[i];
+ (follower.cb && !follower.cb.call(follower.el, params, this)) ||
+ follower.el.attr(params);
+ }
+ for (var subkey in todel) {
+ params[subkey] = todel[subkey];
+ }
+ // this.paper.canvas.style.display = E;
+ }
+ return this;
+ };
+
+ elproto.blur = function(size) {
+ var s = this.node.runtimeStyle,
+ f = s.filter;
+ f = f.replace(blurregexp, E);
+ if (+size !== 0) {
+ this.attrs.blur = size;
+ s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")";
+ s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5));
+ } else {
+ s.filter = f;
+ s.margin = 0;
+ delete this.attrs.blur;
+ }
+ return this;
+ };
+
+ elproto.on = function(eventType, handler) {
+ if (this.removed) {
+ return this;
+ }
+
+ this.node['on'+ eventType] = function() {
+ var evt = R._g.win.event;
+ evt.target = evt.srcElement;
+ handler(evt);
+ };
+ return this;
+ };
+
+ R._engine.getNode = function (el) {
+ var node = el.node || el[0].node;
+ return node.clipRect || node;
+ };
+ R._engine.getLastNode = function (el) {
+ var node = el.node || el[el.length - 1].node;
+ return node.clipRect || node;
+ };
+
+ R._engine.group = function(vml, id, group) {
+ var el = R._g.doc.createElement("div"),
+ p = new Element(el, vml, group);
+
+ el.style.cssText = cssDot;
+
+ id && (el.className = ['red', id, p.id].join('-'));
+ (group || vml).canvas.appendChild(el);
+
+ p.type = 'group';
+ p.canvas = p.node;
+ p.transform = R._engine.group.transform;
+ p.top = null;
+ p.bottom = null;
+
+ return p;
+ };
+
+ R._engine.group.transform = function(tstr) {
+ if (tstr == null) {
+ return this._.transform;
+ }
+
+ var o = this,
+ s = o.node.style,
+ c = o.clip,
+ vbs = o.paper._viewBoxShift,
+ vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
+ oldt,
+ matrix,
+ offset,
+ tx,
+ ty;
+
+ if (vbs) {
+ oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, o._.transform || E);
+ }
+ R._extractTransform(o, vbt + tstr);
+ matrix = o.matrix;
+ offset = matrix.offset();
+ tx = toFloat(offset[0]) || 0;
+ ty = toFloat(offset[1]) || 0;
+
+ s.left = tx + "px";
+ s.top = ty + "px";
+ s.zoom = (o._.tzoom = matrix.get(0)) + E;
+
+ /* @todo try perform relative group transform, thus avoiding
+ * transform on clipping */
+ c && (s.clip = R.format("rect({1}px {2}px {3}px {0}px)", [
+ c[0] - tx, c[1] - ty, c[2] - tx, c[3] - ty
+ ]));
+
+ return o;
+ };
+
+ R._engine.path = function(pathString, vml, group) {
+ var el = createNode("shape");
+ el.style.cssText = cssDot;
+ el.coordsize = zoom + S + zoom;
+ el.coordorigin = vml.coordorigin;
+ var p = new Element(el, vml, group),
+ attr = {
+ fill: "none",
+ stroke: "#000"
+ };
+
+ pathString && (attr.path = pathString);
+ p.type = "path";
+ p.path = [];
+ p.Path = E;
+ setFillAndStroke(p, attr);
+ (group || vml).canvas.appendChild(el);
+
+ var skew = createNode("skew");
+ skew.on = true;
+ el.appendChild(skew);
+ p.skew = skew;
+ return p;
+ };
+
+ R._engine.rect = function(vml, x, y, w, h, r, group) {
+ var path = R._rectPath(x, y, w, h, r),
+ res = vml.path(path, group),
+ a = res.attrs;
+ res.X = a.x = x;
+ res.Y = a.y = y;
+ res.W = a.width = w;
+ res.H = a.height = h;
+ a.r = r;
+ a.path = path;
+ res.type = "rect";
+ return res;
+ };
+ R._engine.ellipse = function(vml, x, y, rx, ry, group) {
+ var res = vml.path(undefined, group);
+ res.X = x - rx;
+ res.Y = y - ry;
+ res.W = rx * 2;
+ res.H = ry * 2;
+ res.type = "ellipse";
+ setFillAndStroke(res, {
+ cx: x,
+ cy: y,
+ rx: rx,
+ ry: ry
+ });
+ return res;
+ };
+ R._engine.circle = function(vml, x, y, r, group) {
+ var res = vml.path(undefined, group);
+ res.X = x - r;
+ res.Y = y - r;
+ res.W = res.H = r * 2;
+ res.type = "circle";
+ setFillAndStroke(res, {
+ cx: x,
+ cy: y,
+ r: r
+ });
+ return res;
+ };
+ R._engine.image = function(vml, src, x, y, w, h, group) {
+ var path = R._rectPath(x, y, w, h),
+ res = vml.path(path, group).attr({
+ stroke: "none"
+ }),
+ a = res.attrs,
+ node = res.node,
+ fill = node.getElementsByTagName(fillString)[0];
+ a.src = src;
+ res.X = a.x = x;
+ res.Y = a.y = y;
+ res.W = a.width = w;
+ res.H = a.height = h;
+ a.path = path;
+ res.type = "image";
+ fill.parentNode == node && node.removeChild(fill);
+ fill.rotate = true;
+ fill.src = src;
+ fill.type = "tile";
+ res._.fillpos = [x, y];
+ res._.fillsize = [w, h];
+ node.appendChild(fill);
+ setCoords(res, 1, 1, 0, 0, 0);
+ return res;
+ };
+ R._engine.text = function(vml, x, y, text, group) {
+ var el = createNode("shape"),
+ path = createNode("path"),
+ o = createNode("textpath");
+ x = x || 0;
+ y = y || 0;
+ text = text;
+ path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1);
+ path.textpathok = true;
+ o.string = Str(text).replace(/ /ig, '\n');
+ o.on = true;
+ el.style.cssText = cssDot;
+ el.coordsize = zoom + S + zoom;
+ el.coordorigin = "0 0";
+ var p = new Element(el, vml, group),
+ attr = {
+ fill: "#000",
+ stroke: "none",
+ text: text
+ };
+
+ p.shape = el;
+ p.path = path;
+ p.textpath = o;
+ p.type = "text";
+ p.attrs.text = Str(text || E);
+ p.attrs.x = x;
+ p.attrs.y = y;
+ p.attrs.w = 1;
+ p.attrs.h = 1;
+ setFillAndStroke(p, attr);
+ el.appendChild(o);
+ el.appendChild(path);
+ (group || vml).canvas.appendChild(el);
+
+ var skew = createNode("skew");
+ skew.on = true;
+ el.appendChild(skew);
+ p.skew = skew;
+ return p;
+ };
+
+ R._engine.setSize = function(width, height) {
+ var cs = this.canvas.style;
+ this.width = width;
+ this.height = height;
+ width == +width && (width += "px");
+ height == +height && (height += "px");
+ cs.width = width;
+ cs.height = height;
+ cs.clip = "rect(0 " + width + " " + height + " 0)";
+ if (this._viewBox) {
+ R._engine.setViewBox.apply(this, this._viewBox);
+ }
+ return this;
+ };
+ R._engine.setViewBox = function(x, y, w, h, fit) {
+ eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]);
+ var width = this.width,
+ height = this.height,
+ size = 1 / mmax(w / width, h / height),
+ H, W;
+ if (fit) {
+ H = height / h;
+ W = width / w;
+ if (w * H < width) {
+ x -= (width - w * H) / 2 / H;
+ }
+ if (h * W < height) {
+ y -= (height - h * W) / 2 / W;
+ }
+ }
+ this._viewBox = [x, y, w, h, !!fit];
+ this._viewBoxShift = {
+ dx: -x,
+ dy: -y,
+ scale: size
+ };
+ this.forEach(function(el) {
+ el.transform("...");
+ });
+ return this;
+ };
+ var createNode;
+ R._engine.initWin = function(win) {
+ var doc = win.document;
+ doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
+ try {
+ !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
+ createNode = R._createNode = function(tagName, attrs) {
+ var el = doc.createElement(''),
+ prop;
+ for (prop in attrs) {
+ el[prop] = Str(attrs[prop]);
+ }
+ return el;
+ };
+ } catch (e) {
+ createNode = R._createNode = function(tagName, attrs) {
+ var el = doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'),
+ prop;
+ for (prop in attrs) {
+ el[prop] = Str(attrs[prop]);
+ }
+ return el;
+ };
+ }
+ };
+ R._engine.initWin(R._g.win);
+ R._engine.create = function() {
+ var con = R._getContainer.apply(0, arguments),
+ container = con.container,
+ height = con.height,
+ s,
+ width = con.width,
+ x = con.x,
+ y = con.y;
+ if (!container) {
+ throw new Error("VML container not found.");
+ }
+ var res = new R._Paper,
+ c = res.canvas = R._g.doc.createElement("div"),
+ cs = c.style;
+ x = x || 0;
+ y = y || 0;
+ width = width || 512;
+ height = height || 342;
+ res.width = width;
+ res.height = height;
+ width == +width && (width += "px");
+ height == +height && (height += "px");
+ res.coordsize = zoom * 1e3 + S + zoom * 1e3;
+ res.coordorigin = "0 0";
+ res.span = R._g.doc.createElement("span");
+ res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;";
+ c.appendChild(res.span);
+ cs.cssText = R.format("top:0;left:0;width:{0};height:{1};display:inline-block;cursor:default;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden", width, height);
+ if (container == 1) {
+ R._g.doc.body.appendChild(c);
+ cs.left = x + "px";
+ cs.top = y + "px";
+ cs.position = "absolute";
+ } else {
+ if (container.firstChild) {
+ container.insertBefore(c, container.firstChild);
+ } else {
+ container.appendChild(c);
+ }
+ }
+ res.renderfix = function() {
+ };
+ return res;
+ };
+ R.prototype.clear = function() {
+ eve("raphael.clear", this);
+ this.canvas.innerHTML = E;
+ this.span = R._g.doc.createElement("span");
+ this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
+ this.canvas.appendChild(this.span);
+ this.bottom = this.top = null;
+ };
+ R.prototype.remove = function() {
+ eve("raphael.remove", this);
+ this.canvas.parentNode.removeChild(this.canvas);
+ for (var i in this) {
+ this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+ }
+ return true;
+ };
+
+ var setproto = R.st;
+ for (var method in elproto)
+ if (elproto[has](method) && !setproto[has](method)) {
+ setproto[method] = (function(methodname) {
+ return function() {
+ var arg = arguments;
+ return this.forEach(function(el) {
+ el[methodname].apply(el, arg);
+ });
+ };
+ })(method);
+ }
+}(window.Raphael);
\ No newline at end of file
diff --git a/source/separator b/source/separator
new file mode 100644
index 0000000..e69de29
diff --git a/tests/basic/baseTestSpec.js b/tests/basic/baseTestSpec.js
new file mode 100644
index 0000000..9ae3a31
--- /dev/null
+++ b/tests/basic/baseTestSpec.js
@@ -0,0 +1,40 @@
+describe('My First Test', function () {
+ var paper,
+ first,
+ second,
+ end;
+
+ it('Raphael constructor exists', function () {
+ expect(Raphael).toBeDefined(true);
+ });
+
+
+ it('Successful paper instantiation', function () {
+ paper = Raphael(0, 0, 400, 400);
+ expect(paper).toEqual(jasmine.any(Raphael));
+ });
+
+ it('Check paper', function () {
+ expect(paper).toBeDefined(true);
+ });
+
+
+ describe('My First Shape', function () {
+
+ it('is a rect', function () {
+ first = paper.rect(0, 0, 40, 40);
+ expect(first).toBe(paper.top);
+ expect(first).toBe(paper.bottom);
+ });
+ });
+
+ describe('My Second Shape', function () {
+ it('is a circle', function () {
+ second = paper.circle(50, 50, 10);
+ expect(second).toBe(paper.top);
+ expect(first).toBe(paper.bottom);
+ });
+ });
+
+});
+
diff --git a/tests/basic/basic.js b/tests/basic/basic.js
new file mode 100644
index 0000000..c30575f
--- /dev/null
+++ b/tests/basic/basic.js
@@ -0,0 +1,19 @@
+describe("RedRaphael", function () {
+ it("should be accessible through window scope", function () {
+ expect(Raphael)
+ .toBeDefined();
+ });
+
+ it("should not dirty the window scope other than exposing itself", function () {
+ expect(arr_diff(initialGlobalKeys,postloadGlobalKeys))
+ .toEqual(["postloadGlobalKeys", "eve", "Raphael"]);
+ });
+
+ describe("Creating paper", function () {
+
+ afterEach(function () {
+
+ });
+ });
+
+})
\ No newline at end of file
diff --git a/tests/basic/specSetup.js b/tests/basic/specSetup.js
new file mode 100644
index 0000000..fe41244
--- /dev/null
+++ b/tests/basic/specSetup.js
@@ -0,0 +1,12 @@
+function arr_diff(a1, a2)
+{
+ var a=[], diff=[];
+ for(var i=0;i
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/index.html b/tests/index.html
new file mode 100644
index 0000000..cb6ee7b
--- /dev/null
+++ b/tests/index.html
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/minified.html b/tests/minified.html
new file mode 100644
index 0000000..3c3fb09
--- /dev/null
+++ b/tests/minified.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/rect.html b/tests/rect.html
new file mode 100644
index 0000000..4c52022
--- /dev/null
+++ b/tests/rect.html
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/runner.html b/tests/runner.html
new file mode 100644
index 0000000..9a9a327
--- /dev/null
+++ b/tests/runner.html
@@ -0,0 +1,71 @@
+
+
+
+ Jasmine Spec Runner
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/runner/index.html b/tests/runner/index.html
new file mode 100644
index 0000000..9a9a327
--- /dev/null
+++ b/tests/runner/index.html
@@ -0,0 +1,71 @@
+
+
+
+ Jasmine Spec Runner
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/runner/jasmine-1.3.1/MIT.LICENSE b/tests/runner/jasmine-1.3.1/MIT.LICENSE
new file mode 100644
index 0000000..7c435ba
--- /dev/null
+++ b/tests/runner/jasmine-1.3.1/MIT.LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008-2011 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/tests/runner/jasmine-1.3.1/jasmine-html.js b/tests/runner/jasmine-1.3.1/jasmine-html.js
new file mode 100644
index 0000000..543d569
--- /dev/null
+++ b/tests/runner/jasmine-1.3.1/jasmine-html.js
@@ -0,0 +1,681 @@
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+ var results = child.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+
+ return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+ var parentDiv = this.dom.summary;
+ var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+ var parent = child[parentSuite];
+
+ if (parent) {
+ if (typeof this.views.suites[parent.id] == 'undefined') {
+ this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+ }
+ parentDiv = this.views.suites[parent.id].element;
+ }
+
+ parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+ for(var fn in jasmine.HtmlReporterHelpers) {
+ ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+ }
+};
+
+jasmine.HtmlReporter = function(_doc) {
+ var self = this;
+ var doc = _doc || window.document;
+
+ var reporterView;
+
+ var dom = {};
+
+ // Jasmine Reporter Public Interface
+ self.logRunningSpecs = false;
+
+ self.reportRunnerStarting = function(runner) {
+ var specs = runner.specs() || [];
+
+ if (specs.length == 0) {
+ return;
+ }
+
+ createReporterDom(runner.env.versionString());
+ doc.body.appendChild(dom.reporter);
+ setExceptionHandling();
+
+ reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+ reporterView.addSpecs(specs, self.specFilter);
+ };
+
+ self.reportRunnerResults = function(runner) {
+ reporterView && reporterView.complete();
+ };
+
+ self.reportSuiteResults = function(suite) {
+ reporterView.suiteComplete(suite);
+ };
+
+ self.reportSpecStarting = function(spec) {
+ if (self.logRunningSpecs) {
+ self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+ };
+
+ self.reportSpecResults = function(spec) {
+ reporterView.specComplete(spec);
+ };
+
+ self.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+ };
+
+ self.specFilter = function(spec) {
+ if (!focusedSpecName()) {
+ return true;
+ }
+
+ return spec.getFullName().indexOf(focusedSpecName()) === 0;
+ };
+
+ return self;
+
+ function focusedSpecName() {
+ var specName;
+
+ (function memoizeFocusedSpec() {
+ if (specName) {
+ return;
+ }
+
+ var paramMap = [];
+ var params = jasmine.HtmlReporter.parameters(doc);
+
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ specName = paramMap.spec;
+ })();
+
+ return specName;
+ }
+
+ function createReporterDom(version) {
+ dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+ dom.banner = self.createDom('div', { className: 'banner' },
+ self.createDom('span', { className: 'title' }, "Jasmine "),
+ self.createDom('span', { className: 'version' }, version)),
+
+ dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+ dom.alert = self.createDom('div', {className: 'alert'},
+ self.createDom('span', { className: 'exceptions' },
+ self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
+ self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
+ dom.results = self.createDom('div', {className: 'results'},
+ dom.summary = self.createDom('div', { className: 'summary' }),
+ dom.details = self.createDom('div', { id: 'details' }))
+ );
+ }
+
+ function noTryCatch() {
+ return window.location.search.match(/catch=false/);
+ }
+
+ function searchWithCatch() {
+ var params = jasmine.HtmlReporter.parameters(window.document);
+ var removed = false;
+ var i = 0;
+
+ while (!removed && i < params.length) {
+ if (params[i].match(/catch=/)) {
+ params.splice(i, 1);
+ removed = true;
+ }
+ i++;
+ }
+ if (jasmine.CATCH_EXCEPTIONS) {
+ params.push("catch=false");
+ }
+
+ return params.join("&");
+ }
+
+ function setExceptionHandling() {
+ var chxCatch = document.getElementById('no_try_catch');
+
+ if (noTryCatch()) {
+ chxCatch.setAttribute('checked', true);
+ jasmine.CATCH_EXCEPTIONS = false;
+ }
+ chxCatch.onclick = function() {
+ window.location.search = searchWithCatch();
+ };
+ }
+};
+jasmine.HtmlReporter.parameters = function(doc) {
+ var paramStr = doc.location.search.substring(1);
+ var params = [];
+
+ if (paramStr.length > 0) {
+ params = paramStr.split('&');
+ }
+ return params;
+}
+jasmine.HtmlReporter.sectionLink = function(sectionName) {
+ var link = '?';
+ var params = [];
+
+ if (sectionName) {
+ params.push('spec=' + encodeURIComponent(sectionName));
+ }
+ if (!jasmine.CATCH_EXCEPTIONS) {
+ params.push("catch=false");
+ }
+ if (params.length > 0) {
+ link += params.join("&");
+ }
+
+ return link;
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
+jasmine.HtmlReporter.ReporterView = function(dom) {
+ this.startedAt = new Date();
+ this.runningSpecCount = 0;
+ this.completeSpecCount = 0;
+ this.passedCount = 0;
+ this.failedCount = 0;
+ this.skippedCount = 0;
+
+ this.createResultsMenu = function() {
+ this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+ this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+ ' | ',
+ this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+ this.summaryMenuItem.onclick = function() {
+ dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+ };
+
+ this.detailsMenuItem.onclick = function() {
+ showDetails();
+ };
+ };
+
+ this.addSpecs = function(specs, specFilter) {
+ this.totalSpecCount = specs.length;
+
+ this.views = {
+ specs: {},
+ suites: {}
+ };
+
+ for (var i = 0; i < specs.length; i++) {
+ var spec = specs[i];
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+ if (specFilter(spec)) {
+ this.runningSpecCount++;
+ }
+ }
+ };
+
+ this.specComplete = function(spec) {
+ this.completeSpecCount++;
+
+ if (isUndefined(this.views.specs[spec.id])) {
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+ }
+
+ var specView = this.views.specs[spec.id];
+
+ switch (specView.status()) {
+ case 'passed':
+ this.passedCount++;
+ break;
+
+ case 'failed':
+ this.failedCount++;
+ break;
+
+ case 'skipped':
+ this.skippedCount++;
+ break;
+ }
+
+ specView.refresh();
+ this.refresh();
+ };
+
+ this.suiteComplete = function(suite) {
+ var suiteView = this.views.suites[suite.id];
+ if (isUndefined(suiteView)) {
+ return;
+ }
+ suiteView.refresh();
+ };
+
+ this.refresh = function() {
+
+ if (isUndefined(this.resultsMenu)) {
+ this.createResultsMenu();
+ }
+
+ // currently running UI
+ if (isUndefined(this.runningAlert)) {
+ this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" });
+ dom.alert.appendChild(this.runningAlert);
+ }
+ this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+ // skipped specs UI
+ if (isUndefined(this.skippedAlert)) {
+ this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" });
+ }
+
+ this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.skippedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.skippedAlert);
+ }
+
+ // passing specs UI
+ if (isUndefined(this.passedAlert)) {
+ this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" });
+ }
+ this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+ // failing specs UI
+ if (isUndefined(this.failedAlert)) {
+ this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+ }
+ this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+ if (this.failedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.failedAlert);
+ dom.alert.appendChild(this.resultsMenu);
+ }
+
+ // summary info
+ this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+ this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+ };
+
+ this.complete = function() {
+ dom.alert.removeChild(this.runningAlert);
+
+ this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.failedCount === 0) {
+ dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+ } else {
+ showDetails();
+ }
+
+ dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+ };
+
+ return this;
+
+ function showDetails() {
+ if (dom.reporter.className.search(/showDetails/) === -1) {
+ dom.reporter.className += " showDetails";
+ }
+ }
+
+ function isUndefined(obj) {
+ return typeof obj === 'undefined';
+ }
+
+ function isDefined(obj) {
+ return !isUndefined(obj);
+ }
+
+ function specPluralizedFor(count) {
+ var str = count + " spec";
+ if (count > 1) {
+ str += "s"
+ }
+ return str;
+ }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+ this.spec = spec;
+ this.dom = dom;
+ this.views = views;
+
+ this.symbol = this.createDom('li', { className: 'pending' });
+ this.dom.symbolSummary.appendChild(this.symbol);
+
+ this.summary = this.createDom('div', { className: 'specSummary' },
+ this.createDom('a', {
+ className: 'description',
+ href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.description)
+ );
+
+ this.detail = this.createDom('div', { className: 'specDetail' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.getFullName())
+ );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+ return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+ this.symbol.className = this.status();
+
+ switch (this.status()) {
+ case 'skipped':
+ break;
+
+ case 'passed':
+ this.appendSummaryToSuiteDiv();
+ break;
+
+ case 'failed':
+ this.appendSummaryToSuiteDiv();
+ this.appendFailureDetail();
+ break;
+ }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+ this.summary.className += ' ' + this.status();
+ this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+ this.detail.className += ' ' + this.status();
+
+ var resultItems = this.spec.results().getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ this.detail.appendChild(messagesDiv);
+ this.dom.details.appendChild(this.detail);
+ }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+ this.suite = suite;
+ this.dom = dom;
+ this.views = views;
+
+ this.element = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description)
+ );
+
+ this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function() {
+ return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
+ this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function(doc) {
+ this.document = doc || document;
+ this.suiteDivs = {};
+ this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) { el.appendChild(child); }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+ var showPassed, showSkipped;
+
+ this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+ this.createDom('div', { className: 'banner' },
+ this.createDom('div', { className: 'logo' },
+ this.createDom('span', { className: 'title' }, "Jasmine"),
+ this.createDom('span', { className: 'version' }, runner.env.versionString())),
+ this.createDom('div', { className: 'options' },
+ "Show ",
+ showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+ showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+ )
+ ),
+
+ this.runnerDiv = this.createDom('div', { className: 'runner running' },
+ this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+ this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+ this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+ );
+
+ this.document.body.appendChild(this.outerDiv);
+
+ var suites = runner.suites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var suiteDiv = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+ this.suiteDivs[suite.id] = suiteDiv;
+ var parentDiv = this.outerDiv;
+ if (suite.parentSuite) {
+ parentDiv = this.suiteDivs[suite.parentSuite.id];
+ }
+ parentDiv.appendChild(suiteDiv);
+ }
+
+ this.startedAt = new Date();
+
+ var self = this;
+ showPassed.onclick = function(evt) {
+ if (showPassed.checked) {
+ self.outerDiv.className += ' show-passed';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+ }
+ };
+
+ showSkipped.onclick = function(evt) {
+ if (showSkipped.checked) {
+ self.outerDiv.className += ' show-skipped';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+ }
+ };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+ var results = runner.results();
+ var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+ this.runnerDiv.setAttribute("class", className);
+ //do it twice for IE
+ this.runnerDiv.setAttribute("className", className);
+ var specs = runner.specs();
+ var specCount = 0;
+ for (var i = 0; i < specs.length; i++) {
+ if (this.specFilter(specs[i])) {
+ specCount++;
+ }
+ }
+ var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+ message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+ this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+ this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+ var results = suite.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.totalCount === 0) { // todo: change this to check results.skipped
+ status = 'skipped';
+ }
+ this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+ if (this.logRunningSpecs) {
+ this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+ var results = spec.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+ var specDiv = this.createDom('div', { className: 'spec ' + status },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(spec.getFullName()),
+ title: spec.getFullName()
+ }, spec.description));
+
+
+ var resultItems = results.getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ specDiv.appendChild(messagesDiv);
+ }
+
+ this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+ return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+ var paramMap = {};
+ var params = this.getLocation().search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ if (!paramMap.spec) {
+ return true;
+ }
+ return spec.getFullName().indexOf(paramMap.spec) === 0;
+};
diff --git a/tests/runner/jasmine-1.3.1/jasmine.css b/tests/runner/jasmine-1.3.1/jasmine.css
new file mode 100644
index 0000000..8c008dc
--- /dev/null
+++ b/tests/runner/jasmine-1.3.1/jasmine.css
@@ -0,0 +1,82 @@
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+#HTMLReporter a { text-decoration: none; }
+#HTMLReporter a:hover { text-decoration: underline; }
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
+#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
+#HTMLReporter .version { color: #aaaaaa; }
+#HTMLReporter .banner { margin-top: 14px; }
+#HTMLReporter .duration { color: #aaaaaa; float: right; }
+#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
+#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
+#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
+#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
+#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
+#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
+#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
+#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
+#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
+#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+#HTMLReporter .runningAlert { background-color: #666666; }
+#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
+#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
+#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
+#HTMLReporter .passingAlert { background-color: #a6b779; }
+#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
+#HTMLReporter .failingAlert { background-color: #cf867e; }
+#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
+#HTMLReporter .results { margin-top: 14px; }
+#HTMLReporter #details { display: none; }
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
+#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter.showDetails .summary { display: none; }
+#HTMLReporter.showDetails #details { display: block; }
+#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter .summary { margin-top: 14px; }
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
+#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
+#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
+#HTMLReporter .description + .suite { margin-top: 0; }
+#HTMLReporter .suite { margin-top: 14px; }
+#HTMLReporter .suite a { color: #333333; }
+#HTMLReporter #details .specDetail { margin-bottom: 28px; }
+#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
+#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
+#HTMLReporter .resultMessage span.result { display: block; }
+#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+
+#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
+#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
+#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
+#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
+#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
+#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
+#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
+#TrivialReporter .runner.running { background-color: yellow; }
+#TrivialReporter .options { text-align: right; font-size: .8em; }
+#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
+#TrivialReporter .suite .suite { margin: 5px; }
+#TrivialReporter .suite.passed { background-color: #dfd; }
+#TrivialReporter .suite.failed { background-color: #fdd; }
+#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
+#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
+#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
+#TrivialReporter .spec.skipped { background-color: #bbb; }
+#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
+#TrivialReporter .passed { background-color: #cfc; display: none; }
+#TrivialReporter .failed { background-color: #fbb; }
+#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
+#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
+#TrivialReporter .resultMessage .mismatch { color: black; }
+#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
+#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
+#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
+#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
diff --git a/tests/runner/jasmine-1.3.1/jasmine.js b/tests/runner/jasmine-1.3.1/jasmine.js
new file mode 100644
index 0000000..6b3459b
--- /dev/null
+++ b/tests/runner/jasmine-1.3.1/jasmine.js
@@ -0,0 +1,2600 @@
+var isCommonJS = typeof window == "undefined" && typeof exports == "object";
+
+/**
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
+ *
+ * @namespace
+ */
+var jasmine = {};
+if (isCommonJS) exports.jasmine = jasmine;
+/**
+ * @private
+ */
+jasmine.unimplementedMethod_ = function() {
+ throw new Error("unimplemented method");
+};
+
+/**
+ * Use jasmine.undefined
instead of undefined
, since undefined
is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Maximum levels of nesting that will be included when an object is pretty-printed
+ */
+jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+/**
+ * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite.
+ * Set to false to let the exception bubble up in the browser.
+ *
+ */
+jasmine.CATCH_EXCEPTIONS = true;
+
+jasmine.getGlobal = function() {
+ function getGlobal() {
+ return this;
+ }
+
+ return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared. Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+ var original = base[name];
+ if (original.apply) {
+ return function() {
+ return original.apply(base, arguments);
+ };
+ } else {
+ // IE support
+ return jasmine.getGlobal()[name];
+ }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+ this.type = 'log';
+ this.values = values;
+ this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+ var text = "";
+ for (var i = 0; i < this.values.length; i++) {
+ if (i > 0) text += " ";
+ if (jasmine.isString_(this.values[i])) {
+ text += this.values[i];
+ } else {
+ text += jasmine.pp(this.values[i]);
+ }
+ }
+ return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+ this.type = 'expect';
+ this.matcherName = params.matcherName;
+ this.passed_ = params.passed;
+ this.expected = params.expected;
+ this.actual = params.actual;
+ this.message = this.passed_ ? 'Passed.' : params.message;
+
+ var trace = (params.trace || new Error(this.message));
+ this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+ return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+ return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+ var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+ return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+ return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+ return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+ return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+ stringPrettyPrinter.format(value);
+ return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+ return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+ return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
+ * attributes on the object.
+ *
+ * @example
+ * // don't care about any other attributes than foo.
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
+ *
+ * @param sample {Object} sample
+ * @returns matchable object for the sample
+ */
+jasmine.objectContaining = function (sample) {
+ return new jasmine.Matchers.ObjectContaining(sample);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+ /**
+ * The name of the spy, if provided.
+ */
+ this.identity = name || 'unknown';
+ /**
+ * Is this Object a spy?
+ */
+ this.isSpy = true;
+ /**
+ * The actual function this spy stubs.
+ */
+ this.plan = function() {
+ };
+ /**
+ * Tracking of the most recent call to the spy.
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy.mostRecentCall.args = [1, 2];
+ */
+ this.mostRecentCall = {};
+
+ /**
+ * Holds arguments for each call to the spy, indexed by call count
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy(7, 8);
+ * mySpy.mostRecentCall.args = [7, 8];
+ * mySpy.argsForCall[0] = [1, 2];
+ * mySpy.argsForCall[1] = [7, 8];
+ */
+ this.argsForCall = [];
+ this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ * bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+ this.plan = this.originalValue;
+ return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+ this.plan = function() {
+ return value;
+ };
+ return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+ this.plan = function() {
+ throw exceptionMsg;
+ };
+ return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ * // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+ this.plan = fakeFunc;
+ return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+ this.wasCalled = false;
+ this.callCount = 0;
+ this.argsForCall = [];
+ this.calls = [];
+ this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+ var spyObj = function() {
+ spyObj.wasCalled = true;
+ spyObj.callCount++;
+ var args = jasmine.util.argsToArray(arguments);
+ spyObj.mostRecentCall.object = this;
+ spyObj.mostRecentCall.args = args;
+ spyObj.argsForCall.push(args);
+ spyObj.calls.push({object: this, args: args});
+ return spyObj.plan.apply(this, arguments);
+ };
+
+ var spy = new jasmine.Spy(name);
+
+ for (var prop in spy) {
+ spyObj[prop] = spy[prop];
+ }
+
+ spyObj.reset();
+
+ return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+ return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+ if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+ }
+ var obj = {};
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+ }
+ return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to jasmine.log
in production code.
+ */
+jasmine.log = function() {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+ return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ * expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+ return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a disabled Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+ return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ * @return {jasmine.Matchers}
+ */
+var expect = function(actual) {
+ return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+ jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+ jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+ jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+ jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+ return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+ return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+ function tryIt(f) {
+ try {
+ return f();
+ } catch(e) {
+ }
+ return null;
+ }
+
+ var xhr = tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ });
+
+ if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+ return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+ /**
+ * @private
+ */
+ var subclass = function() {
+ };
+ subclass.prototype = parentClass.prototype;
+ childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+ var lineNumber;
+ if (e.line) {
+ lineNumber = e.line;
+ }
+ else if (e.lineNumber) {
+ lineNumber = e.lineNumber;
+ }
+
+ var file;
+
+ if (e.sourceURL) {
+ file = e.sourceURL;
+ }
+ else if (e.fileName) {
+ file = e.fileName;
+ }
+
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+ if (file && lineNumber) {
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
+ }
+
+ return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+ if (!str) return str;
+ return str.replace(/&/g, '&')
+ .replace(//g, '>');
+};
+
+jasmine.util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+ return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+ for (var property in source) destination[property] = source[property];
+ return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+ this.currentSpec = null;
+ this.currentSuite = null;
+ this.currentRunner_ = new jasmine.Runner(this);
+
+ this.reporter = new jasmine.MultiReporter();
+
+ this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+ this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ this.lastUpdate = 0;
+ this.specFilter = function() {
+ return true;
+ };
+
+ this.nextSpecId_ = 0;
+ this.nextSuiteId_ = 0;
+ this.equalityTesters_ = [];
+
+ // wrap matchers
+ this.matchersClass = function() {
+ jasmine.Matchers.apply(this, arguments);
+ };
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+ if (jasmine.version_) {
+ return jasmine.version_;
+ } else {
+ throw new Error('Version not set');
+ }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+ if (!jasmine.version_) {
+ return "version unknown";
+ }
+
+ var version = this.version();
+ var versionString = version.major + "." + version.minor + "." + version.build;
+ if (version.release_candidate) {
+ versionString += ".rc" + version.release_candidate;
+ }
+ versionString += " revision " + version.revision;
+ return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+ return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+ return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+ this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+ this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+ var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+ var parentSuite = this.currentSuite;
+ if (parentSuite) {
+ parentSuite.add(suite);
+ } else {
+ this.currentRunner_.add(suite);
+ }
+
+ this.currentSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch(e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ this.it("encountered a declaration exception", function() {
+ throw declarationError;
+ });
+ }
+
+ this.currentSuite = parentSuite;
+
+ return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.beforeEach(beforeEachFunction);
+ } else {
+ this.currentRunner_.beforeEach(beforeEachFunction);
+ }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+ return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.afterEach(afterEachFunction);
+ } else {
+ this.currentRunner_.afterEach(afterEachFunction);
+ }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+ return {
+ execute: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+ var spec = new jasmine.Spec(this, this.currentSuite, description);
+ this.currentSuite.add(spec);
+ this.currentSpec = spec;
+
+ if (func) {
+ spec.runs(func);
+ }
+
+ return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+ return {
+ id: this.nextSpecId(),
+ runs: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.source != b.source)
+ mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
+
+ if (a.ignoreCase != b.ignoreCase)
+ mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.global != b.global)
+ mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.multiline != b.multiline)
+ mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.sticky != b.sticky)
+ mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
+
+ return (mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+ return true;
+ }
+
+ a.__Jasmine_been_here_before__ = b;
+ b.__Jasmine_been_here_before__ = a;
+
+ var hasKey = function(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in b) {
+ if (!hasKey(a, property) && hasKey(b, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ }
+ for (property in a) {
+ if (!hasKey(b, property) && hasKey(a, property)) {
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+ }
+ }
+ for (property in b) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+ }
+ }
+
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+ mismatchValues.push("arrays were not the same length");
+ }
+
+ delete a.__Jasmine_been_here_before__;
+ delete b.__Jasmine_been_here_before__;
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
+ var equalityTester = this.equalityTesters_[i];
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+ if (result !== jasmine.undefined) return result;
+ }
+
+ if (a === b) return true;
+
+ if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+ return (a == jasmine.undefined && b == jasmine.undefined);
+ }
+
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+ return a === b;
+ }
+
+ if (a instanceof Date && b instanceof Date) {
+ return a.getTime() == b.getTime();
+ }
+
+ if (a.jasmineMatches) {
+ return a.jasmineMatches(b);
+ }
+
+ if (b.jasmineMatches) {
+ return b.jasmineMatches(a);
+ }
+
+ if (a instanceof jasmine.Matchers.ObjectContaining) {
+ return a.matches(b);
+ }
+
+ if (b instanceof jasmine.Matchers.ObjectContaining) {
+ return b.matches(a);
+ }
+
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
+ return (a == b);
+ }
+
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+ return (a == b);
+ }
+
+ if (a instanceof RegExp && b instanceof RegExp) {
+ return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ if (typeof a === "object" && typeof b === "object") {
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ //Straight check
+ return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+ if (jasmine.isArray_(haystack)) {
+ for (var i = 0; i < haystack.length; i++) {
+ if (this.equals_(haystack[i], needle)) return true;
+ }
+ return false;
+ }
+ return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+ this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+ this.env = env;
+ this.func = func;
+ this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {
+ if (!jasmine.CATCH_EXCEPTIONS) {
+ this.func.apply(this.spec);
+ }
+ else {
+ try {
+ this.func.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ }
+ }
+ onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+ this.started = false;
+ this.finished = false;
+ this.suites_ = [];
+ this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+ this.started = true;
+ var suites = runner.topLevelSuites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ this.suites_.push(this.summarize_(suite));
+ }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+ var isSuite = suiteOrSpec instanceof jasmine.Suite;
+ var summary = {
+ id: suiteOrSpec.id,
+ name: suiteOrSpec.description,
+ type: isSuite ? 'suite' : 'spec',
+ children: []
+ };
+
+ if (isSuite) {
+ var children = suiteOrSpec.children();
+ for (var i = 0; i < children.length; i++) {
+ summary.children.push(this.summarize_(children[i]));
+ }
+ }
+ return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+ return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+ return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+ this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+ this.results_[spec.id] = {
+ messages: spec.results().getItems(),
+ result: spec.results().failedCount > 0 ? "failed" : "passed"
+ };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+ var results = {};
+ for (var i = 0; i < specIds.length; i++) {
+ var specId = specIds[i];
+ results[specId] = this.summarizeResult_(this.results_[specId]);
+ }
+ return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+ var summaryMessages = [];
+ var messagesLength = result.messages.length;
+ for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+ var resultMessage = result.messages[messageIndex];
+ summaryMessages.push({
+ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+ passed: resultMessage.passed ? resultMessage.passed() : true,
+ type: resultMessage.type,
+ message: resultMessage.message,
+ trace: {
+ stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+ }
+ });
+ }
+
+ return {
+ result : result.result,
+ messages : summaryMessages
+ };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+ this.env = env;
+ this.actual = actual;
+ this.spec = spec;
+ this.isNot = opt_isNot || false;
+ this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+ throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+ for (var methodName in prototype) {
+ if (methodName == 'report') continue;
+ var orig = prototype[methodName];
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+ }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+ return function() {
+ var matcherArgs = jasmine.util.argsToArray(arguments);
+ var result = matcherFunction.apply(this, arguments);
+
+ if (this.isNot) {
+ result = !result;
+ }
+
+ if (this.reportWasCalled_) return result;
+
+ var message;
+ if (!result) {
+ if (this.message) {
+ message = this.message.apply(this, arguments);
+ if (jasmine.isArray_(message)) {
+ message = message[this.isNot ? 1 : 0];
+ }
+ } else {
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+ if (matcherArgs.length > 0) {
+ for (var i = 0; i < matcherArgs.length; i++) {
+ if (i > 0) message += ",";
+ message += " " + jasmine.pp(matcherArgs[i]);
+ }
+ }
+ message += ".";
+ }
+ }
+ var expectationResult = new jasmine.ExpectationResult({
+ matcherName: matcherName,
+ passed: result,
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+ actual: this.actual,
+ message: message
+ });
+ this.spec.addMatcherResult(expectationResult);
+ return jasmine.undefined;
+ };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+ return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+ return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+ return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+ return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+ return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+ return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+ return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+ return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+ return (this.actual === null);
+};
+
+/**
+ * Matcher that compares the actual to NaN.
+ */
+jasmine.Matchers.prototype.toBeNaN = function() {
+ this.message = function() {
+ return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
+ };
+
+ return (this.actual !== this.actual);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+ return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+ return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called.",
+ "Expected spy " + this.actual.identity + " not to have been called."
+ ];
+ };
+
+ return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('wasNotCalled does not take arguments');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to not have been called.",
+ "Expected spy " + this.actual.identity + " to have been called."
+ ];
+ };
+
+ return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+ this.message = function() {
+ var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
+ var positiveMessage = "";
+ if (this.actual.callCount === 0) {
+ positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
+ } else {
+ positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '')
+ }
+ return [positiveMessage, invertedMessage];
+ };
+
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+ ];
+ };
+
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+ return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+ return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+ return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+ return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision, as number of decimal places
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+ if (!(precision === 0)) {
+ precision = precision || 2;
+ }
+ return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} [expected]
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+ var result = false;
+ var exception;
+ if (typeof this.actual != 'function') {
+ throw new Error('Actual is not a function');
+ }
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+ }
+
+ var not = this.isNot ? "not " : "";
+
+ this.message = function() {
+ if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+ } else {
+ return "Expected function to throw an exception.";
+ }
+ };
+
+ return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+ this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
+ if (this.expectedClass == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedClass == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedClass == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedClass == Object) {
+ return typeof other == 'object';
+ }
+
+ return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function() {
+ return '';
+};
+
+jasmine.Matchers.ObjectContaining = function (sample) {
+ this.sample = sample;
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ var env = jasmine.getEnv();
+
+ var hasKey = function(obj, keyName) {
+ return obj != null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in this.sample) {
+ if (!hasKey(other, property) && hasKey(this.sample, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
+ }
+ }
+
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
+ return "";
+};
+// Mock setTimeout, clearTimeout
+// Contributed by Pivotal Computer Systems, www.pivotalsf.com
+
+jasmine.FakeTimer = function() {
+ this.reset();
+
+ var self = this;
+ self.setTimeout = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+ return self.timeoutsMade;
+ };
+
+ self.setInterval = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+ return self.timeoutsMade;
+ };
+
+ self.clearTimeout = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+ self.clearInterval = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function() {
+ this.timeoutsMade = 0;
+ this.scheduledFunctions = {};
+ this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function(millis) {
+ var oldMillis = this.nowMillis;
+ var newMillis = oldMillis + millis;
+ this.runFunctionsWithinRange(oldMillis, newMillis);
+ this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
+ var scheduledFunc;
+ var funcsToRun = [];
+ for (var timeoutKey in this.scheduledFunctions) {
+ scheduledFunc = this.scheduledFunctions[timeoutKey];
+ if (scheduledFunc != jasmine.undefined &&
+ scheduledFunc.runAtMillis >= oldMillis &&
+ scheduledFunc.runAtMillis <= nowMillis) {
+ funcsToRun.push(scheduledFunc);
+ this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ }
+ }
+
+ if (funcsToRun.length > 0) {
+ funcsToRun.sort(function(a, b) {
+ return a.runAtMillis - b.runAtMillis;
+ });
+ for (var i = 0; i < funcsToRun.length; ++i) {
+ try {
+ var funcToRun = funcsToRun[i];
+ this.nowMillis = funcToRun.runAtMillis;
+ funcToRun.funcToCall();
+ if (funcToRun.recurring) {
+ this.scheduleFunction(funcToRun.timeoutKey,
+ funcToRun.funcToCall,
+ funcToRun.millis,
+ true);
+ }
+ } catch(e) {
+ }
+ }
+ this.runFunctionsWithinRange(oldMillis, nowMillis);
+ }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
+ this.scheduledFunctions[timeoutKey] = {
+ runAtMillis: this.nowMillis + millis,
+ funcToCall: funcToCall,
+ recurring: recurring,
+ timeoutKey: timeoutKey,
+ millis: millis
+ };
+};
+
+/**
+ * @namespace
+ */
+jasmine.Clock = {
+ defaultFakeTimer: new jasmine.FakeTimer(),
+
+ reset: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.reset();
+ },
+
+ tick: function(millis) {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.tick(millis);
+ },
+
+ runFunctionsWithinRange: function(oldMillis, nowMillis) {
+ jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+ },
+
+ scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
+ jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+ },
+
+ useMock: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.after(jasmine.Clock.uninstallMock);
+
+ jasmine.Clock.installMock();
+ }
+ },
+
+ installMock: function() {
+ jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+ },
+
+ uninstallMock: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.installed = jasmine.Clock.real;
+ },
+
+ real: {
+ setTimeout: jasmine.getGlobal().setTimeout,
+ clearTimeout: jasmine.getGlobal().clearTimeout,
+ setInterval: jasmine.getGlobal().setInterval,
+ clearInterval: jasmine.getGlobal().clearInterval
+ },
+
+ assertInstalled: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+ }
+ },
+
+ isInstalled: function() {
+ return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+ },
+
+ installed: null
+};
+jasmine.Clock.installed = jasmine.Clock.real;
+
+//else for IE support
+jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setTimeout.apply) {
+ return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().setInterval = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setInterval.apply) {
+ return jasmine.Clock.installed.setInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setInterval(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().clearTimeout = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearTimeout(timeoutKey);
+ }
+};
+
+jasmine.getGlobal().clearInterval = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearInterval(timeoutKey);
+ }
+};
+
+/**
+ * @constructor
+ */
+jasmine.MultiReporter = function() {
+ this.subReporters_ = [];
+};
+jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
+
+jasmine.MultiReporter.prototype.addReporter = function(reporter) {
+ this.subReporters_.push(reporter);
+};
+
+(function() {
+ var functionNames = [
+ "reportRunnerStarting",
+ "reportRunnerResults",
+ "reportSuiteResults",
+ "reportSpecStarting",
+ "reportSpecResults",
+ "log"
+ ];
+ for (var i = 0; i < functionNames.length; i++) {
+ var functionName = functionNames[i];
+ jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
+ return function() {
+ for (var j = 0; j < this.subReporters_.length; j++) {
+ var subReporter = this.subReporters_[j];
+ if (subReporter[functionName]) {
+ subReporter[functionName].apply(subReporter, arguments);
+ }
+ }
+ };
+ })(functionName);
+ }
+})();
+/**
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
+ *
+ * @constructor
+ */
+jasmine.NestedResults = function() {
+ /**
+ * The total count of results
+ */
+ this.totalCount = 0;
+ /**
+ * Number of passed results
+ */
+ this.passedCount = 0;
+ /**
+ * Number of failed results
+ */
+ this.failedCount = 0;
+ /**
+ * Was this suite/spec skipped?
+ */
+ this.skipped = false;
+ /**
+ * @ignore
+ */
+ this.items_ = [];
+};
+
+/**
+ * Roll up the result counts.
+ *
+ * @param result
+ */
+jasmine.NestedResults.prototype.rollupCounts = function(result) {
+ this.totalCount += result.totalCount;
+ this.passedCount += result.passedCount;
+ this.failedCount += result.failedCount;
+};
+
+/**
+ * Adds a log message.
+ * @param values Array of message parts which will be concatenated later.
+ */
+jasmine.NestedResults.prototype.log = function(values) {
+ this.items_.push(new jasmine.MessageResult(values));
+};
+
+/**
+ * Getter for the results: message & results.
+ */
+jasmine.NestedResults.prototype.getItems = function() {
+ return this.items_;
+};
+
+/**
+ * Adds a result, tracking counts (total, passed, & failed)
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
+ */
+jasmine.NestedResults.prototype.addResult = function(result) {
+ if (result.type != 'log') {
+ if (result.items_) {
+ this.rollupCounts(result);
+ } else {
+ this.totalCount++;
+ if (result.passed()) {
+ this.passedCount++;
+ } else {
+ this.failedCount++;
+ }
+ }
+ }
+ this.items_.push(result);
+};
+
+/**
+ * @returns {Boolean} True if everything below passed
+ */
+jasmine.NestedResults.prototype.passed = function() {
+ return this.passedCount === this.totalCount;
+};
+/**
+ * Base class for pretty printing for expectation results.
+ */
+jasmine.PrettyPrinter = function() {
+ this.ppNestLevel_ = 0;
+};
+
+/**
+ * Formats a value in a nice, human-readable string.
+ *
+ * @param value
+ */
+jasmine.PrettyPrinter.prototype.format = function(value) {
+ this.ppNestLevel_++;
+ try {
+ if (value === jasmine.undefined) {
+ this.emitScalar('undefined');
+ } else if (value === null) {
+ this.emitScalar('null');
+ } else if (value === jasmine.getGlobal()) {
+ this.emitScalar('');
+ } else if (value.jasmineToString) {
+ this.emitScalar(value.jasmineToString());
+ } else if (typeof value === 'string') {
+ this.emitString(value);
+ } else if (jasmine.isSpy(value)) {
+ this.emitScalar("spy on " + value.identity);
+ } else if (value instanceof RegExp) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'function') {
+ this.emitScalar('Function');
+ } else if (typeof value.nodeType === 'number') {
+ this.emitScalar('HTMLNode');
+ } else if (value instanceof Date) {
+ this.emitScalar('Date(' + value + ')');
+ } else if (value.__Jasmine_been_here_before__) {
+ this.emitScalar('');
+ } else if (jasmine.isArray_(value) || typeof value == 'object') {
+ value.__Jasmine_been_here_before__ = true;
+ if (jasmine.isArray_(value)) {
+ this.emitArray(value);
+ } else {
+ this.emitObject(value);
+ }
+ delete value.__Jasmine_been_here_before__;
+ } else {
+ this.emitScalar(value.toString());
+ }
+ } finally {
+ this.ppNestLevel_--;
+ }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+ for (var property in obj) {
+ if (!obj.hasOwnProperty(property)) continue;
+ if (property == '__Jasmine_been_here_before__') continue;
+ fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
+ obj.__lookupGetter__(property) !== null) : false);
+ }
+};
+
+jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
+
+jasmine.StringPrettyPrinter = function() {
+ jasmine.PrettyPrinter.call(this);
+
+ this.string = '';
+};
+jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
+
+jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
+ this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
+ this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
+ if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
+ this.append("Array");
+ return;
+ }
+
+ this.append('[ ');
+ for (var i = 0; i < array.length; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(array[i]);
+ }
+ this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
+ if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
+ this.append("Object");
+ return;
+ }
+
+ var self = this;
+ this.append('{ ');
+ var first = true;
+
+ this.iterateObject(obj, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.append(property);
+ self.append(' : ');
+ if (isGetter) {
+ self.append('');
+ } else {
+ self.format(obj[property]);
+ }
+ });
+
+ this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function(value) {
+ this.string += value;
+};
+jasmine.Queue = function(env) {
+ this.env = env;
+
+ // parallel to blocks. each true value in this array means the block will
+ // get executed even if we abort
+ this.ensured = [];
+ this.blocks = [];
+ this.running = false;
+ this.index = 0;
+ this.offset = 0;
+ this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.blocks.unshift(block);
+ this.ensured.unshift(ensure);
+};
+
+jasmine.Queue.prototype.add = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.blocks.push(block);
+ this.ensured.push(ensure);
+};
+
+jasmine.Queue.prototype.insertNext = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.ensured.splice((this.index + this.offset + 1), 0, ensure);
+ this.blocks.splice((this.index + this.offset + 1), 0, block);
+ this.offset++;
+};
+
+jasmine.Queue.prototype.start = function(onComplete) {
+ this.running = true;
+ this.onComplete = onComplete;
+ this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function() {
+ return this.running;
+};
+
+jasmine.Queue.LOOP_DONT_RECURSE = true;
+
+jasmine.Queue.prototype.next_ = function() {
+ var self = this;
+ var goAgain = true;
+
+ while (goAgain) {
+ goAgain = false;
+
+ if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
+ var calledSynchronously = true;
+ var completedSynchronously = false;
+
+ var onComplete = function () {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+ completedSynchronously = true;
+ return;
+ }
+
+ if (self.blocks[self.index].abort) {
+ self.abort = true;
+ }
+
+ self.offset = 0;
+ self.index++;
+
+ var now = new Date().getTime();
+ if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+ self.env.lastUpdate = now;
+ self.env.setTimeout(function() {
+ self.next_();
+ }, 0);
+ } else {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+ goAgain = true;
+ } else {
+ self.next_();
+ }
+ }
+ };
+ self.blocks[self.index].execute(onComplete);
+
+ calledSynchronously = false;
+ if (completedSynchronously) {
+ onComplete();
+ }
+
+ } else {
+ self.running = false;
+ if (self.onComplete) {
+ self.onComplete();
+ }
+ }
+ }
+};
+
+jasmine.Queue.prototype.results = function() {
+ var results = new jasmine.NestedResults();
+ for (var i = 0; i < this.blocks.length; i++) {
+ if (this.blocks[i].results) {
+ results.addResult(this.blocks[i].results());
+ }
+ }
+ return results;
+};
+
+
+/**
+ * Runner
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ */
+jasmine.Runner = function(env) {
+ var self = this;
+ self.env = env;
+ self.queue = new jasmine.Queue(env);
+ self.before_ = [];
+ self.after_ = [];
+ self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function() {
+ var self = this;
+ if (self.env.reporter.reportRunnerStarting) {
+ self.env.reporter.reportRunnerStarting(this);
+ }
+ self.queue.start(function () {
+ self.finishCallback();
+ });
+};
+
+jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.splice(0,0,beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.splice(0,0,afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function() {
+ this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function(suite) {
+ this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function(block) {
+ if (block instanceof jasmine.Suite) {
+ this.addSuite(block);
+ }
+ this.queue.add(block);
+};
+
+jasmine.Runner.prototype.specs = function () {
+ var suites = this.suites();
+ var specs = [];
+ for (var i = 0; i < suites.length; i++) {
+ specs = specs.concat(suites[i].specs());
+ }
+ return specs;
+};
+
+jasmine.Runner.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function() {
+ var topLevelSuites = [];
+ for (var i = 0; i < this.suites_.length; i++) {
+ if (!this.suites_[i].parentSuite) {
+ topLevelSuites.push(this.suites_[i]);
+ }
+ }
+ return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function() {
+ return this.queue.results();
+};
+/**
+ * Internal representation of a Jasmine specification, or test.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {jasmine.Suite} suite
+ * @param {String} description
+ */
+jasmine.Spec = function(env, suite, description) {
+ if (!env) {
+ throw new Error('jasmine.Env() required');
+ }
+ if (!suite) {
+ throw new Error('jasmine.Suite() required');
+ }
+ var spec = this;
+ spec.id = env.nextSpecId ? env.nextSpecId() : null;
+ spec.env = env;
+ spec.suite = suite;
+ spec.description = description;
+ spec.queue = new jasmine.Queue(env);
+
+ spec.afterCallbacks = [];
+ spec.spies_ = [];
+
+ spec.results_ = new jasmine.NestedResults();
+ spec.results_.description = description;
+ spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getFullName = function() {
+ return this.suite.getFullName() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function() {
+ return this.results_;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
+ *
+ * Be careful not to leave calls to jasmine.log
in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+ return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+ var block = new jasmine.Block(this.env, func, this);
+ this.addToQueue(block);
+ return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+ if (this.queue.isRunning()) {
+ this.queue.insertNext(block);
+ } else {
+ this.queue.add(block);
+ }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+ this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+ var positive = new (this.getMatchersClass_())(this.env, actual, this);
+ positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+ return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+ var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+ this.addToQueue(waitsFunc);
+ return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ var latchFunction_ = null;
+ var optional_timeoutMessage_ = null;
+ var optional_timeout_ = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+ switch (typeof arg) {
+ case 'function':
+ latchFunction_ = arg;
+ break;
+ case 'string':
+ optional_timeoutMessage_ = arg;
+ break;
+ case 'number':
+ optional_timeout_ = arg;
+ break;
+ }
+ }
+
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+ this.addToQueue(waitsForFunc);
+ return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+ var expectationResult = new jasmine.ExpectationResult({
+ passed: false,
+ message: e ? jasmine.util.formatException(e) : 'Exception',
+ trace: { stack: e.stack }
+ });
+ this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+ return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+ var parent = this.getMatchersClass_();
+ var newMatchersClass = function() {
+ parent.apply(this, arguments);
+ };
+ jasmine.util.inherit(newMatchersClass, parent);
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+ this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+ this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+ this.removeAllSpies();
+ this.finishCallback();
+ if (onComplete) {
+ onComplete();
+ }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+ if (this.queue.isRunning()) {
+ this.queue.add(new jasmine.Block(this.env, doAfter, this), true);
+ } else {
+ this.afterCallbacks.unshift(doAfter);
+ }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+ var spec = this;
+ if (!spec.env.specFilter(spec)) {
+ spec.results_.skipped = true;
+ spec.finish(onComplete);
+ return;
+ }
+
+ this.env.reporter.reportSpecStarting(this);
+
+ spec.env.currentSpec = spec;
+
+ spec.addBeforesAndAftersToQueue();
+
+ spec.queue.start(function () {
+ spec.finish(onComplete);
+ });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+ var runner = this.env.currentRunner();
+ var i;
+
+ for (var suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+ }
+ }
+ for (i = 0; i < runner.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+ }
+ for (i = 0; i < this.afterCallbacks.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true);
+ }
+ for (suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true);
+ }
+ }
+ for (i = 0; i < runner.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true);
+ }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+ throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+ if (obj == jasmine.undefined) {
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+ throw methodName + '() method does not exist';
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+ throw new Error(methodName + ' has already been spied upon');
+ }
+
+ var spyObj = jasmine.createSpy(methodName);
+
+ this.spies_.push(spyObj);
+ spyObj.baseObj = obj;
+ spyObj.methodName = methodName;
+ spyObj.originalValue = obj[methodName];
+
+ obj[methodName] = spyObj;
+
+ return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+ for (var i = 0; i < this.spies_.length; i++) {
+ var spy = this.spies_[i];
+ spy.baseObj[spy.methodName] = spy.originalValue;
+ }
+ this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+ var self = this;
+ self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+ self.description = description;
+ self.queue = new jasmine.Queue(env);
+ self.parentSuite = parentSuite;
+ self.env = env;
+ self.before_ = [];
+ self.after_ = [];
+ self.children_ = [];
+ self.suites_ = [];
+ self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function() {
+ var fullName = this.description;
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ fullName = parentSuite.description + ' ' + fullName;
+ }
+ return fullName;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+ this.env.reporter.reportSuiteResults(this);
+ this.finished = true;
+ if (typeof(onComplete) == 'function') {
+ onComplete();
+ }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+ return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+ this.children_.push(suiteOrSpec);
+ if (suiteOrSpec instanceof jasmine.Suite) {
+ this.suites_.push(suiteOrSpec);
+ this.env.currentRunner().addSuite(suiteOrSpec);
+ } else {
+ this.specs_.push(suiteOrSpec);
+ }
+ this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+ return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+ return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+ var self = this;
+ this.queue.start(function () {
+ self.finish(onComplete);
+ });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+ this.timeout = timeout;
+ jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+ }
+ this.env.setTimeout(function () {
+ onComplete();
+ }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+ this.timeout = timeout || env.defaultTimeoutInterval;
+ this.latchFunction = latchFunction;
+ this.message = message;
+ this.totalTimeSpentWaitingForLatch = 0;
+ jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+ }
+ var latchFunctionResult;
+ try {
+ latchFunctionResult = this.latchFunction.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ onComplete();
+ return;
+ }
+
+ if (latchFunctionResult) {
+ onComplete();
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+ this.spec.fail({
+ name: 'timeout',
+ message: message
+ });
+
+ this.abort = true;
+ onComplete();
+ } else {
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+ var self = this;
+ this.env.setTimeout(function() {
+ self.execute(onComplete);
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+ }
+};
+
+jasmine.version_= {
+ "major": 1,
+ "minor": 3,
+ "build": 1,
+ "revision": 1354556913
+};