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: + + + 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: + + + 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: + + + 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: + + + 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: + + + 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: + + + 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: + +
+
+ + 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: +
+

Category

+ +
+ 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: +
+
+

Header

+
+
+ 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: + + +
+
+ + +
+
+ + +
+
+ + + 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

+
+
+
+

Animation

+

Animation.delay

+

* + Creates a copy of existing animation object with given delay. +* +

+

Parameters

* +

+

Parameters

  1. delay +number +number of ms to pass between animation start and actual animation
  2. +
+

* +

+

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
+
+

Animation.repeat

+

* + Creates a copy of existing animation object with given repetition. +* +

+

Parameters

* +

+

Parameters

  1. repeat +number +number iterations of animation. For infinite animation pass Infinity
  2. +
+

* +

+

Returns: object new altered Animation object

+

Element.animate

+

* + Creates and starts animation for given element. +* +

+

Parameters

* +

+

Parameters

  1. params +object +final attributes for the element, see also Element.attr
  2. +
  3. ms +number +number of milliseconds for animation to run
  4. +
  5. easing +optional +string +easing type. Accept one of Raphael.easing_formulas or CSS format: cubic‐bezier(XX, XX, XX, XX)
  6. +
  7. callback +optional +function +callback function. Will be called at the end of animation.
  8. +
+

or +

+

Parameters

  1. animation +object +animation object, see Raphael.animation
  2. +
+

* +

+

Returns: object original element

+

Element.animateWith

+

* + Acts similar to Element.animate, but ensure that given animation runs in sync with another given element. +* +

+

Parameters

* +

+

Parameters

  1. el +object +element to sync with
  2. +
  3. anim +object +animation to sync with
  4. +
  5. params +optional +object +final attributes for the element, see also Element.attr
  6. +
  7. ms +optional +number +number of milliseconds for animation to run
  8. +
  9. easing +optional +string +easing type. Accept on of Raphael.easing_formulas or CSS format: cubic‐bezier(XX, XX, XX, XX)
  10. +
  11. callback +optional +function +callback function. Will be called at the end of animation.
  12. +
+

or +

+

Parameters

  1. element +object +element to sync with
  2. +
  3. anim +object +animation to sync with
  4. +
  5. animation +optional +object +animation object, see Raphael.animation
  6. +
+

* +

+

Returns: object original element

+

Element.click

+

* + Adds event handler for click for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.clone

+

* +

+

Returns: object clone of a given element

+

* +

+

Element.data

+

* + Adds or retrieves given value asociated with given key. +* + See also Element.removeData +

+

Parameters

Parameters

  1. key +string +key to store data
  2. +
  3. value +optional +any +value to store
  4. +
+

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"));
+          });
+ }
+
+

Element.dblclick

+

* + Adds event handler for double click for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.drag

+

* + Adds event handlers for drag of the element. +

+

Parameters

Parameters

  1. onmove +function +handler for moving
  2. +
  3. onstart +function +handler for drag start
  4. +
  5. onend +function +handler for drag end
  6. +
  7. mcontext +optional +object +context for moving handler
  8. +
  9. scontext +optional +object +context for drag start handler
  10. +
  11. econtext +optional +object +context for drag end handler
  12. +
+

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: +

+
  1. xnumberx position of the mouse +
  2. ynumbery position of the mouse +
  3. eventobjectDOM event object +
+

Move event and move handler will be called in specified context or in context of the element with following parameters: +

+
  1. dxnumbershift by x from the start point +
  2. dynumbershift by y from the start point +
  3. xnumberx position of the mouse +
  4. ynumbery position of the mouse +
  5. eventobjectDOM event object +
+

End event and end handler will be called in specified context or in context of the element with following parameters: +

+
  1. eventobjectDOM event object +
+

Returns: object Element

+

Element.getBBox

+

* + Return bounding box for a given element +* +

+

Parameters

* +

+

Parameters

  1. isWithoutTransform +boolean +flag, true if you want to have bounding box before transformations. Default is false.
  2. +
+

Returns: object Bounding box object:

+
  1. {
    1. x:numbertop left corner x +
    2. y:numbertop left corner y +
    3. x2:numberbottom right corner x +
    4. y2:numberbottom right corner y +
    5. width:numberwidth +
    6. height:numberheight +
  2. }
+

Element.getData

+

* + Retrieves the element data +

+

Returns: object data

+

Element.glow

+

* + 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

* +

+

Parameters

  1. glow +optional +object +parameters object with all properties optional:
  2. +
+
  1. {
    1. widthnumbersize of the glow, default is 10 +
    2. fillbooleanwill it be filled, default is false +
    3. opacitynumberopacity, default is 0.5 +
    4. offsetxnumberhorizontal offset, default is 0 +
    5. offsetynumbervertical offset, default is 0 +
    6. colorstringglow colour, default is black +
  2. }
+

Returns: object Paper.set of elements that represents glow

+

Element.hover

+

* + Adds event handlers for hover for the element. +

+

Parameters

Parameters

  1. f_in +function +handler for hover in
  2. +
  3. f_out +function +handler for hover out
  4. +
  5. icontext +optional +object +context for hover in handler
  6. +
  7. ocontext +optional +object +context for hover out handler
  8. +
+

Returns: object Element

+

Element.isPointInside

+

* + Determine if given point is inside this element’s shape +* +

+

Parameters

* +

+

Parameters

  1. x +number +x coordinate of the point
  2. +
  3. y +number +y coordinate of the point
  4. +
+

Returns: boolean true if point inside the shape

+

Element.matrix

+
object

* + Keeps Matrix object, which represents element transformation +

+

Element.mousedown

+

* + Adds event handler for mousedown for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.mousemove

+

* + Adds event handler for mousemove for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.mouseout

+

* + Adds event handler for mouseout for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.mouseover

+

* + Adds event handler for mouseover for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.mouseup

+

* + Adds event handler for mouseup for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.onDragOver

+

* + Shortcut for assigning event handler for drag.over.<id> event, where id is id of the element (see Element.id). +

+

Parameters

Parameters

  1. f +function +handler for event, first argument would be the element you are dragging over
  2. +
+

Element.pause

+

* + Stops animation of the element with ability to resume it later on. +* +

+

Parameters

* +

+

Parameters

  1. anim +optional +object +animation object
  2. +
+

* +

+

Returns: object original element

+

Element.removeData

+

* + Removes value associated with an element by given key. + If key is not provided, removes all the data of the element. +

+

Parameters

Parameters

  1. key +optional +string +key
  2. +
+

Returns: object Element

+

Element.resume

+

* + Resumes animation if it was paused with Element.pause method. +* +

+

Parameters

* +

+

Parameters

  1. anim +optional +object +animation object
  2. +
+

* +

+

Returns: object original element

+

Element.setTime

+

* + Sets the status of animation of the element in milliseconds. Similar to Element.status method. +* +

+

Parameters

* +

+

Parameters

  1. anim +object +animation object
  2. +
  3. value +number +number of milliseconds from the beginning of the animation
  4. +
+

* +

+

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>. +

+

Element.status

+

* + Gets or sets the status of animation of the element. +* +

+

Parameters

* +

+

Parameters

  1. anim +optional +object +animation object
  2. +
  3. 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.
  4. +
+

* +

+

Returns: number status

+

or +

+

Returns: array status if anim is not specified. Array of objects in format:

+
  1. {
    1. anim:objectanimation object +
    2. status:numberstatus +
  2. }
+

or +

+

Returns: object original element if value is specified

+

Element.stop

+

* + Stops animation of the element. +* +

+

Parameters

* +

+

Parameters

  1. anim +optional +object +animation object
  2. +
+

* +

+

Returns: object original element

+

Element.touchcancel

+

* + Adds event handler for touchcancel for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.touchend

+

* + Adds event handler for touchend for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.touchmove

+

* + Adds event handler for touchmove for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.touchstart

+

* + Adds event handler for touchstart for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.unclick

+

* + Removes event handler for click for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.undblclick

+

* + Removes event handler for double click for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.undrag

+

* + Removes all drag event handlers from given element. +

+

Element.unhover

+

* + Removes event handlers for hover for the element. +

+

Parameters

Parameters

  1. f_in +function +handler for hover in
  2. +
  3. f_out +function +handler for hover out
  4. +
+

Returns: object Element

+

Element.unmousedown

+

* + Removes event handler for mousedown for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.unmousemove

+

* + Removes event handler for mousemove for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.unmouseout

+

* + Removes event handler for mouseout for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.unmouseover

+

* + Removes event handler for mouseover for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.unmouseup

+

* + Removes event handler for mouseup for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.untouchcancel

+

* + Removes event handler for touchcancel for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.untouchend

+

* + Removes event handler for touchend for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.untouchmove

+

* + Removes event handler for touchmove for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Element.untouchstart

+

* + Removes event handler for touchstart for the element. +

+

Parameters

Parameters

  1. handler +function +handler for the event
  2. +
+

Returns: object Element

+

Matrix.add

+

* + Adds given matrix to existing one. +

+

Parameters

Parameters

  1. a +number + 
  2. +
  3. b +number + 
  4. +
  5. c +number + 
  6. +
  7. d +number + 
  8. +
  9. e +number + 
  10. +
  11. f +number + 
  12. +
+
  1. r
+

Parameters

  1. matrix +object +Matrix
  2. +
+

Matrix.clone

+

* + Returns copy of the matrix +

+

Returns: object Matrix

+

Matrix.invert

+

* + Returns inverted version of the matrix +

+

Returns: object Matrix

+

Matrix.rotate

+

* + Rotates the matrix +

+

Parameters

Parameters

  1. a +number + 
  2. +
  3. x +number + 
  4. +
  5. y +number + 
  6. +
+

Matrix.scale

+

* + Scales the matrix +

+

Parameters

Parameters

  1. x +number + 
  2. +
  3. y +optional +number + 
  4. +
  5. cx +optional +number + 
  6. +
  7. cy +optional +number + 
  8. +
+

Matrix.split

+

* + Splits matrix into primitive transformations +

+

Returns: object in format:

+
  1. dxnumbertranslation by x +
  2. dynumbertranslation by y +
  3. scalexnumberscale by x +
  4. scaleynumberscale by y +
  5. shearnumbershear +
  6. rotatenumberrotation in deg +
  7. isSimplebooleancould it be represented via simple transformations +
+

Matrix.toTransformString

+

* + Return transform string that represents given matrix +

+

Returns: string transform string

+

Matrix.translate

+

* + Translate the matrix +

+

Parameters

Parameters

  1. x +number + 
  2. +
  3. y +number + 
  4. +
+

Matrix.x

+

* + Return x coordinate for given point after transformation described by the matrix. See also Matrix.y +

+

Parameters

Parameters

  1. x +number + 
  2. +
  3. y +number + 
  4. +
+

Returns: number x

+

Matrix.y

+

* + Return y coordinate for given point after transformation described by the matrix. See also Matrix.x +

+

Parameters

Parameters

  1. x +number + 
  2. +
  3. y +number + 
  4. +
+

Returns: number y

+

Paper.add

+

* + Imports elements in JSON array in format {type: type, <attributes>} +* +

+

Parameters

* +

+

Parameters

  1. json +array + 
  2. +
+

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"
+     }
+ ]);
+
+

Paper.bottom

+

* + Points to the bottom element on the paper +

+

Paper.circle

+

* + Draws a circle. +* +

+

Parameters

* +

+

Parameters

  1. x +number +x coordinate of the centre
  2. +
  3. y +number +y coordinate of the centre
  4. +
  5. r +number +radius
  6. +
+

Returns: object Raphaël element object with type “circle”

+

* +

+

Usage

 var c = paper.circle(50, 50, 40);
+
+

Paper.customAttributes

+
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);
+
+

Paper.ellipse

+

* + Draws an ellipse. +* +

+

Parameters

* +

+

Parameters

  1. x +number +x coordinate of the centre
  2. +
  3. y +number +y coordinate of the centre
  4. +
  5. rx +number +horizontal radius
  6. +
  7. ry +number +vertical radius
  8. +
+

Returns: object Raphaël element object with type “ellipse”

+

* +

+

Usage

 var c = paper.ellipse(50, 50, 40, 20);
+
+

Paper.forEach

+

* + Executes given function for each element on the paper +

+

If callback function returns false it will stop loop running. +* +

+

Parameters

* +

+

Parameters

  1. callback +function +function to run
  2. +
  3. thisArg +object +context object for the callback
  4. +
+

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

* +

+

Parameters

  1. x +number +x coordinate from the top left corner of the window
  2. +
  3. y +number +y coordinate from the top left corner of the window
  4. +
+

Usage

 paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
+
+

Paper.getElementsByBBox

+

* + Returns set of elements that have an intersecting bounding box +* +

+

Parameters

* +

+

Parameters

  1. bbox +object +bbox to check with
  2. +
+

Returns: object Set

+

Paper.getElementsByPoint

+

* + Returns set of elements that have common point inside +* +

+

Parameters

* +

+

Parameters

  1. x +number +x coordinate of the point
  2. +
  3. y +number +y coordinate of the point
  4. +
+

Returns: object Set

+

Paper.getFont

+

* + 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

* +

+

Parameters

  1. family +string +font family name or any word from it
  2. +
  3. weight +optional +string +font weight
  4. +
  5. style +optional +string +font style
  6. +
  7. stretch +optional +string +font stretch
  8. +
+

Returns: object the font object

+

Usage

 paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30);
+
+

Paper.group

+

* + Creates a group +* +

+

Parameters

* +

+

Parameters

  1. id +number +id of the group
  2. +
+

Returns: object Raphaël element object with type “group”

+

* +

+

Usage

 var g = paper.group();
+
+

Paper.hide

+

* + Hides a paper +* +

+

Usage

 paper.hide();
+
+

Paper.image

+

* + Embeds an image into the surface. +* +

+

Parameters

* +

+

Parameters

  1. src +string +URI of the source image
  2. +
  3. x +number +x coordinate position
  4. +
  5. y +number +y coordinate position
  6. +
  7. width +number +width of the image
  8. +
  9. height +number +height of the image
  10. +
+

Returns: object Raphaël element object with type “image”

+

* +

+

Usage

 var c = paper.image("apple.png", 10, 10, 80, 80);
+
+

Paper.path

+

* + Creates a path element by given path data string. +

+

Parameters

Parameters

  1. pathString +optional +string +path string in SVG format.
  2. +
+

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.

+ + + + + + + + + + + +
CommandNameParameters
Mmoveto(x y)+
Zclosepath(none)
Llineto(x y)+
Hhorizontal linetox+
Vvertical linetoy+
Ccurveto(x1 y1 x2 y2 x y)+
Ssmooth curveto(x2 y2 x y)+
Qquadratic Bézier curveto(x1 y1 x y)+
Tsmooth quadratic Bézier curveto(x y)+
Aelliptical arc(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
RCatmull-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/ +

    +

    Paper.print

    +

    * + 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

    * +

    +

    Parameters

    1. x +number +x position of the text
    2. +
    3. y +number +y position of the text
    4. +
    5. string +string +text to print
    6. +
    7. font +object +font object, see Paper.getFont
    8. +
    9. size +optional +number +size of the font, default is 16
    10. +
    11. origin +optional +string +could be "baseline" or "middle", default is "middle"
    12. +
    13. letter_spacing +optional +number +number in range -1..1, default is 0
    14. +
    +

    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"});
    +
    +

    Paper.raphael

    +

    * + Points to the Raphael object/function +

    +

    Paper.rect

    +

    +

    Draws a rectangle. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. x +number +x coordinate of the top left corner
    2. +
    3. y +number +y coordinate of the top left corner
    4. +
    5. width +number +width
    6. +
    7. height +number +height
    8. +
    9. r +optional +number +radius for rounded corners, default is 0
    10. +
    +

    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);
    +
    +

    Paper.safari

    +

    * + There is an inconvenient rendering bug in Safari (WebKit): + sometimes the rendering should be forced. + This method should help with dealing with this bug. +

    +

    Paper.set

    +

    * + 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
    +
    +

    Paper.setFinish

    +

    * + See Paper.setStart. This method finishes catching and returns resulting set. +* +

    +

    Returns: object set

    +

    Paper.setSize

    +

    * + If you need to change dimensions of the canvas call this method +* +

    +

    Parameters

    * +

    +

    Parameters

    1. width +number +new width of the canvas
    2. +
    3. height +number +new height of the canvas
    4. +
    +

    Paper.setStart

    +

    * + 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
    +
    +

    Paper.setViewBox

    +

    * + Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by + specifying new boundaries. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. x +number +new x position, default is 0
    2. +
    3. y +number +new y position, default is 0
    4. +
    5. w +number +new width of the canvas
    6. +
    7. h +number +new height of the canvas
    8. +
    9. fit +boolean +true if you want graphics to fit into new boundary box
    10. +
    +

    Paper.show

    +

    * + Shows a hidden paper +* +

    +

    Usage

     paper.show();
    +
    +

    Paper.text

    +

    * + Draws a text string. If you need line breaks, put “\n” in the string. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. x +number +x coordinate position
    2. +
    3. y +number +y coordinate position
    4. +
    5. text +string +The text string to draw
    6. +
    +

    Returns: object Raphaël element object with type “text”

    +

    * +

    +

    Usage

     var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!");
    +
    +

    Paper.top

    +

    * + Points to the topmost element on the paper +

    +

    Raphael

    +

    * + 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

    * +

    +

    Parameters

    1. container +HTMLElement string +DOM element or its ID which is going to be a parent for drawing surface
    2. +
    3. width +number + 
    4. +
    5. height +number + 
    6. +
    7. callback +optional +function +callback function which is going to be executed in the context of newly created paper
    8. +
    +

    or +

    +

    Parameters

    1. x +number + 
    2. +
    3. y +number + 
    4. +
    5. width +number + 
    6. +
    7. height +number + 
    8. +
    9. callback +optional +function +callback function which is going to be executed in the context of newly created paper
    10. +
    +

    or +

    +

    Parameters

    1. 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.
    2. +
    3. callback +optional +function +callback function which is going to be executed in the context of newly created paper
    4. +
    +

    or +

    +

    Parameters

    1. 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.
    2. +
    +

    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"
    + }]);
    +
    +

    Raphael.angle

    +

    * + Returns angle between two or three points +

    +

    Parameters

    Parameters

    1. x1 +number +x coord of first point
    2. +
    3. y1 +number +y coord of first point
    4. +
    5. x2 +number +x coord of second point
    6. +
    7. y2 +number +y coord of second point
    8. +
    9. x3 +optional +number +x coord of third point
    10. +
    11. y3 +optional +number +y coord of third point
    12. +
    +

    Returns: number angle in degrees.

    +

    Raphael.animation

    +

    * + 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

    * +

    +

    Parameters

    1. params +object +final attributes for the element, see also Element.attr
    2. +
    3. ms +number +number of milliseconds for animation to run
    4. +
    5. easing +optional +string +easing type. Accept one of Raphael.easing_formulas or CSS format: cubic&#x2010;bezier(XX,&#160;XX,&#160;XX,&#160;XX)
    6. +
    7. callback +optional +function +callback function. Will be called at the end of animation.
    8. +
    +

    * +

    +

    Returns: object Animation

    +

    Raphael.bezierBBox

    +

    * + Utility method +* + Return bounding box of a given cubic bezier curve +

    +

    Parameters

    Parameters

    1. p1x +number +x of the first point of the curve
    2. +
    3. p1y +number +y of the first point of the curve
    4. +
    5. c1x +number +x of the first anchor of the curve
    6. +
    7. c1y +number +y of the first anchor of the curve
    8. +
    9. c2x +number +x of the second anchor of the curve
    10. +
    11. c2y +number +y of the second anchor of the curve
    12. +
    13. p2x +number +x of the second point of the curve
    14. +
    15. p2y +number +y of the second point of the curve
    16. +
    +

    or +

    +

    Parameters

    1. bez +array +array of six points for bezier curve
    2. +
    +

    Returns: object point information in format:

    +
    1. {
      1. min: {
        1. x:numberx coordinate of the left point +
        2. y:numbery coordinate of the top point +
      2. }
      3. max: {
        1. x:numberx coordinate of the right point +
        2. y:numbery coordinate of the bottom point +
      4. }
    2. }
    +

    Raphael.clone

    +

    * + Returns a recursively cloned version of an object. +

    +

    Raphael.color

    +

    * + Parses the color string and returns object with all values for the given color. +

    +

    Parameters

    Parameters

    1. clr +string +color string in one of the supported formats (see Raphael.getRGB)
    2. +
    +

    Returns: object Combined RGB & HSB object in format:

    +
    1. {
      1. rnumberred, +
      2. gnumbergreen, +
      3. bnumberblue, +
      4. hexstringcolor in HTML/CSS format: #••••••, +
      5. errorbooleantrue if string can’t be parsed, +
      6. hnumberhue, +
      7. snumbersaturation, +
      8. vnumbervalue (brightness), +
      9. lnumberlightness +
    2. }
    +

    Raphael.createUUID

    +

    * + 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);
    +
    +

    Raphael.define

    +

    * + Allows a unified definition of composite shapes and other behaviours using + simple directives. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. definition +object +the shape definition
    2. +
    +

    Raphael.deg

    +

    * + Transform angle to degrees +

    +

    Parameters

    Parameters

    1. deg +number +angle in radians
    2. +
    +

    Returns: number angle in degrees.

    +

    Raphael.easing_formulas

    +

    * + 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.

    +

    Raphael.el

    +
    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

    Parameters

    1. p1x +number +x of the first point of the curve
    2. +
    3. p1y +number +y of the first point of the curve
    4. +
    5. c1x +number +x of the first anchor of the curve
    6. +
    7. c1y +number +y of the first anchor of the curve
    8. +
    9. c2x +number +x of the second anchor of the curve
    10. +
    11. c2y +number +y of the second anchor of the curve
    12. +
    13. p2x +number +x of the second point of the curve
    14. +
    15. p2y +number +y of the second point of the curve
    16. +
    17. t +number +position on the curve (0..1)
    18. +
    +

    Returns: object point information in format:

    +
    1. {
      1. x:numberx coordinate of the point +
      2. y:numbery coordinate of the point +
      3. m: {
        1. x:numberx coordinate of the left anchor +
        2. y:numbery coordinate of the left anchor +
      4. }
      5. n: {
        1. x:numberx coordinate of the right anchor +
        2. y:numbery coordinate of the right anchor +
      6. }
      7. start: {
        1. x:numberx coordinate of the start of the curve +
        2. y:numbery coordinate of the start of the curve +
      8. }
      9. end: {
        1. x:numberx coordinate of the end of the curve +
        2. y:numbery coordinate of the end of the curve +
      10. }
      11. alpha:numberangle of the curve derivative at the point +
    2. }
    +

    Raphael.fn

    +
    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();
    +
    +

    Raphael.format

    +

    * + Simple format function. Replaces construction of type “{<number>}” to the corresponding argument. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. token +string +string to format
    2. +
    3. +string +rest of arguments will be treated as parameters for replacement
    4. +
    +

    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));
    +
    +

    Raphael.fullfill

    +

    * + A little bit more advanced format function than Raphael.format. Replaces construction of type “{<name>}” to the corresponding argument. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. token +string +string to format
    2. +
    3. json +object +object which properties will be used as a replacement
    4. +
    +

    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
    +     }
    + }));
    +
    +

    Raphael.getColor

    +

    * + On each call returns next colour in the spectrum. To reset it back to red call Raphael.getColor.reset +

    +

    Parameters

    Parameters

    1. value +optional +number +brightness, default is 0.75
    2. +
    +

    Returns: string hex representation of the colour.

    +

    Raphael.getPointAtLength

    +

    * + Return coordinates of the point located at the given length on the given path. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. path +string +SVG path string
    2. +
    3. length +number + 
    4. +
    +

    * +

    +

    Returns: object representation of the point:

    +
    1. {
      1. x:numberx coordinate +
      2. y:numbery coordinate +
      3. alpha:numberangle of derivative +
    2. }
    +

    Raphael.getRGB

    +

    * + Parses colour string as RGB object +

    +

    Parameters

    Parameters

    1. colour +string +colour string in one of formats:
    2. +
    +
      +
    • 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:

    +
    1. {
      1. rnumberred, +
      2. gnumbergreen, +
      3. bnumberblue +
      4. hexstringcolor in HTML/CSS format: #••••••, +
      5. errorbooleantrue if string can’t be parsed +
    2. }
    +

    Raphael.getSubpath

    +

    * + Return subpath of a given path from given length to given length. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. path +string +SVG path string
    2. +
    3. from +number +position of the start of the segment
    4. +
    5. to +number +position of the end of the segment
    6. +
    +

    * +

    +

    Returns: string pathstring for the segment

    +

    Raphael.getTotalLength

    +

    * + Returns length of the given path in pixels. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. path +string +SVG path string.
    2. +
    +

    * +

    +

    Returns: number length.

    +

    Raphael.hsb

    +

    * + Converts HSB values to hex representation of the colour. +

    +

    Parameters

    Parameters

    1. h +number +hue
    2. +
    3. s +number +saturation
    4. +
    5. b +number +value or brightness
    6. +
    +

    Returns: string hex representation of the colour.

    +

    Raphael.hsb2rgb

    +

    * + Converts HSB values to RGB object. +

    +

    Parameters

    Parameters

    1. h +number +hue
    2. +
    3. s +number +saturation
    4. +
    5. v +number +value or brightness
    6. +
    +

    Returns: object RGB object in format:

    +
    1. {
      1. rnumberred, +
      2. gnumbergreen, +
      3. bnumberblue, +
      4. hexstringcolor in HTML/CSS format: #•••••• +
    2. }
    +

    Raphael.hsl

    +

    * + Converts HSL values to hex representation of the colour. +

    +

    Parameters

    Parameters

    1. h +number +hue
    2. +
    3. s +number +saturation
    4. +
    5. l +number +luminosity
    6. +
    +

    Returns: string hex representation of the colour.

    +

    Raphael.hsl2rgb

    +

    * + Converts HSL values to RGB object. +

    +

    Parameters

    Parameters

    1. h +number +hue
    2. +
    3. s +number +saturation
    4. +
    5. l +number +luminosity
    6. +
    +

    Returns: object RGB object in format:

    +
    1. {
      1. rnumberred, +
      2. gnumbergreen, +
      3. bnumberblue, +
      4. hexstringcolor in HTML/CSS format: #•••••• +
    2. }
    +

    Raphael.is

    +

    * + Handfull replacement for typeof operator. +

    +

    Parameters

    Parameters

    1. o + +any object or primitive
    2. +
    3. type +string +name of the type, i.e. “string”, “function”, “number”, etc.
    4. +
    +

    Returns: boolean is given value is of given type

    +

    Raphael.isBBoxIntersect

    +

    * + Utility method +* + Returns true if two bounding boxes intersect +

    +

    Parameters

    Parameters

    1. bbox1 +string +first bounding box
    2. +
    3. bbox2 +string +second bounding box
    4. +
    +

    Returns: boolean true if they intersect

    +

    Raphael.isPointInsideBBox

    +

    * + Utility method +* + Returns true if given point is inside bounding boxes. +

    +

    Parameters

    Parameters

    1. bbox +string +bounding box
    2. +
    3. x +string +x coordinate of the point
    4. +
    5. y +string +y coordinate of the point
    6. +
    +

    Returns: boolean true if point inside

    +

    Raphael.isPointInsidePath

    +

    * + Utility method +* + Returns true if given point is inside a given closed path. +

    +

    Parameters

    Parameters

    1. path +string +path string
    2. +
    3. x +number +x of the point
    4. +
    5. y +number +y of the point
    6. +
    +

    Returns: boolean true, if point is inside the path

    +

    Raphael.mapPath

    +

    * + Transform the path string with given matrix. +

    +

    Parameters

    Parameters

    1. path +string +path string
    2. +
    3. matrix +object +see Matrix
    4. +
    +

    Returns: string transformed path string

    +

    Raphael.matrix

    +

    * + Utility method +* + Returns matrix based on given parameters. +

    +

    Parameters

    Parameters

    1. a +number + 
    2. +
    3. b +number + 
    4. +
    5. c +number + 
    6. +
    7. d +number + 
    8. +
    9. e +number + 
    10. +
    11. f +number + 
    12. +
    +

    Returns: object Matrix

    +

    Raphael.ninja

    +

    * + 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

    Parameters

    1. pathString +string array +path string or array of segments (in the last case it will be returned straight away)
    2. +
    +

    Returns: array array of segments.

    +

    Raphael.parseTransformString

    +

    * + Utility method +* + Parses given path string into an array of transformations. +

    +

    Parameters

    Parameters

    1. TString +string array +transform string or array of transformations (in the last case it will be returned straight away)
    2. +
    +

    Returns: array array of transformations.

    +

    Raphael.path2curve

    +

    * + Utility method +* + Converts path to a new path where all segments are cubic bezier curves. +

    +

    Parameters

    Parameters

    1. pathString +string array +path string or array of segments
    2. +
    +

    Returns: array array of segments.

    +

    Raphael.pathBBox

    +

    * + Utility method +* + Return bounding box of a given path +

    +

    Parameters

    Parameters

    1. path +string +path string
    2. +
    +

    Returns: object bounding box

    +
    1. {
      1. x:numberx coordinate of the left top point of the box +
      2. y:numbery coordinate of the left top point of the box +
      3. x2:numberx coordinate of the right bottom point of the box +
      4. y2:numbery coordinate of the right bottom point of the box +
      5. width:numberwidth of the box +
      6. height:numberheight of the box +
      7. cx:numberx coordinate of the center of the box +
      8. cy:numbery coordinate of the center of the box +
    2. }
    +

    Raphael.pathIntersection

    +

    * + Utility method +* + Finds intersections of two paths +

    +

    Parameters

    Parameters

    1. path1 +string +path string
    2. +
    3. path2 +string +path string
    4. +
    +

    Returns: array dots of intersection

    +
    1. [
    2. {
      1. x:numberx coordinate of the point +
      2. y:numbery coordinate of the point +
      3. t1:numbert value for segment of path1 +
      4. t2:numbert value for segment of path2 +
      5. segment1:numberorder number for segment of path1 +
      6. segment2:numberorder number for segment of path2 +
      7. bez1:arrayeight coordinates representing beziér curve for the segment of path1 +
      8. bez2:arrayeight coordinates representing beziér curve for the segment of path2 +
    3. }
    4. ]
    +

    Raphael.pathToRelative

    +

    * + Utility method +* + Converts path to relative form +

    +

    Parameters

    Parameters

    1. pathString +string array +path string or array of segments
    2. +
    +

    Returns: array array of segments.

    +

    Raphael.pick

    +

    * + Returns the first truthy argument. +

    +

    Raphael.rad

    +

    * + Transform angle to radians +

    +

    Parameters

    Parameters

    1. deg +number +angle in degrees
    2. +
    +

    Returns: number angle in radians.

    +

    Raphael.registerFont

    +

    * + 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

    * +

    +

    Parameters

    1. font +object +the font to register
    2. +
    +

    Returns: object the font you passed in

    +

    Usage

     Cufon.registerFont(Raphael.registerFont({…}));
    +
    +

    Raphael.rgb

    +

    * + Converts RGB values to hex representation of the colour. +

    +

    Parameters

    Parameters

    1. r +number +red
    2. +
    3. g +number +green
    4. +
    5. b +number +blue
    6. +
    +

    Returns: string hex representation of the colour.

    +

    Raphael.rgb2hsb

    +

    * + Converts RGB values to HSB object. +

    +

    Parameters

    Parameters

    1. r +number +red
    2. +
    3. g +number +green
    4. +
    5. b +number +blue
    6. +
    +

    Returns: object HSB object in format:

    +
    1. {
      1. hnumberhue +
      2. snumbersaturation +
      3. bnumberbrightness +
    2. }
    +

    Raphael.rgb2hsl

    +

    * + Converts RGB values to HSL object. +

    +

    Parameters

    Parameters

    1. r +number +red
    2. +
    3. g +number +green
    4. +
    5. b +number +blue
    6. +
    +

    Returns: object HSL object in format:

    +
    1. {
      1. hnumberhue +
      2. snumbersaturation +
      3. lnumberluminosity +
    2. }
    +

    Raphael.setWindow

    +

    * + Used when you need to draw in &lt;iframe>. Switched window to the iframe one. +

    +

    Parameters

    Parameters

    1. newwin +window +new window object
    2. +
    +

    Raphael.snapTo

    +

    * + Snaps given value to given grid. +

    +

    Parameters

    Parameters

    1. values +array number +given array of values or step of the grid
    2. +
    3. value +number +value to adjust
    4. +
    5. tolerance +optional +number +tolerance for snapping. Default is 10.
    6. +
    +

    Returns: number adjusted value.

    +

    Raphael.st

    +
    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();
    +
    +

    Raphael.svg

    +
    boolean

    * + true if browser supports SVG. +

    +

    Raphael.toMatrix

    +

    * + Utility method +* + Returns matrix of transformations applied to a given path +

    +

    Parameters

    Parameters

    1. path +string +path string
    2. +
    3. transform +string array +transformation string
    4. +
    +

    Returns: object Matrix

    +

    Raphael.transformPath

    +

    * + Utility method +* + Returns path transformed by a given transformation +

    +

    Parameters

    Parameters

    1. path +string +path string
    2. +
    3. transform +string array +transformation string
    4. +
    +

    Returns: string path

    +

    Raphael.type

    +
    string

    * + Can be “SVG”, “VML” or empty, depending on browser support. +

    +

    Raphael.vml

    +
    boolean

    * + true if browser supports VML. +

    +

    Set.clear

    +

    * + Removeds all elements from the set +

    +

    Set.exclude

    +

    * + Removes given element from the set +* +

    +

    Parameters

    * +

    +

    Parameters

    1. element +object +element to remove
    2. +
    +

    Returns: boolean true if object was found & removed from the set

    +

    Set.forEach

    +

    * + Executes given function for each element in the set. +

    +

    If function returns false it will stop loop running. +* +

    +

    Parameters

    * +

    +

    Parameters

    1. callback +function +function to run
    2. +
    3. thisArg +object +context object for the callback
    4. +
    +

    Returns: object Set object

    +

    Set.pop

    +

    * + Removes last element and returns it. +

    +

    Returns: object element

    +

    Set.push

    +

    * + Adds each argument to the current set. +

    +

    Returns: object original element

    +

    Set.splice

    +

    * + Removes given element from the set +* +

    +

    Parameters

    * +

    +

    Parameters

    1. index +number +position of the deletion
    2. +
    3. count +number +number of element to remove
    4. +
    5. insertion… +optional +object +elements to insert
    6. +
    +

    Returns: object set elements that were deleted

    +

    eve

    +

    Fires event with given name, given scope and other parameters. +

    +

    Arguments

    Parameters

    1. name +string +name of the event, dot (.) or slash (/) separated
    2. +
    3. scope +object +context for the event handlers
    4. +
    5. varargs +... +the rest of arguments will be sent to event handlers
    6. +
    +

    Returns: object array of returned values from the listeners

    +

    eve.f

    +

    * + 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

    Parameters

    1. event +string +event name
    2. +
    3. varargs + +and any other arguments
    4. +
    +

    Returns: function possible event handler function

    +

    eve.listeners

    +

    Internal method which gives you array of all event handlers that will be triggered by the given name. +

    +

    Arguments

    Parameters

    1. name +string +name of the event, dot (.) or slash (/) separated
    2. +
    +

    Returns: array array of event handlers

    +

    eve.nt

    +

    * + Could be used inside event handler to figure out actual name of the event. +* +

    +

    Arguments

    * +

    +

    Parameters

    1. subname +optional +string +subname of the event
    2. +
    +

    * +

    +

    Returns: string name of the event, if subname is not specified

    +

    or +

    +

    Returns: boolean true, if current event’s name contains subname

    +

    eve.nts

    +

    * + Could be used inside event handler to figure out actual name of the event. +* +* +

    +

    Returns: array names of the event

    +

    eve.off

    +

    * + Removes given function from the list of event listeners assigned to given name. + If no arguments specified all the events will be cleared. +* +

    +

    Arguments

    * +

    +

    Parameters

    1. name +string +name of the event, dot (.) or slash (/) separated, with optional wildcards
    2. +
    3. f +function +event handler function
    4. +
    +

    eve.on

    +

    * + 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

    * +

    +

    Parameters

    1. name +string +name of the event, dot (.) or slash (/) separated, with optional wildcards
    2. +
    3. f +function +event handler function
    4. +
    +

    * +

    +

    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”. +

    +

    eve.once

    +

    * + 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

    * +

    +

    Parameters

    1. name +string +name of the event, dot (.) or slash (/) separated, with optional wildcards
    2. +
    3. f +function +event handler function
    4. +
    +

    * +

    +

    Returns: function same return function as eve.on

    +

    eve.stop

    +

    * + Is used inside an event handler to stop the event, preventing any subsequent listeners from firing. +

    +

    eve.version

    +
    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+""};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.

    + # + # + # + # + # + # + # + # + # + # + # + #
    CommandNameParameters
    Mmoveto(x y)+
    Zclosepath(none)
    Llineto(x y)+
    Hhorizontal linetox+
    Vvertical linetoy+
    Ccurveto(x1 y1 x2 y2 x y)+
    Ssmooth curveto(x2 y2 x y)+
    Qquadratic Bézier curveto(x1 y1 x y)+
    Tsmooth quadratic Bézier curveto(x y)+
    Aelliptical arc(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
    RCatmull-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.

    + # + # + # + # + # + # + # + # + # + # + # + #
    CommandNameParameters
    Mmoveto(x y)+
    Zclosepath(none)
    Llineto(x y)+
    Hhorizontal linetox+
    Vvertical linetoy+
    Ccurveto(x1 y1 x2 y2 x y)+
    Ssmooth curveto(x2 y2 x y)+
    Qquadratic Bézier curveto(x1 y1 x y)+
    Tsmooth quadratic Bézier curveto(x y)+
    Aelliptical arc(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
    RCatmull-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 +};