kenan 1 год назад
Родитель
Сommit
18257939a7
100 измененных файлов с 24744 добавлено и 0 удалено
  1. 448 0
      admin/css/admin.css
  2. 105 0
      admin/css/load.css
  3. 140 0
      admin/css/other/console1.css
  4. 18 0
      admin/css/other/console2.css
  5. 6 0
      admin/css/other/department.css
  6. 76 0
      admin/css/other/error.css
  7. 531 0
      admin/css/other/icon.css
  8. 93 0
      admin/css/other/login.css
  9. 80 0
      admin/css/other/person.css
  10. 39 0
      admin/css/other/result.css
  11. 166 0
      admin/data/menu.json
  12. 88 0
      admin/data/message.json
  13. 508 0
      admin/images/403.svg
  14. 314 0
      admin/images/404.svg
  15. 191 0
      admin/images/500.svg
  16. BIN
      admin/images/act.jpg
  17. BIN
      admin/images/avatar.jpg
  18. 33 0
      admin/images/background.svg
  19. BIN
      admin/images/captcha.gif
  20. BIN
      admin/images/logo.png
  21. BIN
      admin/images/show.png
  22. 623 0
      app/app.js
  23. 6191 0
      app/assets/js/crypto/crypto-js.js
  24. 27 0
      app/assets/js/plupload-2.3.7/bower.json
  25. 85 0
      app/assets/js/plupload-2.3.7/examples/custom.html
  26. 34 0
      app/assets/js/plupload-2.3.7/examples/dump.php
  27. 217 0
      app/assets/js/plupload-2.3.7/examples/events.html
  28. 139 0
      app/assets/js/plupload-2.3.7/examples/jquery/all_runtimes.html
  29. 113 0
      app/assets/js/plupload-2.3.7/examples/jquery/jquery_ui_widget.html
  30. 66 0
      app/assets/js/plupload-2.3.7/examples/jquery/queue_widget.html
  31. 131 0
      app/assets/js/plupload-2.3.7/examples/jquery/s3.php
  32. 126 0
      app/assets/js/plupload-2.3.7/examples/upload.php
  33. BIN
      app/assets/js/plupload-2.3.7/js/Moxie.swf
  34. BIN
      app/assets/js/plupload-2.3.7/js/Moxie.xap
  35. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/ar.js
  36. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/az.js
  37. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/bg.js
  38. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/bs.js
  39. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/ca.js
  40. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/cs.js
  41. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/cy.js
  42. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/da.js
  43. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/de.js
  44. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/el.js
  45. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/en.js
  46. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/es.js
  47. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/et.js
  48. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/fa.js
  49. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/fi.js
  50. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/fr.js
  51. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/he.js
  52. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/hr.js
  53. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/hu.js
  54. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/hy.js
  55. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/id.js
  56. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/it.js
  57. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/ja.js
  58. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/ka.js
  59. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/kk.js
  60. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/km.js
  61. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/ko.js
  62. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/ku_IQ.js
  63. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/lt.js
  64. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/lv.js
  65. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/ms.js
  66. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/nl.js
  67. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/pl.js
  68. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/pt.js
  69. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/pt_BR.js
  70. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/ro.js
  71. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/ru.js
  72. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/sk.js
  73. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/sl.js
  74. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/sq.js
  75. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/sr.js
  76. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/sv.js
  77. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/th_TH.js
  78. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/tr.js
  79. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/uk_UA.js
  80. 1 0
      app/assets/js/plupload-2.3.7/js/i18n/vi.js
  81. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/zh_CN.js
  82. 2 0
      app/assets/js/plupload-2.3.7/js/i18n/zh_TW.js
  83. 185 0
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/css/jquery.plupload.queue.css
  84. BIN
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/backgrounds.gif
  85. BIN
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/buttons-disabled.png
  86. BIN
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/buttons.png
  87. BIN
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/delete.gif
  88. BIN
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/done.gif
  89. BIN
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/error.gif
  90. BIN
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/throbber.gif
  91. BIN
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/transp50.png
  92. 433 0
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/jquery.plupload.queue.js
  93. 0 0
      app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/jquery.plupload.queue.min.js
  94. 379 0
      app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/css/jquery.ui.plupload.css
  95. BIN
      app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/img/loading.gif
  96. BIN
      app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/img/plupload.png
  97. 1358 0
      app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/jquery.ui.plupload.js
  98. 0 0
      app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/jquery.ui.plupload.min.js
  99. 11714 0
      app/assets/js/plupload-2.3.7/js/moxie.js
  100. 12 0
      app/assets/js/plupload-2.3.7/js/moxie.min.js

+ 448 - 0
admin/css/admin.css

@@ -0,0 +1,448 @@
+html,
+body,
+.layui-layout {
+	height: 100%;
+}
+
+.pear-admin .layui-header,
+.pear-admin .layui-body,
+.pear-admin .layui-logo,
+.pear-admin .layui-side,
+.pear-admin .layui-header .layui-layout-left {
+	transition: all .3s;
+}
+
+.pear-admin .layui-logo .title {
+	font-size: 20px;
+}
+
+.pear-admin .layui-layout-right .layui-nav-child {
+	border: 1px solid whitesmoke;
+	border-radius: 4px;
+	width: 150px;
+}
+
+.pear-admin .layui-header {
+	left: 230px;
+	width: calc(100% - 230px);
+	background-color: white;
+	border-bottom: 1px solid whitesmoke;
+}
+
+.pear-admin .layui-header .layui-nav-img {
+	width: 30px;
+	height: 30px;
+}
+
+.pear-admin .layui-layout-control {
+	left: 140px;
+	position: absolute;
+}
+
+.pear-admin .layui-layout-control .layui-nav{
+	padding: 0px;
+}
+
+.pear-admin .layui-logo {
+	width: 230px;
+	height: 59px;
+	line-height: 59px;
+	position: relative;
+	background-color: #28333E;
+	border-bottom: 1px solid rgba(0,0,0,.12);
+}
+
+.pear-admin .layui-logo img {
+	width: 34px;
+	height: 34px;
+}
+
+.pear-admin .layui-logo .title {
+	font-size: 21px;
+	font-weight: 550;
+	color: #5FB878;
+	position: relative;
+	top: 5px;
+	margin-left: 5px;
+}
+
+.pear-admin .layui-logo .logo {
+	display: none;
+}
+
+.pear-admin .layui-side {
+	top: 0px;
+	width: 230px;
+	box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
+	z-index: 9999;
+}
+
+.pear-admin .layui-side-scroll::-webkit-scrollbar {
+	width: 0px;
+	height: 0px;
+}
+
+.pear-admin .layui-side-scroll {
+	height: calc(100% - 60px) !important;
+	background-color: #28333E;
+	width: 247px;
+
+}
+
+.pear-admin .layui-header .layui-nav .layui-nav-item>a {
+	color: black;
+	font-size: 15px;
+}
+
+.pear-admin .layui-body {
+	left: 230px;
+	bottom: 0px;
+	padding-bottom: 0px;
+}
+
+.pear-admin .layui-layout-left {
+	left: 0px;
+}
+
+/** 隐 藏 布 局 样 式 */
+.pear-mini .layui-logo .title {
+	display: none;
+}
+
+.pear-mini .layui-logo .logo {
+	display: inline-block;
+}
+
+.pear-mini .layui-side {
+	width: 60px;
+}
+
+.pear-mini .layui-header {
+	left: 60px;
+	width: calc(100% - 60px);
+}
+
+.pear-mini .layui-body {
+	left: 60px;
+}
+
+.pear-mini .layui-logo {
+	width: 60px;
+}
+
+.pear-mini .layui-nav-tree .layui-nav-item span {
+	display: none;
+}
+
+.pear-mini .bottom-nav li {
+	width: 100% !important;
+}
+
+.pear-mini .layui-side-scroll {
+	height: calc(100% - 60px);
+}
+
+.pear-admin .layui-header .layui-nav .layui-nav-bar {
+	top: 0px !important;
+	height: 2px !important;
+	background-color: #5FB878;
+}
+
+.pear-admin .layui-header .layui-nav .layui-this:after {
+	display: none;
+}
+
+.pear-admin .layui-header .layui-nav-more {
+	display: none;
+}
+
+.pear-collasped-pe {
+	display: none;
+	width: 50px;
+	position: absolute;
+	z-index: 400000;
+	bottom: 30px;
+	right: 30px;
+	background-color: #5FB878 !important;
+	height: 50px;
+	line-height: 50px;
+	text-align: center;
+	border-radius: 50px;
+	box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
+}
+
+.pear-collasped-pe a {
+	color: white !important;
+}
+
+@media screen and (min-width: 768px) {
+	.layui-hide-sm {
+		display: inline-block !important;
+	}
+}
+
+@media screen and (min-width: 769px) {
+	.layui-hide-sm {
+		display: none !important;
+	}
+}
+
+/** 新增兼容 */
+@media screen and (max-width:768px) {
+	.collaspe {
+		display: none !important;
+	}
+
+	.pear-collasped-pe {
+		display: inline-block !important;
+	}
+
+	.layui-layout-control {
+		left: 45px !important;
+	}
+
+	.layui-layout-left {
+		padding-left: 10px;
+		padding-right: 10px;
+	}
+
+	.pear-mini .bottom-nav {
+		display: none;
+	}
+
+	.pear-mini .layui-side-scroll {
+		height: calc(100% - 62px);
+	}
+
+	/** 隐 藏 布 局 样 式 */
+	.pear-mini .layui-side {
+		width: 0px;
+	}
+
+	.pear-mini .layui-header {
+		left: 0px;
+		width: 100%;
+	}
+
+	.pear-mini .layui-body {
+		left: 0px;
+	}
+
+	.pear-mini .layui-logo {
+		width: 0px;
+	}
+
+	.pear-admin .layui-body {
+		left: 0px;
+	}
+
+	.pear-admin .layui-header {
+		left: 0px;
+		width: 100%;
+	}
+
+	.pear-admin .pear-cover {
+		width: 100%;
+		height: 100%;
+		background-color: #1E1E1E;
+		display: block;
+		position: absolute;
+		z-index: 1000;
+		opacity: 0;
+		margin-top: -60px;
+	}
+
+	.pear-mini .pear-cover {
+		display: none;
+	}
+}
+
+@-webkit-keyframes am-horizontal-roll_show {
+	0% {
+		opacity: 1;
+		-webkit-transform: translateX(2000px);
+		transform: translateX(2000px)
+	}
+
+	100% {
+		opacity: 1;
+		-webkit-transform: translateX(0);
+		transform: translateX(0)
+	}
+}
+
+@keyframes am-horizontal-roll_show {
+	0% {
+		opacity: 1;
+		-webkit-transform: translateX(800px);
+		-ms-transform: translateX(800px);
+		transform: translateX(800px)
+	}
+
+	100% {
+		opacity: 1;
+		-webkit-transform: translateX(0);
+		-ms-transform: translateX(0);
+		transform: translateX(0)
+	}
+}
+
+.layer-anim-right {
+	-webkit-animation: am-horizontal-roll_show .6s ease-out;
+	animation: am-horizontal-roll_show .6s ease-out;
+
+}
+
+/** 亮色侧边风格 */
+.light-theme .layui-logo {
+	background-color: white !important;
+	color: black !important;
+	border-bottom: 1px whitesmoke solid;
+}
+
+.light-theme .layui-side-scroll {
+	background-color: white !important;
+	color: black !important;
+}
+
+.light-theme .layui-side {
+	box-shadow: 2px 0 8px 0 rgba(29, 35, 41, .05) !important;
+}
+
+/** 主 题 选 择 界 面 样 式 */
+.pearone-color .color-title {
+	padding: 15px 0 0px 20px;
+	margin-bottom: 4px;
+}
+
+.pearone-color .color-content {
+	padding: 15px 10px 0 20px;
+}
+
+.pearone-color .color-content ul {
+	list-style: none;
+	padding: 0px;
+}
+
+.pearone-color .color-content ul li {
+	position: relative;
+	display: inline-block;
+	vertical-align: top;
+	width: 70px;
+	height: 50px;
+	margin: 0 20px 20px 0;
+	padding: 2px 2px 2px 2px;
+	background-color: #f2f2f2;
+	cursor: pointer;
+	font-size: 12px;
+	color: #666;
+}
+
+.pearone-color .color-content li.layui-this:after,
+.pearone-color .color-content li:hover:after {
+	width: 100%;
+	height: 100%;
+	padding: 4px;
+	top: -5px;
+	left: -5px;
+	border: #5FB878 2px solid;
+	opacity: 1;
+	border-radius: 4px;
+}
+
+.pearone-color .color-content li:after {
+	content: '';
+	position: absolute;
+	z-index: 20;
+	top: 50%;
+	left: 50%;
+	width: 1px;
+	height: 0;
+	border: 2px solid #F2F2F2;
+	transition: all .3s;
+	-webkit-transition: all .3s;
+	opacity: 0;
+}
+
+.select-color {
+	margin-bottom: 30px;
+}
+
+.select-color .select-color-title {
+	padding: 15px 0 0px 20px;
+	margin-bottom: 4px;
+}
+
+.select-color .select-color-content {
+	padding: 20px 0 0px 0px;
+	margin-bottom: 4px;
+}
+
+.select-color .select-color-content .select-color-item {
+	background-color: gray;
+	width: 30px;
+	height: 30px;
+	border-radius: 3px;
+	float: left;
+	margin-left: 20px;
+	color: white;
+	font-size: 18px;
+	text-align: center;
+	box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .15);
+	line-height: 30px;
+}
+
+/** 友情链接 */
+.more-setting {
+	margin-top: 45px;
+}
+
+.more-setting form {
+	margin-top: 30px;
+}
+
+.more-setting-title {
+	padding: 15px 0 0px 20px;
+	margin-bottom: 4px;
+}
+
+.more-setting .layui-form-label {
+	width: 60px;
+}
+
+.more-menu-list {
+	width: 100%;
+	margin-top: 80px;
+}
+
+.more-menu-item:first-child {
+	border-top: 1px solid #e8e8e8;
+}
+
+.more-menu-item .layui-icon {
+	font-size: 18px;
+	padding-right: 10px;
+}
+
+.more-menu-item {
+	color: #595959;
+	height: 50px;
+	line-height: 50px;
+	font-size: 16px;
+	padding: 0 25px;
+	border-bottom: 1px solid #e8e8e8;
+	font-style: normal;
+	display: block;
+}
+
+.more-menu-item:hover {
+	background-color: whitesmoke;
+}
+
+.more-menu-item:after {
+	color: #8c8c8c;
+	right: 16px;
+	content: "\e602";
+	position: absolute;
+	font-family: layui-icon !important;
+}

+ 105 - 0
admin/css/load.css

@@ -0,0 +1,105 @@
+.loader-main{
+	position: fixed;
+	width: 100%;
+	height: 100%;
+	background-color: whitesmoke;
+	z-index: 9999999;
+}
+.loader {
+	width: 50px;
+	height: 50px;
+	margin: 30px auto 40px;
+	margin-top: 20%;
+	position: relative;
+	z-index: 999999;
+	background-color: whitesmoke;
+}
+.loader:before {
+	content: "";
+	width: 50px;
+	height: 7px;
+	border-radius: 50%;
+	background: #000;
+	opacity: 0.1;
+	position: absolute;
+	top: 59px;
+	left: 0;
+	animation: shadow .5s linear infinite;
+}
+.loader:after {
+	content: "";
+	width: 50px;
+	height: 50px;
+	border-radius: 3px;
+	 background-color: #5FB878;
+	position: absolute;
+	top: 0;
+	left: 0;
+	animation: loading .5s linear infinite;
+}
+@-webkit-keyframes loading {
+	17% {
+		border-bottom-right-radius: 3px;
+	}
+
+	25% {
+		transform: translateY(9px) rotate(22.5deg);
+	}
+
+	50% {
+		transform: translateY(18px) scale(1, 0.9) rotate(45deg);
+		border-bottom-right-radius: 40px;
+	}
+
+	75% {
+		transform: translateY(9px) rotate(67.5deg);
+	}
+
+	100% {
+		transform: translateY(0) rotate(90deg);
+	}
+}
+@keyframes loading {
+	17% {
+		border-bottom-right-radius: 3px;
+	}
+
+	25% {
+		transform: translateY(9px) rotate(22.5deg);
+	}
+
+	50% {
+		transform: translateY(18px) scale(1, 0.9) rotate(45deg);
+		border-bottom-right-radius: 40px;
+	}
+
+	75% {
+		transform: translateY(9px) rotate(67.5deg);
+	}
+
+	100% {
+		transform: translateY(0) rotate(90deg);
+	}
+}
+@-webkit-keyframes shadow {
+
+	0%,
+	100% {
+		transform: scale(1, 1);
+	}
+
+	50% {
+		transform: scale(1.2, 1);
+	}
+}
+@keyframes shadow {
+
+	0%,
+	100% {
+		transform: scale(1, 1);
+	}
+
+	50% {
+		transform: scale(1.2, 1);
+	}
+}

+ 140 - 0
admin/css/other/console1.css

@@ -0,0 +1,140 @@
+.top-panel {
+	border-radius: 4px;
+	text-align: center;
+}
+
+.top-panel>.layui-card-body {
+	height: 60px;
+}
+
+.top-panel-number {
+	line-height: 60px;
+	font-size: 30px;
+	border-right: 1px solid #eceff9;
+}
+
+.top-panel-tips {
+	padding-left: 8px;
+	padding-top: 16px;
+	line-height: 30px;
+	font-size: 12px;
+}
+
+.pear-container {
+	background-color: whitesmoke;
+	margin: 10px;
+}
+
+.card {
+	width: 100%;
+	height: 160px;
+	background-color: whitesmoke;
+	border-radius: 4px;
+}
+
+.card .header .avatar {
+	width: 28px;
+	height: 28px;
+	margin: 20px;
+	border-radius: 50px;
+}
+
+.card .header {
+	color: dimgray;
+}
+
+.card .body {
+	color: gray;
+}
+
+.card .body {
+	margin-left: 20px;
+	margin-right: 20px;
+}
+
+.card .footer {
+	margin-left: 20px;
+	margin-right: 20px;
+	margin-top: 20px;
+	font-size: 13px;
+	color: gray;
+	position: absolute;
+}
+
+.custom-tab .layui-tab-title {
+	border-bottom-width: 0px;
+	border-bottom-style: none;
+}
+
+.custom-tab .layui-tab-title li {
+	margin-left: 10px;
+}
+.list .list-item {
+	height: 32px;
+	line-height: 32px;
+	color: gray;
+	padding: 5px;
+	padding-left: 15px;
+	border-radius: 4px;
+	margin-top: 5.2px;
+}
+
+.list .list-item:hover {
+	background-color: whitesmoke;
+}
+
+.list .list-item .title {
+	font-size: 13px;
+	width: 100%;
+}
+
+.list .list-item .footer {
+	position: absolute;
+	right: 30px;
+	font-size: 12px;
+}
+
+.top-panel-tips i {
+	font-size: 33px;
+}
+
+.layuiadmin-card-status {
+	padding: 0 10px 10px;
+}
+
+.layuiadmin-card-status dd {
+	padding: 15px 0;
+	border-bottom: 1px solid #EEE;
+	display: -webkit-flex;
+	display: flex;
+}
+
+.layuiadmin-card-status dd div.layui-status-img,
+.layuiadmin-card-team .layui-team-img {
+	width: 32px;
+	height: 32px;
+	border-radius: 50%;
+	margin-right: 15px;
+}
+
+.layuiadmin-card-status dd div.layui-status-img a {
+	width: 100%;
+	height: 100%;
+	display: inline-block;
+	text-align: center;
+	line-height: 32px;
+}
+
+.layuiadmin-card-status dd div span {
+	color: #BBB;
+}
+
+.layuiadmin-card-status dd div a {
+	color: #01AAED;
+}
+
+.top-panel-tips svg {
+	margin-top: -12px;
+	width: 50px;
+	height: 50px;
+}

+ 18 - 0
admin/css/other/console2.css

@@ -0,0 +1,18 @@
+			.pear-container {background-color: whitesmoke;margin: 10px;}
+			.pear-card {width: 100%;height: 66px;background-color: #F8F8F8;display: inline-block;border-radius: 5px;text-align: center;margin-bottom: 3px;}
+            .pear-card:hover,.pear-card2:hover{box-shadow: 2px 0 8px 0 lightgray!important;}.pear-card2 {width: 100%;height: 90px;background-color: #F8F8F8;display: inline-block;border-radius: 5px;text-align: center;margin-bottom: 3px;}
+			.pear-card2 i {font-size: 30px;height: 90px;line-height: 90px;}
+			.pear-card i {font-size: 30px;height: 66px;line-height: 66px;}
+			.layui-col-md3 {text-align: center;}
+			.pear-card-title {margin-top: 3px;}
+			.person img {width: 90px;height: 90px;border-radius: 4px;margin-top: 8px;margin-left: 8px;}
+			.pear-card2 .count {color: #51A351;font-size: 30px;margin-top: 12px;}
+			.pear-card2 .title {color: gray;font-size: 14px;margin-top: 14px;}
+			.pear-card-status {padding: 0 10px 10px;}
+			.pear-card-status li {position: relative;padding: 10px 0;border-bottom: 1px solid #EEE;}
+			.pear-card-status li h3 {padding-bottom: 5px;font-weight: 700;}
+			.pear-card-status li p {padding-bottom: 10px;padding-top: 3px ;}
+			.pear-card-status li>span {color: #999;}
+			.pear-reply {position: absolute;right: 20px;}
+			.person .title{font-size: 17px;font-weight: 600;margin-left: 18px;margin-top: 16px;position: absolute;display: inline-block;}
+			.person .desc{font-size: 16px;font-weight: 600;margin-left: 115px;margin-top: -30px;position: absolute;display: inline-block;}

+ 6 - 0
admin/css/other/department.css

@@ -0,0 +1,6 @@
+.organizationTree {
+	width: 100% !important;
+	height: -webkit-calc(100vh - 130px);
+	height: -moz-calc(100vh - 130px);
+	height: calc(100vh - 130px);
+}

+ 76 - 0
admin/css/other/error.css

@@ -0,0 +1,76 @@
+* {
+	padding: 0;
+	margin: 0;
+	font-size: 0.38rem;
+}
+
+ul {
+	list-style: none;
+}
+
+a {
+	text-decoration: none;
+	-webkit-tap-highlight-color: transparent
+}
+
+.clearfix:after {
+	content: '';
+	width: 0;
+	height: 0;
+	display: block;
+	clear: both;
+}
+
+html {
+	height: 100%;
+	width: 100%;
+}
+
+body {
+	font-size: 0.28rem;
+	height: 100%;
+	width: 100%;
+	display: flex;
+	flex-direction: column;
+	position: relative;
+	background-color: white !important;
+}
+
+.content {
+	position: absolute;
+	top: 50%;
+	transform: translateY(-50%);
+	width: 100%;
+	text-align: center;
+}
+
+.content>img {
+	height: 300px;
+	max-width: 370px;
+	margin-right: 180px;
+}
+
+.content>* {
+	display: inline-block;
+}
+
+.content-r {
+	vertical-align: top;
+}
+
+.content-r>h1 {
+	font-size: 72px;
+	color: #434e59;
+	margin-bottom: 24px;
+	font-weight: 600;
+}
+
+.content-r>p {
+	font-size: 20px;
+	color: rgba(0, 0, 0, .45);
+	margin-bottom: 16px;
+}
+
+button {
+	margin-top: 20px;
+}

+ 531 - 0
admin/css/other/icon.css

@@ -0,0 +1,531 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -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-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}

+ 93 - 0
admin/css/other/login.css

@@ -0,0 +1,93 @@
+.layui-form {
+	width: 320px !important;
+	margin: auto !important;
+	margin-top: 160px !important;
+}
+
+.layui-form button {
+	width: 100% !important;
+	height: 44px !important;
+	line-height: 44px !important;
+	font-size: 16px !important;
+	background-color: #5FB878 !important;
+	font-weight: 550 !important;
+}
+
+.layui-form-checked[lay-skin=primary] i {
+	border-color: #5FB878 !important;
+	background-color: #5FB878 !important;
+	color: #fff !important;
+}
+
+.layui-tab-content {
+	margin-top: 15px !important;
+	padding-left: 0px !important;
+	padding-right: 0px !important;
+}
+
+.layui-form-item {
+	margin-top: 20px !important;
+}
+
+.layui-input {
+	height: 44px !important;
+	line-height: 44px !important;
+	padding-left: 15px !important;
+	border-radius: 3px !important;
+}
+
+.layui-input:focus {
+	box-shadow: 0px 0px 2px 1px #5FB878 !important;
+}
+
+.layui-form-danger:focus{
+	box-shadow: 0px 0px 2px 1px #f56c6c !important;
+}
+
+.logo {
+	width: 60px !important;
+	margin-top: 10px !important;
+	margin-bottom: 10px !important;
+	margin-left: 20px !important;
+}
+
+.title {
+	font-size: 30px !important;
+	font-weight: 550 !important;
+	margin-left: 20px !important;
+	color: #5FB878 !important;
+	display: inline-block !important;
+	height: 60px !important;
+	line-height: 60px !important;
+	margin-top: 10px !important;
+	position: absolute !important;
+}
+
+.desc {
+	width: 100% !important;
+	text-align: center !important;
+	color: gray !important;
+	height: 60px !important;
+	line-height: 60px !important;
+}
+
+body {
+	background-repeat:no-repeat;
+	background-color: whitesmoke;
+	background-size: 100%;
+	height: 100%;
+ }
+
+.code {
+	float: left;
+	margin-right: 13px;
+	margin: 0px !important;
+	border: #e6e6e6 1px solid;
+	display: inline-block!important;
+}
+
+.codeImage {
+	float: right;
+	height: 42px;
+	border: #e6e6e6 1px solid;
+}

+ 80 - 0
admin/css/other/person.css

@@ -0,0 +1,80 @@
+.pear-container {
+	background-color: whitesmoke;
+	margin: 10px;
+}
+.layui-body {
+	padding: 25px;
+}
+.text-center {
+	text-align: center;
+}
+.user-info-head {
+	width: 110px;
+	height: 110px;
+	line-height: 110px;
+	position: relative;
+	display: inline-block;
+	border-radius: 50%;
+	overflow: hidden;
+	cursor: pointer;
+	margin: 0 auto;
+}
+.layui-line-dash {
+	border-bottom: 1px dashed #ccc;
+	margin: 15px 0;
+}
+.comment {
+	position: absolute;
+	bottom: 3px;
+	right: 10px;
+	font-size: 12px;
+	color: dimgray;
+}
+.content {
+	padding-left: 13px;
+	font-size: 13px;
+	color: dimgray;
+}
+.title {
+	padding-left: 13.5px;
+}
+.layui-tab-title {
+	border-bottom: none;
+}
+.fl-item {
+	height: 30px;
+	font-size: 13.5;
+}
+.dot {
+	width: 10px;
+	height: 10px;
+	border-radius: 50px;
+	background-color: gray;
+	display: inline-block;
+	margin-right: 10px;
+}
+
+.list .list-item {
+	height: 32px;
+	line-height: 32px;
+	color: gray;
+	padding: 5px;
+	padding-left: 15px;
+	border-radius: 4px;
+	margin-top: 5.2px;
+}
+
+.list .list-item:hover {
+	background-color: whitesmoke;
+}
+
+.list .list-item .title {
+	font-size: 13px;
+	width: 100%;
+}
+
+.list .list-item .footer {
+	position: absolute;
+	right: 30px;
+	font-size: 12px;
+}

+ 39 - 0
admin/css/other/result.css

@@ -0,0 +1,39 @@
+.result {
+	text-align: center;
+
+}
+.result .success svg {
+	color: #32C682;
+	text-align: center;
+	margin-top: 40px;
+
+}
+.result .error svg {
+	color: #f56c6c;
+	text-align: center;
+	margin-top: 40px;
+
+}
+.result .title {
+	margin-top: 25px;
+
+}
+.result .desc {
+	margin-top: 25px;
+	width: 60%;
+	margin-left: 20%;
+	color: rgba(0, 0, 0, .45);
+}
+.result .content {
+	margin-top: 20px;
+	width: 80%;
+	border-radius: 10px;
+	background-color: whitesmoke;
+	height: 200px;
+	margin-left: 10%;
+}
+.result .action {
+	padding-top: 10px;
+	border-top: 1px whitesmoke solid;
+	margin-top: 25px;
+}

+ 166 - 0
admin/data/menu.json

@@ -0,0 +1,166 @@
+[
+  {
+    "id": "agent-dashboard",
+    "title": "数据统计",
+    "type": 0,
+    "icon": "icon pear-icon pear-icon-data-view",
+    "href": "",
+    "children": [
+      {
+        "id": 101,
+        "title": "总数据",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/home/dashboard.html"
+      }
+    ]
+  },
+  {
+    "id": "agent-setting",
+    "title": "系统配置",
+    "type": 0,
+    "icon": "icon pear-icon pear-icon-setting",
+    "href": "",
+    "children": [
+      {
+        "id": 201,
+        "title": "通用配置",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/setting/setting.html"
+      },
+      {
+        "id": 202,
+        "title": "推广域名",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/web/web_list.html"
+      },
+      {
+        "id": 203,
+        "title": "公告管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/announce/announce_list.html"
+      },
+      {
+        "id": 204,
+        "title": "应用管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/app/app_list.html"
+      },
+      {
+        "id": 205,
+        "title": "客服管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/serving/serving.html"
+      }
+    ]
+  },
+  {
+    "id": "agent-setting",
+    "title": "财务管理",
+    "type": 0,
+    "icon": "layui-icon layui-icon-face-surprised",
+    "href": "",
+    "children": [
+      {
+        "id": 301,
+        "title": "充值明细",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/recharge/recharge_list.html"
+      },
+      {
+        "id": 302,
+        "title": "提现管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/withdraw/withdraw_list.html"
+      },
+      {
+        "id": 303,
+        "title": "扣量管理",
+        "icon": "",
+        "type": 0,
+        "children": [
+          {
+            "id": 3013,
+            "title": "CPS",
+            "icon": "",
+            "type": 1,
+            "openType": "_iframe",
+            "href": "view/deduction/deduction_cps_list.html"
+          },
+          {
+            "id": 3011,
+            "title": "CPA",
+            "icon": "",
+            "type": 1,
+            "openType": "_iframe",
+            "href": "view/deduction/deduction_cpa_list.html"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "id": "agent-users-group",
+    "title": "用户及组",
+    "type": 0,
+    "icon": "icon pear-icon pear-icon-data-view",
+    "href": "",
+    "children": [
+      {
+        "id": 5,
+        "title": "全局代理管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/agent/agent_list.html"
+      },
+      {
+        "id": 401,
+        "title": "cps代理管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/agent/agent_cps_list.html"
+      },
+      {
+        "id": 404,
+        "title": "cpa代理管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/agent/agent_cpa_list.html"
+      },
+      {
+        "id": 402,
+        "title": "渠道管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/channel/channel_list.html"
+      },
+      {
+        "id": 403,
+        "title": "管理员管理",
+        "icon": "",
+        "type": 1,
+        "openType": "_iframe",
+        "href": "view/users/users_list.html"
+      }
+    ]
+  }
+]

+ 88 - 0
admin/data/message.json

@@ -0,0 +1,88 @@
+[{
+		"id": 1,
+		"title": "私信",
+		"children": [{
+			"id": 11,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条私人消息",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		}, {
+			"id": 12,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条私人消息",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		}]
+	},
+	{
+		"id": 2,
+		"title": "消息",
+		"children": [{
+			"id": 11,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条紧急任务",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		}, {
+			"id": 12,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条紧急任务",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		},
+		{
+			"id": 11,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条紧急任务",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		}, {
+			"id": 12,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条紧急任务",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		},
+		{
+			"id": 11,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条紧急任务",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		}, {
+			"id": 12,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条紧急任务",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		}]
+	},
+	{
+		"id": 3,
+		"title": "通知",
+		"children": [{
+			"id": 11,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条警告通知",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		}, {
+			"id": 12,
+			"avatar":"admin/images/avatar.jpg",
+			"title": "收到一条警告通知",
+			"context": "这是消息内容。",
+			"form": "就眠仪式",
+			"time": "2019-02-15"
+		}]
+	}
+]

+ 508 - 0
admin/images/403.svg

@@ -0,0 +1,508 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="227px" height="269px" viewBox="0 0 227 269" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 9</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+        <path d="M0,131.5 C1.52216317e-15,101.788282 2.0023434,70.3064817 6.0070302,37.054599 L6.00703147,37.0545992 C8.23177711,18.5819983 23.2321456,4.27478563 41.7892683,2.9258328 C68.6224469,0.975277594 91.0407969,-6.24317082e-09 109.044318,0 C127.133265,6.27279111e-09 149.842798,0.984554771 177.17292,2.9536643 L177.17292,2.95366535 C195.745345,4.29179116 210.761581,18.6099912 212.981582,37.0977487 C216.993859,70.5112465 218.999998,102.082949 219,131.812857 C219.000002,161.472158 217.003381,192.843579 213.010137,225.927119 L213.010136,225.927119 C210.780269,244.401296 195.772997,258.705423 177.213148,260.046888 C149.974602,262.015629 127.477504,263 109.721856,263 C91.927568,263 69.2911098,262.01134 41.8124813,260.034021 L41.8124814,260.03402 C23.2430488,258.697792 8.22697111,244.385384 6.00173205,225.9014 C2.00057735,192.665746 1.52149174e-15,161.198612 0,131.5 Z" id="path-1"></path>
+        <filter x="-4.5%" y="-1.4%" width="106.2%" height="104.4%" filterUnits="objectBoundingBox" id="filter-2">
+            <feMorphology radius="0.81" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
+            <feOffset dx="-6" dy="4" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <path d="M39.654321,130.992298 C39.654321,110.09311 40.5351746,89.1940983 42.2968819,68.2952631 L42.2968835,68.2952632 C43.2666685,56.7908671 52.197293,47.5570778 63.6629191,46.2039222 C78.8424188,44.4124609 94.0195118,43.5167302 109.194198,43.5167302 C124.360772,43.5167302 139.527341,44.4115034 154.693904,46.2010498 L154.693904,46.2010495 C166.164025,47.5544421 175.09671,56.7944422 176.061501,68.3037662 C177.833381,89.4411461 178.719321,110.482698 178.719321,131.428422 C178.719321,152.307984 177.838969,173.187319 176.078265,194.066429 L176.078265,194.066429 C175.10807,205.571375 166.17633,214.805149 154.709997,216.157282 C139.486491,217.95247 124.287302,218.850064 109.112431,218.850064 C93.9666716,218.850064 78.8209665,217.95591 63.6753158,216.167604 L63.6753156,216.167605 C52.2067135,214.813462 43.275345,205.574785 42.309801,194.06695 C40.539481,172.967394 39.654321,151.94251 39.654321,130.992298 Z" id="path-3"></path>
+        <filter x="-6.0%" y="-2.3%" width="108.6%" height="105.9%" filterUnits="objectBoundingBox" id="filter-4">
+            <feMorphology radius="0.81" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
+            <feOffset dx="-5" dy="3" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <path d="M161.510068,89.8583333 L176.8425,89.8583333 L176.8425,107.391667 L161.510068,107.391667 L161.510068,107.391667 C157.8829,107.391667 154.9425,104.451267 154.9425,100.824099 L154.9425,96.4259009 L154.9425,96.4259009 C154.9425,92.7987335 157.8829,89.8583333 161.510068,89.8583333 Z" id="path-5"></path>
+        <filter x="-13.7%" y="-5.7%" width="118.3%" height="117.1%" filterUnits="objectBoundingBox" id="filter-6">
+            <feOffset dx="-2" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <path d="M183.957568,89.8583333 L199.29,89.8583333 L199.29,107.391667 L183.957568,107.391667 L183.957568,107.391667 C180.3304,107.391667 177.39,104.451267 177.39,100.824099 L177.39,96.4259009 L177.39,96.4259009 C177.39,92.7987335 180.3304,89.8583333 183.957568,89.8583333 Z" id="path-7"></path>
+        <filter x="-2.3%" y="-2.9%" width="109.1%" height="111.4%" filterUnits="objectBoundingBox" id="filter-8">
+            <feOffset dx="1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <filter x="-55.5%" y="-9.3%" width="177.5%" height="148.0%" filterUnits="objectBoundingBox" id="filter-9">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-55.5%" y="-9.3%" width="177.5%" height="148.0%" filterUnits="objectBoundingBox" id="filter-10">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <path d="M8.86493515,17.2480344 C8.4007802,16.9327578 8.09567896,16.3993146 8.09567896,15.7943295 C8.09567896,14.82567 8.87784133,14.0404164 9.84268751,14.0404164 C10.8075337,14.0404164 11.5896961,14.82567 11.5896961,15.7943295 C11.5896961,16.3993146 11.2845948,16.9327578 10.8204399,17.2480344 L11.7961308,19.984547 C11.9101195,20.3042502 11.743355,20.6558271 11.4236517,20.7698158 C11.3574028,20.7934365 11.2875908,20.8055099 11.2172568,20.8055099 L8.46811816,20.8055099 L8.46811816,20.8055099 C8.1287016,20.8055099 7.85355011,20.5303584 7.85355011,20.1909418 C7.85355011,20.1206079 7.86562345,20.0507959 7.8892442,19.984547 L8.86493515,17.2480344 Z" id="path-11"></path>
+        <filter x="-12.0%" y="-7.4%" width="124.1%" height="114.8%" filterUnits="objectBoundingBox" id="filter-12">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetInner1"></feOffset>
+            <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 1 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-13">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-14">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-15">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-16">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-17">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-18">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-19">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-20">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-21">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-22">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-44.4%" y="-20.0%" width="166.7%" height="160.0%" filterUnits="objectBoundingBox" id="filter-23">
+            <feOffset dx="-2" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-44.4%" y="-20.0%" width="166.7%" height="160.0%" filterUnits="objectBoundingBox" id="filter-24">
+            <feOffset dx="-2" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-44.4%" y="-20.0%" width="166.7%" height="160.0%" filterUnits="objectBoundingBox" id="filter-25">
+            <feOffset dx="-2" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-44.4%" y="-20.0%" width="166.7%" height="160.0%" filterUnits="objectBoundingBox" id="filter-26">
+            <feOffset dx="-2" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-44.4%" y="-20.0%" width="166.7%" height="160.0%" filterUnits="objectBoundingBox" id="filter-27">
+            <feOffset dx="-2" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-44.4%" y="-20.0%" width="166.7%" height="160.0%" filterUnits="objectBoundingBox" id="filter-28">
+            <feOffset dx="-2" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-44.4%" y="-20.0%" width="166.7%" height="160.0%" filterUnits="objectBoundingBox" id="filter-29">
+            <feOffset dx="-2" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-30" x="79.0833333" y="68.7939815" width="60.8333333" height="24.3518519"></rect>
+        <filter x="-2.5%" y="-2.1%" width="103.3%" height="108.2%" filterUnits="objectBoundingBox" id="filter-31">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <rect id="path-32" x="119.233333" y="71.2346165" width="18.2504951" height="19.5072939"></rect>
+        <path d="M6.69173423,0.214583333 L15.4541667,0.214583333 L15.4541667,30.8979167 L6.69173423,30.8979167 L6.69173423,30.8979167 C3.06456682,30.8979167 0.124166667,27.9575165 0.124166667,24.3303491 L0.124166667,6.7821509 L0.124166667,6.7821509 C0.124166667,3.15498349 3.06456682,0.214583333 6.69173423,0.214583333 Z" id="path-34"></path>
+        <filter x="-29.4%" y="-4.9%" width="139.1%" height="116.3%" filterUnits="objectBoundingBox" id="filter-35">
+            <feOffset dx="-3" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.866666667   0 0 0 0 0.890196078   0 0 0 0 0.909803922  0 0 0 1 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-36">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-37">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <path d="M42.8291667,11.875589 L42.8291667,19.236911 C42.8291667,19.9264853 42.3373793,20.5354959 41.738915,20.595957 L17.6441667,22.6791667 L17.6441667,8.43333333 L41.738915,10.516543 C42.3410444,10.5773757 42.8291667,11.185286 42.8291667,11.875589 Z" id="path-38"></path>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-39">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-40">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-41" x="12.23" y="6.78958333" width="7.1175" height="17.5333333" rx="1.09459459"></rect>
+        <filter x="-42.1%" y="-5.7%" width="156.2%" height="117.1%" filterUnits="objectBoundingBox" id="filter-42">
+            <feOffset dx="-2" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <path d="M6.69173423,0.214583333 L15.4541667,0.214583333 L15.4541667,30.8979167 L6.69173423,30.8979167 L6.69173423,30.8979167 C3.06456682,30.8979167 0.124166667,27.9575165 0.124166667,24.3303491 L0.124166667,6.7821509 L0.124166667,6.7821509 C0.124166667,3.15498349 3.06456682,0.214583333 6.69173423,0.214583333 Z" id="path-43"></path>
+        <filter x="-29.4%" y="-4.9%" width="139.1%" height="116.3%" filterUnits="objectBoundingBox" id="filter-44">
+            <feOffset dx="-3" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.866666667   0 0 0 0 0.890196078   0 0 0 0 0.909803922  0 0 0 1 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-45">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-46">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <path d="M42.8291667,11.875589 L42.8291667,19.236911 C42.8291667,19.9264853 42.3373793,20.5354959 41.738915,20.595957 L17.6441667,22.6791667 L17.6441667,8.43333333 L41.738915,10.516543 C42.3410444,10.5773757 42.8291667,11.185286 42.8291667,11.875589 Z" id="path-47"></path>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-48">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <filter x="-50.0%" y="-10.0%" width="160.0%" height="160.0%" filterUnits="objectBoundingBox" id="filter-49">
+            <feOffset dx="-1" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-50" x="12.23" y="6.78958333" width="7.1175" height="17.5333333" rx="1.09459459"></rect>
+        <filter x="-42.1%" y="-5.7%" width="156.2%" height="117.1%" filterUnits="objectBoundingBox" id="filter-51">
+            <feOffset dx="-2" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <path d="M24.5975819,18.9156325 C22.7107005,18.6906938 20.1873316,18.3702571 18.5998357,18.0903387 C15.7716385,17.5916513 10.2254435,16.2267099 10.2254435,16.2267099 L9.43228672,20.7249253 C9.43228672,20.7249253 15.1331234,21.2766981 17.950402,21.7734603 C19.3152185,22.0141143 21.3273422,22.4758916 23.0359088,22.887195 C22.0718328,24.3735021 20.9147108,26.1229174 20.0932954,27.2534987 C18.405278,29.5768553 14.7471849,33.9633914 14.7471849,33.9633914 L18.4424572,36.6481639 C18.4424572,36.6481639 21.4374695,31.7661671 23.1189701,29.4517801 C23.9598468,28.2944125 25.3148663,26.6203912 26.4570264,25.2388063 C27.4382453,26.7462318 28.6051214,28.5736505 29.3214044,29.8142891 C30.7573178,32.301364 33.2767374,37.4273633 33.2767374,37.4273633 L37.2324017,35.1435594 C37.2324017,35.1435594 33.990657,30.4217925 32.5602872,27.9443193 C31.8079686,26.6412654 30.764866,24.5861738 29.94691,22.9346427 C31.7349883,22.451283 33.9931664,21.8608332 35.4733174,21.5462174 C38.2823878,20.9491311 43.9360463,20.1370415 43.9360463,20.1370415 L42.9863873,15.669247 C42.9863873,15.669247 37.4939659,17.2932232 34.6957402,17.8880045 C33.1431973,18.2180076 30.6947576,18.5971515 28.8277097,18.8686298 C28.722602,16.9801623 28.6032977,14.4864013 28.6032977,12.8962937 C28.6032977,10.024467 28.984416,4.32551158 28.984416,4.32551158 L24.4168083,4.32551158 C24.4168083,4.32551158 24.8633581,10.0355541 24.8633581,12.8962937 C24.8633581,14.5048733 24.7214143,17.0240015 24.5975819,18.9156325 Z" id="path-52"></path>
+        <filter x="-14.6%" y="-6.2%" width="120.9%" height="121.4%" filterUnits="objectBoundingBox" id="filter-54">
+            <feMorphology radius="0.547297297" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
+            <feOffset dx="-3" dy="3" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
+            <feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"></feComposite>
+            <feColorMatrix values="0 0 0 0 0.639215686   0 0 0 0 0.694117647   0 0 0 0 0.749019608  0 0 0 0.3 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <ellipse id="path-55" cx="26.802716" cy="22.6705733" rx="4.38" ry="4.38333333"></ellipse>
+        <filter x="-34.2%" y="-11.4%" width="145.7%" height="134.2%" filterUnits="objectBoundingBox" id="filter-56">
+            <feOffset dx="-2" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.596078431   0 0 0 0 0.647058824   0 0 0 0 0.701960784  0 0 0 1 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="403" transform="translate(-592.000000, -260.000000)">
+            <g id="Group-9" transform="translate(599.000000, 261.000000)">
+                <g id="Group-11">
+                    <g id="Rectangle-355">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
+                        <use stroke="#A3B1BF" stroke-width="1.62" fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-1"></use>
+                    </g>
+                    <g id="Rectangle-355">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use>
+                        <use stroke="#A3B1BF" stroke-width="1.62" fill-opacity="0.15" fill="#A3B1BF" fill-rule="evenodd" xlink:href="#path-3"></use>
+                    </g>
+                    <g id="Rectangle-357">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-6)" xlink:href="#path-5"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-5"></use>
+                        <path stroke="#A3B1BF" stroke-width="1.62" d="M176.0325,106.581667 L176.0325,90.6683333 L161.510068,90.6683333 C158.330251,90.6683333 155.7525,93.2460841 155.7525,96.4259009 L155.7525,100.824099 C155.7525,104.003916 158.330251,106.581667 161.510068,106.581667 L176.0325,106.581667 Z"></path>
+                    </g>
+                    <g id="Rectangle-357" transform="translate(188.340000, 98.625000) scale(-1, 1) translate(-188.340000, -98.625000) ">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-8)" xlink:href="#path-7"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-7"></use>
+                        <path stroke="#A3B1BF" stroke-width="1.62" d="M198.48,106.581667 L198.48,90.6683333 L183.957568,90.6683333 C180.777751,90.6683333 178.2,93.2460841 178.2,96.4259009 L178.2,100.824099 C178.2,104.003916 180.777751,106.581667 183.957568,106.581667 L198.48,106.581667 Z"></path>
+                    </g>
+                    <path d="M169.537821,109.198898 L179.520726,109.198898 L179.520726,106.316665 C179.657239,106.659699 174.968976,106.316665 172.419859,106.316665 L174.153055,100.243742 C171.605657,100.243742 169.537821,102.294522 169.537821,104.822572 L169.537821,109.198898 Z M181.404585,106.764356 L181.334952,105.82938 C178.493277,106.319657 175.877716,105.82938 172.088276,105.82938 L174.153055,98.0162037 C170.365914,98.0162037 167.291667,101.063519 167.291667,104.822572 L167.291667,106.764356 L166.869647,106.764356 L166.869647,106.764356 C165.758829,106.764356 164.858333,107.664852 164.858333,108.775669 L164.858333,108.775669 L164.858333,115.540394 C164.858333,119.983665 168.460316,123.585648 172.903588,123.585648 L176.279745,123.585648 C180.723017,123.585648 184.325,119.983665 184.325,115.540394 L184.325,108.775669 C184.325,107.664852 183.424504,106.764356 182.313686,106.764356 L181.404585,106.764356 Z" id="Shape" fill="#D4DBE2" fill-rule="nonzero"></path>
+                    <g id="Group-6" filter="url(#filter-9)" transform="translate(160.419753, 95.472603)">
+                        <ellipse id="Oval-191" stroke="#D9D9D9" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#D9D9D9" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6" filter="url(#filter-10)" transform="translate(189.259259, 95.472603)">
+                        <ellipse id="Oval-191" stroke="#D9D9D9" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#D9D9D9" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="lock" transform="translate(166.683333, 96.798611)">
+                        <path d="M2.43333333,9.34812925 L2.43333333,7.750693 C2.43333333,4.33901358 4.64933408,1.45058816 7.70555556,0.476293029 L7.70555556,4.05203095 C6.57838885,4.84048413 5.84,6.15673686 5.84,7.64734194 L5.84,9.34812925 L14.4830461,9.34812925 C14.4830461,8.8280509 14.4830461,8.25372782 14.4830461,7.64734194 C14.4830461,6.44285214 14.0009139,5.352206 13.2211113,4.56188949 L13.2211113,0.864048014 C15.7633754,2.09038625 17.52,4.7131478 17.52,7.750693 C17.52,8.30041562 17.52,8.83504216 17.52,9.3491485 C18.6008993,9.38327886 19.4666667,10.2702555 19.4666667,11.3594429 L19.4666667,18.3317768 C19.4666667,22.7750482 15.8646835,26.3770314 11.4214121,26.3770314 L8.04525456,26.3770314 C3.60198316,26.3770314 5.4414381e-16,22.7750482 0,18.3317768 L0,11.3594429 C-1.36035952e-16,10.248625 0.900495789,9.34812925 2.01131364,9.34812925 L2.01131364,9.34812925 L2.43333333,9.34812925 Z" id="Combined-Shape" stroke="#A3B1BF" stroke-width="1.62" fill="#F0F2F5"></path>
+                        <g id="Oval-1115">
+                            <use fill-opacity="0.3" fill="#A3B1BF" fill-rule="evenodd" xlink:href="#path-11"></use>
+                            <use fill="black" fill-opacity="1" filter="url(#filter-12)" xlink:href="#path-11"></use>
+                        </g>
+                    </g>
+                    <g id="Group-6" filter="url(#filter-13)" transform="translate(64.000000, 75.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-11" filter="url(#filter-14)" transform="translate(152.000000, 75.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-2" filter="url(#filter-15)" transform="translate(57.000000, 120.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-3" filter="url(#filter-16)" transform="translate(57.000000, 137.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-4" filter="url(#filter-17)" transform="translate(64.000000, 186.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-5" filter="url(#filter-18)" transform="translate(93.000000, 191.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-6" filter="url(#filter-19)" transform="translate(122.000000, 191.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-7" filter="url(#filter-20)" transform="translate(152.000000, 186.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6" filter="url(#filter-21)" transform="translate(160.419753, 95.472603)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F5F5F5" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6" filter="url(#filter-22)" transform="translate(189.259259, 95.472603)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                    </g>
+                    <g id="Group-6" filter="url(#filter-23)" transform="translate(25.000000, 38.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.64189189" fill="#F7FAFC" cx="4.38" cy="4.93125" rx="4.38" ry="4.38333333"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="4.0041131 9.13310534 7.56201455 8.23226901 2.34303487 0.44644438 0.446211571 3.63004005 0.788921826 7.80592737"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-8" filter="url(#filter-24)" transform="translate(25.000000, 218.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.64189189" fill="#F7FAFC" cx="4.38" cy="4.93125" rx="4.38" ry="4.38333333"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="4.0041131 9.13310534 7.56201455 8.23226901 2.34303487 0.44644438 0.446211571 3.63004005 0.788921826 7.80592737"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-9" filter="url(#filter-25)" transform="translate(106.000000, 237.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.64189189" fill="#F7FAFC" cx="4.38" cy="4.93125" rx="4.38" ry="4.38333333"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="4.0041131 9.13310534 7.56201455 8.23226901 2.34303487 0.44644438 0.446211571 3.63004005 0.788921826 7.80592737"></polygon>
+                    </g>
+                    <g id="Group-6-Copy-10" filter="url(#filter-26)" transform="translate(185.000000, 219.000000)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.64189189" fill="#F7FAFC" cx="4.38" cy="4.93125" rx="4.38" ry="4.38333333"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="4.0041131 9.13310534 7.56201455 8.23226901 2.34303487 0.44644438 0.446211571 3.63004005 0.788921826 7.80592737"></polygon>
+                    </g>
+                    <g id="Group-6" filter="url(#filter-27)" transform="translate(14.419753, 129.698630)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.64189189" fill="#F7FAFC" cx="4.38" cy="4.93125" rx="4.38" ry="4.38333333"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="4.0041131 9.13310534 7.56201455 8.23226901 2.34303487 0.44644438 0.446211571 3.63004005 0.788921826 7.80592737"></polygon>
+                    </g>
+                    <g id="Group-6" filter="url(#filter-28)" transform="translate(105.444444, 20.715753)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.64189189" fill="#F7FAFC" cx="4.38" cy="4.93125" rx="4.38" ry="4.38333333"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="4.0041131 9.13310534 7.56201455 8.23226901 2.34303487 0.44644438 0.446211571 3.63004005 0.788921826 7.80592737"></polygon>
+                    </g>
+                    <g id="Group-6" filter="url(#filter-29)" transform="translate(185.055000, 37.806250)">
+                        <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.64189189" fill="#F5F5F5" cx="4.38" cy="4.93125" rx="4.38" ry="4.38333333"></ellipse>
+                        <polygon id="Path-301" fill="#A3B1BF" points="4.0041131 9.13310534 7.56201455 8.23226901 2.34303487 0.44644438 0.446211571 3.63004005 0.788921826 7.80592737"></polygon>
+                    </g>
+                    <g id="Rectangle-373">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-31)" xlink:href="#path-30"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-30"></use>
+                        <rect stroke="#A3B1BF" stroke-width="2.43" x="80.2983333" y="70.0089815" width="58.4033333" height="21.9218519"></rect>
+                    </g>
+                    <mask id="mask-33" fill="white">
+                        <use xlink:href="#path-32"></use>
+                    </mask>
+                    <use id="Mask" fill-opacity="0.3" fill="#A3B1BF" xlink:href="#path-32"></use>
+                    <rect id="Rectangle-375" fill="#A3B1BF" x="114.366667" y="77.3171296" width="1.825" height="8.11728395" rx="0.9125"></rect>
+                    <rect id="Rectangle-375" fill="#A3B1BF" x="118.016667" y="72.6496914" width="2.43333333" height="16.2345679" rx="1.21666667"></rect>
+                    <g id="Group-4" transform="translate(25.000000, 88.000000)">
+                        <g id="Rectangle-369">
+                            <use fill="black" fill-opacity="1" filter="url(#filter-35)" xlink:href="#path-34"></use>
+                            <use fill="#EAEFF3" fill-rule="evenodd" xlink:href="#path-34"></use>
+                            <path stroke="#A3B1BF" stroke-width="1.62" d="M14.6441667,30.0879167 L14.6441667,1.02458333 L6.69173423,1.02458333 C3.51191747,1.02458333 0.934166667,3.60233414 0.934166667,6.7821509 L0.934166667,24.3303491 C0.934166667,27.5101659 3.51191747,30.0879167 6.69173423,30.0879167 L14.6441667,30.0879167 Z"></path>
+                        </g>
+                        <g id="Group-6" filter="url(#filter-36)" transform="translate(6.207500, 6.789583)">
+                            <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                            <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                        </g>
+                        <g id="Group-6" filter="url(#filter-37)" transform="translate(6.543210, 19.181507)">
+                            <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                            <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                        </g>
+                        <g id="Rectangle-371">
+                            <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-38"></use>
+                            <path stroke="#A3B1BF" stroke-width="1.62" d="M18.4541667,9.31638699 L18.4541667,21.7961161 L41.6574976,19.7900592 C41.8219325,19.7734468 42.0191667,19.5280875 42.0191667,19.236911 L42.0191667,11.875589 C42.0191667,11.5822335 41.824213,11.3392839 41.6691435,11.3235325 L18.4541667,9.31638699 Z"></path>
+                        </g>
+                        <g id="Group-6" filter="url(#filter-39)" transform="translate(23.000000, 13.000000)">
+                            <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                            <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                        </g>
+                        <g id="Group-6-Copy" filter="url(#filter-40)" transform="translate(33.000000, 13.000000)">
+                            <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                            <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                        </g>
+                        <g id="Rectangle-370">
+                            <use fill="black" fill-opacity="1" filter="url(#filter-42)" xlink:href="#path-41"></use>
+                            <use fill="#EAEFF3" fill-rule="evenodd" xlink:href="#path-41"></use>
+                            <rect stroke="#A3B1BF" stroke-width="1.62" x="13.04" y="7.59958333" width="5.4975" height="15.9133333" rx="1.09459459"></rect>
+                        </g>
+                        <path d="M13.59875,15.55625 L17.97875,15.55625" id="Line" stroke="#A3B1BF" stroke-width="2.18918919" stroke-linecap="square"></path>
+                    </g>
+                    <g id="Group-4-Copy" transform="translate(25.000000, 145.000000)">
+                        <g id="Rectangle-369">
+                            <use fill="black" fill-opacity="1" filter="url(#filter-44)" xlink:href="#path-43"></use>
+                            <use fill="#EAEFF3" fill-rule="evenodd" xlink:href="#path-43"></use>
+                            <path stroke="#A3B1BF" stroke-width="1.62" d="M14.6441667,30.0879167 L14.6441667,1.02458333 L6.69173423,1.02458333 C3.51191747,1.02458333 0.934166667,3.60233414 0.934166667,6.7821509 L0.934166667,24.3303491 C0.934166667,27.5101659 3.51191747,30.0879167 6.69173423,30.0879167 L14.6441667,30.0879167 Z"></path>
+                        </g>
+                        <g id="Group-6" filter="url(#filter-45)" transform="translate(6.207500, 6.789583)">
+                            <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                            <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                        </g>
+                        <g id="Group-6" filter="url(#filter-46)" transform="translate(6.543210, 19.181507)">
+                            <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                            <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                        </g>
+                        <g id="Rectangle-371">
+                            <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-47"></use>
+                            <path stroke="#A3B1BF" stroke-width="1.62" d="M18.4541667,9.31638699 L18.4541667,21.7961161 L41.6574976,19.7900592 C41.8219325,19.7734468 42.0191667,19.5280875 42.0191667,19.236911 L42.0191667,11.875589 C42.0191667,11.5822335 41.824213,11.3392839 41.6691435,11.3235325 L18.4541667,9.31638699 Z"></path>
+                        </g>
+                        <g id="Group-6" filter="url(#filter-48)" transform="translate(23.000000, 13.000000)">
+                            <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                            <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                        </g>
+                        <g id="Group-6-Copy" filter="url(#filter-49)" transform="translate(33.000000, 13.000000)">
+                            <ellipse id="Oval-191" stroke="#A3B1BF" stroke-width="1.09459459" fill="#F7FAFC" cx="2.19" cy="2.73958333" rx="2.19" ry="2.19166667"></ellipse>
+                            <polygon id="Path-301" fill="#A3B1BF" points="3.78100727 4.39009284 1.17151744 0.497180523 0.223105786 2.08897836 0.101076918 4.39009284"></polygon>
+                        </g>
+                        <g id="Rectangle-370">
+                            <use fill="black" fill-opacity="1" filter="url(#filter-51)" xlink:href="#path-50"></use>
+                            <use fill="#EAEFF3" fill-rule="evenodd" xlink:href="#path-50"></use>
+                            <rect stroke="#A3B1BF" stroke-width="1.62" x="13.04" y="7.59958333" width="5.4975" height="15.9133333" rx="1.09459459"></rect>
+                        </g>
+                        <path d="M13.59875,15.55625 L17.97875,15.55625" id="Line" stroke="#A3B1BF" stroke-width="2.18918919" stroke-linecap="square"></path>
+                    </g>
+                </g>
+                <g id="Group-17" transform="translate(135.185185, 131.500000)">
+                    <path d="M22.4835494,46.23099 C10.0861375,46.23099 0.0360493827,36.1732534 0.0360493827,23.7664066 C0.0360493827,11.3595599 10.0861375,1.30182331 22.4835494,1.30182331 C34.8809613,1.30182331 44.9310494,11.3595599 44.9310494,23.7664066 C44.9310494,36.1732534 34.8809613,46.23099 22.4835494,46.23099 Z M22.4835494,39.65599 C31.2524505,39.65599 38.3610494,32.5419812 38.3610494,23.7664066 C38.3610494,14.9908321 31.2524505,7.87682331 22.4835494,7.87682331 C13.7146483,7.87682331 6.60604938,14.9908321 6.60604938,23.7664066 C6.60604938,32.5419812 13.7146483,39.65599 22.4835494,39.65599 Z" id="Oval-190" fill-opacity="0.3" fill="#A3B1BF"></path>
+                    <mask id="mask-53" fill="white">
+                        <use xlink:href="#path-52"></use>
+                    </mask>
+                    <g id="Mask">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-54)" xlink:href="#path-52"></use>
+                        <use stroke="#A3B1BF" stroke-width="1.09459459" fill="#A3B1BF" fill-rule="evenodd" xlink:href="#path-52"></use>
+                    </g>
+                    <g id="Group-7" transform="translate(0.360494, 0.078598)" fill="#98A5B3">
+                        <path d="M20.5636489,0.927088888 C22.1113303,0.589405992 23.7186545,0.411496914 25.3675,0.411496914 C37.7649119,0.411496914 47.815,10.4692335 47.815,22.8760802 C47.815,33.7386653 40.1110508,42.8005273 29.8728116,44.8880725 L27.4696515,38.6276265 C35.2448963,37.5983622 41.245,30.9384541 41.245,22.8760802 C41.245,14.1005057 34.1364011,6.98649691 25.3675,6.98649691 C22.0362626,6.98649691 18.9446369,8.01317718 16.3913275,9.76760576 L15.30877,6.94744709 L20.5636489,0.927088888 Z" id="Oval-190"></path>
+                    </g>
+                    <path d="M26.802716,45.1351566 C14.4053041,45.1351566 4.35521605,35.0774201 4.35521605,22.6705733 C4.35521605,10.2637265 14.4053041,0.20598998 26.802716,0.20598998 C39.200128,0.20598998 49.250216,10.2637265 49.250216,22.6705733 C49.250216,35.0774201 39.200128,45.1351566 26.802716,45.1351566 Z M26.802716,38.5601566 C35.5716172,38.5601566 42.680216,31.4461479 42.680216,22.6705733 C42.680216,13.8949988 35.5716172,6.78098998 26.802716,6.78098998 C18.0338149,6.78098998 10.925216,13.8949988 10.925216,22.6705733 C10.925216,31.4461479 18.0338149,38.5601566 26.802716,38.5601566 Z" id="Oval-190" fill="#A3B1BF"></path>
+                    <path d="M37.5685802,6.47400902 C37.5685802,6.47400902 40.3560433,8.0639828 43.0005786,12.4958138 C45.6451139,16.9276447 45.9870813,21.4863845 45.9870813,21.4863845" id="Line" stroke="#F7FAFC" stroke-width="1.62" stroke-linecap="round"></path>
+                    <g id="Oval-199">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-56)" xlink:href="#path-55"></use>
+                        <use fill="#A3B1BF" fill-rule="evenodd" xlink:href="#path-55"></use>
+                    </g>
+                    <path d="M27.0403924,24.1861178 C28.3842853,24.1861178 29.4737257,23.0958483 29.4737257,21.7509326 C29.4737257,20.406017 28.3842853,19.3157475 27.0403924,19.3157475 C27.0403924,19.3157475 27.6699621,20.406017 27.6699621,21.7509326 C27.6699621,23.0958483 27.0403924,24.1861178 27.0403924,24.1861178 Z" id="Oval-199" fill="#F7FAFC" transform="translate(28.257059, 21.750933) rotate(-43.000000) translate(-28.257059, -21.750933) "></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 314 - 0
admin/images/404.svg

@@ -0,0 +1,314 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="423px" height="341px" viewBox="0 0 423 341" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 4</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="404" transform="translate(-484.000000, -221.000000)">
+            <g id="Group-4" transform="translate(464.000000, 222.000000)">
+                <g id="Group-5" transform="translate(75.417348, 0.163879)" stroke="#A3B1BF" stroke-width="1.62" opacity="0.6" stroke-linejoin="round" stroke-dasharray="12.15">
+                    <path d="M169.575185,288.890375 C103.647066,288.890375 50.2010204,235.455806 50.2010204,169.540425 C50.2010204,103.625045 103.647066,50.1904762 169.575185,50.1904762 C235.50394,50.1904762 288.94935,103.625045 288.94935,169.540425 C288.94935,235.455806 235.50394,288.890375 169.575185,288.890375 Z" id="Stroke-1"></path>
+                    <path d="M169.405699,338.555288 C76.0274364,338.555288 0.329411882,262.872619 0.329411882,169.513299 C0.329411882,76.1539786 76.0274364,0.471309613 169.405699,0.471309613 C262.783961,0.471309613 338.481985,76.1539786 338.481985,169.513299 C338.481985,262.872619 262.783961,338.555288 169.405699,338.555288 Z" id="Stroke-3"></path>
+                </g>
+                <polygon id="Fill-6" fill="#F5F5F5" transform="translate(106.914750, 199.432805) rotate(22.000000) translate(-106.914750, -199.432805) " points="97.7112298 198.803016 116.11827 190.231152 107.544667 208.634458"></polygon>
+                <polygon id="Stroke-7" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(106.914750, 199.432805) rotate(22.000000) translate(-106.914750, -199.432805) " points="97.7112298 198.803016 116.11827 190.231152 107.544667 208.634458"></polygon>
+                <polygon id="Fill-8" transform="translate(58.996118, 219.767028) rotate(22.000000) translate(-58.996118, -219.767028) " points="38.8543444 215.183828 54.4119879 199.629341 79.1378915 224.350228 63.580248 239.904716"></polygon>
+                <polygon id="Stroke-9" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(58.996118, 219.767028) rotate(22.000000) translate(-58.996118, -219.767028) " points="38.8543444 215.183828 54.4119879 199.629341 79.1378915 224.350228 63.580248 239.904716"></polygon>
+                <polygon id="Fill-10" fill="#F5F5F5" transform="translate(71.226096, 214.577614) rotate(22.000000) translate(-71.226096, -214.577614) " points="51.4642422 198.657893 55.3028278 194.820086 90.9879502 230.497335 87.1487294 234.335141"></polygon>
+                <polygon id="Stroke-11" stroke="#A3B1BF" stroke-width="1.62" fill="#F0F2F5" stroke-linejoin="round" transform="translate(71.226096, 214.577614) rotate(22.000000) translate(-71.226096, -214.577614) " points="51.4642422 198.657893 55.3028278 194.820086 90.9879502 230.497335 87.1487294 234.335141"></polygon>
+                <polygon id="Fill-12" transform="translate(84.698338, 273.903349) rotate(22.000000) translate(-84.698338, -273.903349) " points="56.0769883 259.690379 70.4821667 245.288122 113.319688 288.116319 98.9145099 302.518575"></polygon>
+                <polygon id="Stroke-13" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(84.698338, 273.903349) rotate(22.000000) translate(-84.698338, -273.903349) " points="56.0769883 259.690379 70.4821667 245.288122 113.319688 288.116319 98.9145099 302.518575"></polygon>
+                <polygon id="Fill-14" transform="translate(75.456149, 212.782520) rotate(22.000000) translate(-75.456149, -212.782520) " points="63.8911557 203.879723 66.5512281 201.22019 87.0211429 221.685318 84.3604352 224.34485"></polygon>
+                <polygon id="Stroke-15" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(75.456149, 212.782520) rotate(22.000000) translate(-75.456149, -212.782520) " points="63.8911557 203.879723 66.5512281 201.22019 87.0211429 221.685318 84.3604352 224.34485"></polygon>
+                <polygon id="Fill-16" fill="#F5F5F5" transform="translate(78.176142, 202.618192) rotate(22.000000) translate(-78.176142, -202.618192) " points="74.4026766 205.006817 80.5652518 198.845492 81.9496076 200.229567 75.7870324 206.390892"></polygon>
+                <polygon id="Stroke-17" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(78.176142, 202.618192) rotate(22.000000) translate(-78.176142, -202.618192) " points="74.4026766 205.006817 80.5652518 198.845492 81.9496076 200.229567 75.7870324 206.390892"></polygon>
+                <polygon id="Fill-18" fill="#F5F5F5" transform="translate(84.676979, 217.928886) rotate(22.000000) translate(-84.676979, -217.928886) " points="80.9035138 220.317511 87.066089 214.156186 88.4504448 215.540261 82.2878696 221.701586"></polygon>
+                <polygon id="Stroke-19" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(84.676979, 217.928886) rotate(22.000000) translate(-84.676979, -217.928886) " points="80.9035138 220.317511 87.066089 214.156186 88.4504448 215.540261 82.2878696 221.701586"></polygon>
+                <polygon id="Fill-20" transform="translate(70.238421, 242.404581) rotate(22.000000) translate(-70.238421, -242.404581) " points="67.8493111 238.631881 74.0118863 244.793206 72.6275305 246.177281 66.4649553 240.015956"></polygon>
+                <polygon id="Stroke-21" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(70.238421, 242.404581) rotate(22.000000) translate(-70.238421, -242.404581) " points="67.8493111 238.631881 74.0118863 244.793206 72.6275305 246.177281 66.4649553 240.015956"></polygon>
+                <polygon id="Fill-22" transform="translate(48.081755, 224.398789) rotate(22.000000) translate(-48.081755, -224.398789) " points="35.1127107 220.725179 36.3242602 211.432376 61.0507992 236.153899 51.756111 237.365203"></polygon>
+                <polygon id="Stroke-23" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(48.081755, 224.398789) rotate(22.000000) translate(-48.081755, -224.398789) " points="35.1127107 220.725179 36.3242602 211.432376 61.0507992 236.153899 51.756111 237.365203"></polygon>
+                <polygon id="Fill-24" transform="translate(38.612968, 228.416820) rotate(22.000000) translate(-38.612968, -228.416820) " points="32.9179858 217.470622 26.2496982 216.056058 50.9762371 240.777581 49.5613861 234.110647"></polygon>
+                <polygon id="Stroke-25" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(38.612968, 228.416820) rotate(22.000000) translate(-38.612968, -228.416820) " points="32.9179858 217.470622 26.2496982 216.056058 50.9762371 240.777581 49.5613861 234.110647"></polygon>
+                <polygon id="Fill-26" transform="translate(31.086342, 221.523909) rotate(22.000000) translate(-31.086342, -221.523909) " points="32.6469986 217.297684 26.8592604 218.37941 34.2314793 225.750133 35.3134242 219.963569"></polygon>
+                <polygon id="Stroke-27" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(31.086342, 221.523909) rotate(22.000000) translate(-31.086342, -221.523909) " points="32.6469986 217.297684 26.8592604 218.37941 34.2314793 225.750133 35.3134242 219.963569"></polygon>
+                <polygon id="Fill-28" transform="translate(38.344372, 238.617819) rotate(22.000000) translate(-38.344372, -238.617819) " points="39.9050284 234.391595 34.1172902 235.47332 41.4895091 242.844044 42.571454 237.05748"></polygon>
+                <polygon id="Stroke-29" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(38.344372, 238.617819) rotate(22.000000) translate(-38.344372, -238.617819) " points="39.9050284 234.391595 34.1172902 235.47332 41.4895091 242.844044 42.571454 237.05748"></polygon>
+                <polygon id="Fill-30" fill="#F0F2F5" transform="translate(75.352798, 203.766862) rotate(22.000000) translate(-75.352798, -203.766862) " points="71.4417859 201.708217 73.2937351 199.856644 79.2638092 205.824871 77.4118601 207.67708"></polygon>
+                <polygon id="Stroke-31" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(75.352798, 203.766862) rotate(22.000000) translate(-75.352798, -203.766862) " points="71.4417859 201.708217 73.2937351 199.856644 79.2638092 205.824871 77.4118601 207.67708"></polygon>
+                <polygon id="Fill-32" fill="#F0F2F5" transform="translate(81.871541, 219.119730) rotate(22.000000) translate(-81.871541, -219.119730) " points="77.9605297 217.061085 79.8124789 215.209512 85.7825531 221.177739 83.9306039 223.029948"></polygon>
+                <polygon id="Stroke-33" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(81.871541, 219.119730) rotate(22.000000) translate(-81.871541, -219.119730) " points="77.9605297 217.061085 79.8124789 215.209512 85.7825531 221.177739 83.9306039 223.029948"></polygon>
+                <polygon id="Fill-34" transform="translate(68.034935, 237.215417) rotate(22.000000) translate(-68.034935, -237.215417) " points="65.1594898 237.106164 67.9256601 234.340555 70.9103796 237.324669 68.1442092 240.090278"></polygon>
+                <polygon id="Stroke-35" stroke="#A3B1BF" stroke-width="1.62" fill="#F5F5F5" stroke-linejoin="round" transform="translate(68.034935, 237.215417) rotate(22.000000) translate(-68.034935, -237.215417) " points="65.1594898 237.106164 67.9256601 234.340555 70.9103796 237.324669 68.1442092 240.090278"></polygon>
+                <path d="M90.2556147,213.065319 C79.2271463,202.039088 74.6433339,188.153875 78.4889079,179.512775 C79.1248602,178.084237 80.8319571,175.429786 84.5339495,179.131027 C88.2353065,182.832268 120.560237,215.150007 123.931865,218.52095 C127.303492,221.891894 125.245065,224.192545 123.817508,224.827733 C115.174655,228.675068 101.284718,224.092186 90.2556147,213.065319 Z" id="Fill-36" fill="#F5F5F5" transform="translate(101.453924, 201.708917) rotate(22.000000) translate(-101.453924, -201.708917) "></path>
+                <path d="M90.2556147,213.065319 C79.2271463,202.039088 74.6433339,188.153875 78.4889079,179.512775 C79.1248602,178.084237 80.8319571,175.429786 84.5339495,179.131027 C88.2353065,182.832268 120.560237,215.150007 123.931865,218.52095 C127.303492,221.891894 125.245065,224.192545 123.817508,224.827733 C115.174655,228.675068 101.284718,224.092186 90.2556147,213.065319 Z" id="Stroke-38" stroke="#A3B1BF" stroke-width="1.62" fill="#F0F2F5" stroke-linejoin="round" transform="translate(101.453924, 201.708917) rotate(22.000000) translate(-101.453924, -201.708917) "></path>
+                <polygon id="Fill-40" fill="#F0F2F5" transform="translate(86.633853, 208.038961) rotate(22.000000) translate(-86.633853, -208.038961) " points="77.9716233 201.230061 79.8235724 199.378488 95.2960835 214.84786 93.4441343 216.699433"></polygon>
+                <polygon id="Stroke-42" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(86.633853, 208.038961) rotate(22.000000) translate(-86.633853, -208.038961) " points="77.9716233 201.230061 79.8235724 199.378488 95.2960835 214.84786 93.4441343 216.699433"></polygon>
+                <path d="M121.635514,196.068815 C120.517356,197.186746 118.704797,197.186746 117.586639,196.068815 C116.469116,194.950884 116.469116,193.138692 117.586639,192.020761 C118.704797,190.903465 120.517356,190.903465 121.635514,192.020761 C122.753672,193.138692 122.753672,194.950884 121.635514,196.068815" id="Fill-44" fill="#A3B1BF" transform="translate(119.611315, 194.045026) rotate(22.000000) translate(-119.611315, -194.045026) "></path>
+                <polygon id="Fill-46" fill-opacity="0.6" fill="#A3B1BF" transform="translate(81.250567, 248.056422) rotate(22.000000) translate(-81.250567, -248.056422) " points="81.2505672 249.672341 79.6343206 248.056422 81.2505672 246.440503 82.8668137 248.056422"></polygon>
+                <polygon id="Stroke-48" transform="translate(81.250567, 248.056422) rotate(22.000000) translate(-81.250567, -248.056422) " points="81.2505672 249.672341 79.6343206 248.056422 81.2505672 246.440503 82.8668137 248.056422"></polygon>
+                <polygon id="Fill-50" fill-opacity="0.6" fill="#A3B1BF" transform="translate(82.702196, 251.475282) rotate(22.000000) translate(-82.702196, -251.475282) " points="82.7021965 253.091201 81.0859499 251.475282 82.7021965 249.859363 84.318443 251.475282"></polygon>
+                <polygon id="Stroke-52" transform="translate(82.702196, 251.475282) rotate(22.000000) translate(-82.702196, -251.475282) " points="82.7021965 253.091201 81.0859499 251.475282 82.7021965 249.859363 84.318443 251.475282"></polygon>
+                <polygon id="Fill-54" fill-opacity="0.6" fill="#A3B1BF" transform="translate(84.153791, 254.894059) rotate(22.000000) translate(-84.153791, -254.894059) " points="84.1537906 256.509978 82.5375441 254.894059 84.1537906 253.278141 85.7700372 254.894059"></polygon>
+                <polygon id="Stroke-56" transform="translate(84.153791, 254.894059) rotate(22.000000) translate(-84.153791, -254.894059) " points="84.1537906 256.509978 82.5375441 254.894059 84.1537906 253.278141 85.7700372 254.894059"></polygon>
+                <polygon id="Fill-58" fill-opacity="0.6" fill="#A3B1BF" transform="translate(85.605385, 258.312837) rotate(22.000000) translate(-85.605385, -258.312837) " points="85.6053848 259.928756 83.9891383 258.312837 85.6053848 256.696918 87.2216313 258.312837"></polygon>
+                <polygon id="Stroke-60" transform="translate(85.605385, 258.312837) rotate(22.000000) translate(-85.605385, -258.312837) " points="85.6053848 259.928756 83.9891383 258.312837 85.6053848 256.696918 87.2216313 258.312837"></polygon>
+                <polygon id="Fill-62" fill-opacity="0.6" fill="#A3B1BF" transform="translate(78.094482, 249.395723) rotate(22.000000) translate(-78.094482, -249.395723) " points="78.0944819 251.011642 76.4782353 249.395723 78.0944819 247.779804 79.7107284 249.395723"></polygon>
+                <polygon id="Stroke-64" transform="translate(78.094482, 249.395723) rotate(22.000000) translate(-78.094482, -249.395723) " points="78.0944819 251.011642 76.4782353 249.395723 78.0944819 247.779804 79.7107284 249.395723"></polygon>
+                <polygon id="Fill-66" fill-opacity="0.6" fill="#A3B1BF" transform="translate(79.546052, 252.814559) rotate(22.000000) translate(-79.546052, -252.814559) " points="79.5460522 254.430478 77.9298057 252.814559 79.5460522 251.198641 81.1622988 252.814559"></polygon>
+                <polygon id="Stroke-68" transform="translate(79.546052, 252.814559) rotate(22.000000) translate(-79.546052, -252.814559) " points="79.5460522 254.430478 77.9298057 252.814559 79.5460522 251.198641 81.1622988 252.814559"></polygon>
+                <polygon id="Fill-70" fill-opacity="0.6" fill="#A3B1BF" transform="translate(80.997705, 256.233360) rotate(22.000000) translate(-80.997705, -256.233360) " points="80.9977053 257.849279 79.3814588 256.23336 80.9977053 254.617442 82.6139518 256.23336"></polygon>
+                <polygon id="Stroke-72" transform="translate(80.997705, 256.233360) rotate(22.000000) translate(-80.997705, -256.233360) " points="79.3814588 256.23336 80.9977053 254.617442 82.6139518 256.23336 80.9977053 257.849279"></polygon>
+                <polygon id="Fill-74" fill-opacity="0.6" fill="#A3B1BF" transform="translate(82.449276, 259.652197) rotate(22.000000) translate(-82.449276, -259.652197) " points="82.4492757 261.268115 80.8330292 259.652197 82.4492757 258.036278 84.0655222 259.652197"></polygon>
+                <polygon id="Stroke-76" transform="translate(82.449276, 259.652197) rotate(22.000000) translate(-82.449276, -259.652197) " points="82.4492757 261.268115 80.8330292 259.652197 82.4492757 258.036278 84.0655222 259.652197"></polygon>
+                <polygon id="Fill-78" fill-opacity="0.6" fill="#A3B1BF" transform="translate(74.938373, 250.735083) rotate(22.000000) translate(-74.938373, -250.735083) " points="74.9383727 252.351002 73.3221262 250.735083 74.9383727 249.119164 76.5546193 250.735083"></polygon>
+                <polygon id="Stroke-80" transform="translate(74.938373, 250.735083) rotate(22.000000) translate(-74.938373, -250.735083) " points="74.9383727 252.351002 73.3221262 250.735083 74.9383727 249.119164 76.5546193 250.735083"></polygon>
+                <polygon id="Fill-82" fill-opacity="0.6" fill="#A3B1BF" transform="translate(76.389967, 254.153860) rotate(22.000000) translate(-76.389967, -254.153860) " points="76.3899669 255.769779 74.7737204 254.15386 76.3899669 252.537942 78.0062134 254.15386"></polygon>
+                <polygon id="Stroke-84" transform="translate(76.389967, 254.153860) rotate(22.000000) translate(-76.389967, -254.153860) " points="76.3899669 255.769779 74.7737204 254.15386 76.3899669 252.537942 78.0062134 254.15386"></polygon>
+                <polygon id="Fill-86" fill-opacity="0.6" fill="#A3B1BF" transform="translate(77.841620, 257.572661) rotate(22.000000) translate(-77.841620, -257.572661) " points="77.84162 259.18858 76.2253735 257.572661 77.84162 255.956743 79.4578665 257.572661"></polygon>
+                <polygon id="Stroke-88" transform="translate(77.841620, 257.572661) rotate(22.000000) translate(-77.841620, -257.572661) " points="77.84162 259.18858 76.2253735 257.572661 77.84162 255.956743 79.4578665 257.572661"></polygon>
+                <polygon id="Fill-90" fill-opacity="0.6" fill="#A3B1BF" transform="translate(79.293190, 260.991498) rotate(22.000000) translate(-79.293190, -260.991498) " points="79.2931904 262.607416 77.6769438 260.991498 79.2931904 259.375579 80.9094369 260.991498"></polygon>
+                <polygon id="Stroke-92" transform="translate(79.293190, 260.991498) rotate(22.000000) translate(-79.293190, -260.991498) " points="79.2931904 262.607416 77.6769438 260.991498 79.2931904 259.375579 80.9094369 260.991498"></polygon>
+                <polygon id="Fill-94" fill-opacity="0.6" fill="#A3B1BF" transform="translate(71.782287, 252.074384) rotate(22.000000) translate(-71.782287, -252.074384) " points="71.7822874 253.690302 70.1660409 252.074384 71.7822874 250.458465 73.3985339 252.074384"></polygon>
+                <polygon id="Stroke-96" transform="translate(71.782287, 252.074384) rotate(22.000000) translate(-71.782287, -252.074384) " points="71.7822874 253.690302 70.1660409 252.074384 71.7822874 250.458465 73.3985339 252.074384"></polygon>
+                <polygon id="Fill-98" fill-opacity="0.6" fill="#A3B1BF" transform="translate(73.233882, 255.493161) rotate(22.000000) translate(-73.233882, -255.493161) " points="73.2338816 257.10908 71.6176351 255.493161 73.2338816 253.877242 74.8501281 255.493161"></polygon>
+                <polygon id="Stroke-100" transform="translate(73.233882, 255.493161) rotate(22.000000) translate(-73.233882, -255.493161) " points="73.2338816 257.10908 71.6176351 255.493161 73.2338816 253.877242 74.8501281 255.493161"></polygon>
+                <polygon id="Fill-102" fill-opacity="0.6" fill="#A3B1BF" transform="translate(74.685535, 258.911962) rotate(22.000000) translate(-74.685535, -258.911962) " points="74.6855347 260.527881 73.0692881 258.911962 74.6855347 257.296044 76.3017812 258.911962"></polygon>
+                <polygon id="Stroke-104" transform="translate(74.685535, 258.911962) rotate(22.000000) translate(-74.685535, -258.911962) " points="74.6855347 260.527881 73.0692881 258.911962 74.6855347 257.296044 76.3017812 258.911962"></polygon>
+                <polygon id="Fill-106" fill-opacity="0.6" fill="#A3B1BF" transform="translate(76.137105, 262.330799) rotate(22.000000) translate(-76.137105, -262.330799) " points="76.137105 263.946717 74.5208585 262.330799 76.137105 260.71488 77.7533516 262.330799"></polygon>
+                <polygon id="Stroke-108" transform="translate(76.137105, 262.330799) rotate(22.000000) translate(-76.137105, -262.330799) " points="76.137105 263.946717 74.5208585 262.330799 76.137105 260.71488 77.7533516 262.330799"></polygon>
+                <polygon id="Fill-110" fill-opacity="0.6" fill="#A3B1BF" transform="translate(68.626202, 253.413685) rotate(22.000000) translate(-68.626202, -253.413685) " points="68.6262021 255.029603 67.0099556 253.413685 68.6262021 251.797766 70.2424486 253.413685"></polygon>
+                <polygon id="Stroke-112" transform="translate(68.626202, 253.413685) rotate(22.000000) translate(-68.626202, -253.413685) " points="68.6262021 255.029603 67.0099556 253.413685 68.6262021 251.797766 70.2424486 253.413685"></polygon>
+                <polygon id="Fill-114" fill-opacity="0.6" fill="#A3B1BF" transform="translate(70.077796, 256.832462) rotate(22.000000) translate(-70.077796, -256.832462) " points="70.0777963 258.448381 68.4615497 256.832462 70.0777963 255.216543 71.6940428 256.832462"></polygon>
+                <polygon id="Stroke-116" transform="translate(70.077796, 256.832462) rotate(22.000000) translate(-70.077796, -256.832462) " points="70.0777963 258.448381 68.4615497 256.832462 70.0777963 255.216543 71.6940428 256.832462"></polygon>
+                <polygon id="Fill-118" fill-opacity="0.6" fill="#A3B1BF" transform="translate(71.529426, 260.251322) rotate(22.000000) translate(-71.529426, -260.251322) " points="71.5294256 261.867241 69.913179 260.251322 71.5294256 258.635403 73.1456721 260.251322"></polygon>
+                <polygon id="Stroke-120" transform="translate(71.529426, 260.251322) rotate(22.000000) translate(-71.529426, -260.251322) " points="71.5294256 261.867241 69.913179 260.251322 71.5294256 258.635403 73.1456721 260.251322"></polygon>
+                <polygon id="Fill-122" fill-opacity="0.6" fill="#A3B1BF" transform="translate(72.981020, 263.670099) rotate(22.000000) translate(-72.981020, -263.670099) " points="72.9810197 265.286018 71.3647732 263.670099 72.9810197 262.054181 74.5972663 263.670099"></polygon>
+                <polygon id="Stroke-124" transform="translate(72.981020, 263.670099) rotate(22.000000) translate(-72.981020, -263.670099) " points="72.9810197 265.286018 71.3647732 263.670099 72.9810197 262.054181 74.5972663 263.670099"></polygon>
+                <polygon id="Fill-126" fill-opacity="0.6" fill="#A3B1BF" transform="translate(88.852907, 265.961362) rotate(22.000000) translate(-88.852907, -265.961362) " points="88.8529067 267.577281 87.2366602 265.961362 88.8529067 264.345443 90.4691533 265.961362"></polygon>
+                <polygon id="Stroke-128" transform="translate(88.852907, 265.961362) rotate(22.000000) translate(-88.852907, -265.961362) " points="88.8529067 267.577281 87.2366602 265.961362 88.8529067 264.345443 90.4691533 265.961362"></polygon>
+                <polygon id="Fill-130" fill-opacity="0.6" fill="#A3B1BF" transform="translate(90.304501, 269.380139) rotate(22.000000) translate(-90.304501, -269.380139) " points="90.3045009 270.996058 88.6882544 269.380139 90.3045009 267.764221 91.9207474 269.380139"></polygon>
+                <polygon id="Stroke-132" transform="translate(90.304501, 269.380139) rotate(22.000000) translate(-90.304501, -269.380139) " points="90.3045009 270.996058 88.6882544 269.380139 90.3045009 267.764221 91.9207474 269.380139"></polygon>
+                <polygon id="Fill-134" fill-opacity="0.6" fill="#A3B1BF" transform="translate(91.756130, 272.798999) rotate(22.000000) translate(-91.756130, -272.798999) " points="91.7561302 274.414918 90.1398837 272.798999 91.7561302 271.183081 93.3723767 272.798999"></polygon>
+                <polygon id="Stroke-136" transform="translate(91.756130, 272.798999) rotate(22.000000) translate(-91.756130, -272.798999) " points="91.7561302 274.414918 90.1398837 272.798999 91.7561302 271.183081 93.3723767 272.798999"></polygon>
+                <polygon id="Fill-138" fill-opacity="0.6" fill="#A3B1BF" transform="translate(93.207724, 276.217777) rotate(22.000000) translate(-93.207724, -276.217777) " points="93.2077244 277.833695 91.5914778 276.217777 93.2077244 274.601858 94.8239709 276.217777"></polygon>
+                <polygon id="Stroke-140" transform="translate(93.207724, 276.217777) rotate(22.000000) translate(-93.207724, -276.217777) " points="93.2077244 277.833695 91.5914778 276.217777 93.2077244 274.601858 94.8239709 276.217777"></polygon>
+                <polygon id="Fill-142" fill-opacity="0.6" fill="#A3B1BF" transform="translate(85.696821, 267.300663) rotate(22.000000) translate(-85.696821, -267.300663) " points="85.6968214 268.916582 84.0805749 267.300663 85.6968214 265.684744 87.313068 267.300663"></polygon>
+                <polygon id="Stroke-144" transform="translate(85.696821, 267.300663) rotate(22.000000) translate(-85.696821, -267.300663) " points="85.6968214 268.916582 84.0805749 267.300663 85.6968214 265.684744 87.313068 267.300663"></polygon>
+                <polygon id="Fill-146" fill-opacity="0.6" fill="#A3B1BF" transform="translate(87.148416, 270.719440) rotate(22.000000) translate(-87.148416, -270.719440) " points="87.1484156 272.335359 85.5321691 270.71944 87.1484156 269.103521 88.7646621 270.71944"></polygon>
+                <polygon id="Stroke-148" transform="translate(87.148416, 270.719440) rotate(22.000000) translate(-87.148416, -270.719440) " points="87.1484156 272.335359 85.5321691 270.71944 87.1484156 269.103521 88.7646621 270.71944"></polygon>
+                <polygon id="Fill-150" fill-opacity="0.6" fill="#A3B1BF" transform="translate(88.599986, 274.138276) rotate(22.000000) translate(-88.599986, -274.138276) " points="88.599986 275.754195 86.9837394 274.138276 88.599986 272.522358 90.2162325 274.138276"></polygon>
+                <polygon id="Stroke-152" transform="translate(88.599986, 274.138276) rotate(22.000000) translate(-88.599986, -274.138276) " points="88.599986 275.754195 86.9837394 274.138276 88.599986 272.522358 90.2162325 274.138276"></polygon>
+                <polygon id="Fill-154" fill-opacity="0.6" fill="#A3B1BF" transform="translate(90.051639, 277.557078) rotate(22.000000) translate(-90.051639, -277.557078) " points="90.0516391 279.172996 88.4353925 277.557078 90.0516391 275.941159 91.6678856 277.557078"></polygon>
+                <polygon id="Stroke-156" transform="translate(90.051639, 277.557078) rotate(22.000000) translate(-90.051639, -277.557078) " points="90.0516391 279.172996 88.4353925 277.557078 90.0516391 275.941159 91.6678856 277.557078"></polygon>
+                <polygon id="Fill-158" fill-opacity="0.6" fill="#A3B1BF" transform="translate(82.540736, 268.639964) rotate(22.000000) translate(-82.540736, -268.639964) " points="82.5407361 270.255882 80.9244896 268.639964 82.5407361 267.024045 84.1569826 268.639964"></polygon>
+                <polygon id="Stroke-160" transform="translate(82.540736, 268.639964) rotate(22.000000) translate(-82.540736, -268.639964) " points="82.5407361 270.255882 80.9244896 268.639964 82.5407361 267.024045 84.1569826 268.639964"></polygon>
+                <polygon id="Fill-162" fill-opacity="0.6" fill="#A3B1BF" transform="translate(83.992306, 272.058800) rotate(22.000000) translate(-83.992306, -272.058800) " points="83.9923065 273.674719 82.3760599 272.0588 83.9923065 270.442881 85.608553 272.0588"></polygon>
+                <polygon id="Stroke-164" transform="translate(83.992306, 272.058800) rotate(22.000000) translate(-83.992306, -272.058800) " points="83.9923065 273.674719 82.3760599 272.0588 83.9923065 270.442881 85.608553 272.0588"></polygon>
+                <polygon id="Fill-166" fill-opacity="0.6" fill="#A3B1BF" transform="translate(85.443901, 275.477577) rotate(22.000000) translate(-85.443901, -275.477577) " points="85.4439007 277.093496 83.8276541 275.477577 85.4439007 273.861659 87.0601472 275.477577"></polygon>
+                <polygon id="Stroke-168" transform="translate(85.443901, 275.477577) rotate(22.000000) translate(-85.443901, -275.477577) " points="85.4439007 277.093496 83.8276541 275.477577 85.4439007 273.861659 87.0601472 275.477577"></polygon>
+                <polygon id="Fill-170" fill-opacity="0.6" fill="#A3B1BF" transform="translate(86.895554, 278.896378) rotate(22.000000) translate(-86.895554, -278.896378) " points="86.8955537 280.512297 85.2793072 278.896378 86.8955537 277.28046 88.5118003 278.896378"></polygon>
+                <polygon id="Stroke-172" transform="translate(86.895554, 278.896378) rotate(22.000000) translate(-86.895554, -278.896378) " points="86.8955537 280.512297 85.2793072 278.896378 86.8955537 277.28046 88.5118003 278.896378"></polygon>
+                <polygon id="Fill-174" fill-opacity="0.6" fill="#A3B1BF" transform="translate(79.384651, 269.979265) rotate(22.000000) translate(-79.384651, -269.979265) " points="79.3846508 271.595183 77.7684043 269.979265 79.3846508 268.363346 81.0008973 269.979265"></polygon>
+                <polygon id="Stroke-176" transform="translate(79.384651, 269.979265) rotate(22.000000) translate(-79.384651, -269.979265) " points="79.3846508 271.595183 77.7684043 269.979265 79.3846508 268.363346 81.0008973 269.979265"></polygon>
+                <polygon id="Fill-178" fill-opacity="0.6" fill="#A3B1BF" transform="translate(80.836221, 273.398101) rotate(22.000000) translate(-80.836221, -273.398101) " points="80.8362212 275.01402 79.2199746 273.398101 80.8362212 271.782182 82.4524677 273.398101"></polygon>
+                <polygon id="Stroke-180" transform="translate(80.836221, 273.398101) rotate(22.000000) translate(-80.836221, -273.398101) " points="80.8362212 275.01402 79.2199746 273.398101 80.8362212 271.782182 82.4524677 273.398101"></polygon>
+                <polygon id="Fill-182" fill-opacity="0.6" fill="#A3B1BF" transform="translate(82.287815, 276.816878) rotate(22.000000) translate(-82.287815, -276.816878) " points="82.2878153 278.432797 80.6715688 276.816878 82.2878153 275.20096 83.9040619 276.816878"></polygon>
+                <polygon id="Stroke-184" transform="translate(82.287815, 276.816878) rotate(22.000000) translate(-82.287815, -276.816878) " points="82.2878153 278.432797 80.6715688 276.816878 82.2878153 275.20096 83.9040619 276.816878"></polygon>
+                <polygon id="Fill-186" fill-opacity="0.6" fill="#A3B1BF" transform="translate(83.739445, 280.235738) rotate(22.000000) translate(-83.739445, -280.235738) " points="83.7394446 281.851657 82.1231981 280.235738 83.7394446 278.61982 85.3556912 280.235738"></polygon>
+                <polygon id="Stroke-188" transform="translate(83.739445, 280.235738) rotate(22.000000) translate(-83.739445, -280.235738) " points="83.7394446 281.851657 82.1231981 280.235738 83.7394446 278.61982 85.3556912 280.235738"></polygon>
+                <polygon id="Fill-190" fill-opacity="0.6" fill="#A3B1BF" transform="translate(76.228483, 271.318601) rotate(22.000000) translate(-76.228483, -271.318601) " points="76.2284828 272.934519 74.6122362 271.318601 76.2284828 269.702682 77.8447293 271.318601"></polygon>
+                <polygon id="Stroke-192" transform="translate(76.228483, 271.318601) rotate(22.000000) translate(-76.228483, -271.318601) " points="76.2284828 272.934519 74.6122362 271.318601 76.2284828 269.702682 77.8447293 271.318601"></polygon>
+                <polygon id="Fill-194" fill-opacity="0.6" fill="#A3B1BF" transform="translate(77.680136, 274.737402) rotate(22.000000) translate(-77.680136, -274.737402) " points="77.6801358 276.353321 76.0638893 274.737402 77.6801358 273.121483 79.2963824 274.737402"></polygon>
+                <polygon id="Stroke-196" transform="translate(77.680136, 274.737402) rotate(22.000000) translate(-77.680136, -274.737402) " points="77.6801358 276.353321 76.0638893 274.737402 77.6801358 273.121483 79.2963824 274.737402"></polygon>
+                <polygon id="Fill-198" fill-opacity="0.6" fill="#A3B1BF" transform="translate(79.131730, 278.156179) rotate(22.000000) translate(-79.131730, -278.156179) " points="79.13173 279.772098 77.5154835 278.156179 79.13173 276.540261 80.7479765 278.156179"></polygon>
+                <polygon id="Stroke-200" transform="translate(79.131730, 278.156179) rotate(22.000000) translate(-79.131730, -278.156179) " points="79.13173 279.772098 77.5154835 278.156179 79.13173 276.540261 80.7479765 278.156179"></polygon>
+                <polygon id="Fill-202" fill-opacity="0.6" fill="#A3B1BF" transform="translate(80.583359, 281.575039) rotate(22.000000) translate(-80.583359, -281.575039) " points="80.5833593 283.190958 78.9671128 281.575039 80.5833593 279.959121 82.1996058 281.575039"></polygon>
+                <polygon id="Stroke-204" transform="translate(80.583359, 281.575039) rotate(22.000000) translate(-80.583359, -281.575039) " points="80.5833593 283.190958 78.9671128 281.575039 80.5833593 279.959121 82.1996058 281.575039"></polygon>
+                <polygon id="Fill-206" fill-opacity="0.6" fill="#A3B1BF" transform="translate(96.455246, 283.866302) rotate(22.000000) translate(-96.455246, -283.866302) " points="96.4552463 285.48222 94.8389998 283.866302 96.4552463 282.250383 98.0714929 283.866302"></polygon>
+                <polygon id="Stroke-208" transform="translate(96.455246, 283.866302) rotate(22.000000) translate(-96.455246, -283.866302) " points="96.4552463 285.48222 94.8389998 283.866302 96.4552463 282.250383 98.0714929 283.866302"></polygon>
+                <polygon id="Fill-210" fill-opacity="0.6" fill="#A3B1BF" transform="translate(97.906840, 287.285079) rotate(22.000000) translate(-97.906840, -287.285079) " points="97.9068405 288.900998 96.290594 287.285079 97.9068405 285.66916 99.523087 287.285079"></polygon>
+                <polygon id="Stroke-212" transform="translate(97.906840, 287.285079) rotate(22.000000) translate(-97.906840, -287.285079) " points="97.9068405 288.900998 96.290594 287.285079 97.9068405 285.66916 99.523087 287.285079"></polygon>
+                <polygon id="Fill-214" fill-opacity="0.6" fill="#A3B1BF" transform="translate(99.358435, 290.703856) rotate(22.000000) translate(-99.358435, -290.703856) " points="99.3584347 292.319775 97.7421881 290.703856 99.3584347 289.087938 100.974681 290.703856"></polygon>
+                <polygon id="Stroke-216" transform="translate(99.358435, 290.703856) rotate(22.000000) translate(-99.358435, -290.703856) " points="99.3584347 292.319775 97.7421881 290.703856 99.3584347 289.087938 100.974681 290.703856"></polygon>
+                <polygon id="Fill-218" fill-opacity="0.6" fill="#A3B1BF" transform="translate(100.810064, 294.122716) rotate(22.000000) translate(-100.810064, -294.122716) " points="100.810064 295.738635 99.1938174 294.122716 100.810064 292.506798 102.42631 294.122716"></polygon>
+                <polygon id="Stroke-220" transform="translate(100.810064, 294.122716) rotate(22.000000) translate(-100.810064, -294.122716) " points="100.810064 295.738635 99.1938174 294.122716 100.810064 292.506798 102.42631 294.122716"></polygon>
+                <polygon id="Fill-222" fill-opacity="0.6" fill="#A3B1BF" transform="translate(93.299102, 285.205579) rotate(22.000000) translate(-93.299102, -285.205579) " points="93.2991021 286.821497 91.6828556 285.205579 93.2991021 283.58966 94.9153486 285.205579"></polygon>
+                <polygon id="Stroke-224" transform="translate(93.299102, 285.205579) rotate(22.000000) translate(-93.299102, -285.205579) " points="93.2991021 286.821497 91.6828556 285.205579 93.2991021 283.58966 94.9153486 285.205579"></polygon>
+                <polygon id="Fill-226" fill-opacity="0.6" fill="#A3B1BF" transform="translate(94.750755, 288.624380) rotate(22.000000) translate(-94.750755, -288.624380) " points="94.7507552 290.240299 93.1345086 288.62438 94.7507552 287.008461 96.3670017 288.62438"></polygon>
+                <polygon id="Stroke-228" transform="translate(94.750755, 288.624380) rotate(22.000000) translate(-94.750755, -288.624380) " points="94.7507552 290.240299 93.1345086 288.62438 94.7507552 287.008461 96.3670017 288.62438"></polygon>
+                <polygon id="Fill-230" fill-opacity="0.6" fill="#A3B1BF" transform="translate(96.202326, 292.043216) rotate(22.000000) translate(-96.202326, -292.043216) " points="96.2023255 293.659135 94.586079 292.043216 96.2023255 290.427297 97.8185721 292.043216"></polygon>
+                <polygon id="Stroke-232" transform="translate(96.202326, 292.043216) rotate(22.000000) translate(-96.202326, -292.043216) " points="96.2023255 293.659135 94.586079 292.043216 96.2023255 290.427297 97.8185721 292.043216"></polygon>
+                <polygon id="Fill-234" fill-opacity="0.6" fill="#A3B1BF" transform="translate(97.653979, 295.462017) rotate(22.000000) translate(-97.653979, -295.462017) " points="97.6539786 297.077936 96.0377321 295.462017 97.6539786 293.846099 99.2702252 295.462017"></polygon>
+                <polygon id="Stroke-236" transform="translate(97.653979, 295.462017) rotate(22.000000) translate(-97.653979, -295.462017) " points="97.6539786 297.077936 96.0377321 295.462017 97.6539786 293.846099 99.2702252 295.462017"></polygon>
+                <polygon id="Fill-238" fill-opacity="0.6" fill="#A3B1BF" transform="translate(90.143017, 286.544880) rotate(22.000000) translate(-90.143017, -286.544880) " points="90.1430168 288.160798 88.5267702 286.54488 90.1430168 284.928961 91.7592633 286.54488"></polygon>
+                <polygon id="Stroke-240" transform="translate(90.143017, 286.544880) rotate(22.000000) translate(-90.143017, -286.544880) " points="90.1430168 288.160798 88.5267702 286.54488 90.1430168 284.928961 91.7592633 286.54488"></polygon>
+                <polygon id="Fill-242" fill-opacity="0.6" fill="#A3B1BF" transform="translate(91.594670, 289.963681) rotate(22.000000) translate(-91.594670, -289.963681) " points="91.5946698 291.5796 89.9784233 289.963681 91.5946698 288.347762 93.2109164 289.963681"></polygon>
+                <polygon id="Stroke-244" transform="translate(91.594670, 289.963681) rotate(22.000000) translate(-91.594670, -289.963681) " points="91.5946698 291.5796 89.9784233 289.963681 91.5946698 288.347762 93.2109164 289.963681"></polygon>
+                <polygon id="Fill-246" fill-opacity="0.6" fill="#A3B1BF" transform="translate(93.046240, 293.382517) rotate(22.000000) translate(-93.046240, -293.382517) " points="93.0462402 294.998436 91.4299937 293.382517 93.0462402 291.766598 94.6624868 293.382517"></polygon>
+                <polygon id="Stroke-248" transform="translate(93.046240, 293.382517) rotate(22.000000) translate(-93.046240, -293.382517) " points="93.0462402 294.998436 91.4299937 293.382517 93.0462402 291.766598 94.6624868 293.382517"></polygon>
+                <polygon id="Fill-250" fill-opacity="0.6" fill="#A3B1BF" transform="translate(94.497893, 296.801318) rotate(22.000000) translate(-94.497893, -296.801318) " points="94.4978933 298.417237 92.8816468 296.801318 94.4978933 295.1854 96.1141398 296.801318"></polygon>
+                <polygon id="Stroke-252" transform="translate(94.497893, 296.801318) rotate(22.000000) translate(-94.497893, -296.801318) " points="94.4978933 298.417237 92.8816468 296.801318 94.4978933 295.1854 96.1141398 296.801318"></polygon>
+                <polygon id="Fill-254" fill-opacity="0.6" fill="#A3B1BF" transform="translate(86.986931, 287.884181) rotate(22.000000) translate(-86.986931, -287.884181) " points="86.9869315 289.500099 85.3706849 287.884181 86.9869315 286.268262 88.603178 287.884181"></polygon>
+                <polygon id="Stroke-256" transform="translate(86.986931, 287.884181) rotate(22.000000) translate(-86.986931, -287.884181) " points="86.9869315 289.500099 85.3706849 287.884181 86.9869315 286.268262 88.603178 287.884181"></polygon>
+                <polygon id="Fill-258" fill-opacity="0.6" fill="#A3B1BF" transform="translate(88.438585, 291.302982) rotate(22.000000) translate(-88.438585, -291.302982) " points="88.4385845 292.9189 86.822338 291.302982 88.4385845 289.687063 90.0548311 291.302982"></polygon>
+                <polygon id="Stroke-260" transform="translate(88.438585, 291.302982) rotate(22.000000) translate(-88.438585, -291.302982) " points="88.4385845 292.9189 86.822338 291.302982 88.4385845 289.687063 90.0548311 291.302982"></polygon>
+                <polygon id="Fill-262" fill-opacity="0.6" fill="#A3B1BF" transform="translate(89.890155, 294.721818) rotate(22.000000) translate(-89.890155, -294.721818) " points="89.8901549 296.337737 88.2739084 294.721818 89.8901549 293.105899 91.5064014 294.721818"></polygon>
+                <polygon id="Stroke-264" transform="translate(89.890155, 294.721818) rotate(22.000000) translate(-89.890155, -294.721818) " points="89.8901549 296.337737 88.2739084 294.721818 89.8901549 293.105899 91.5064014 294.721818"></polygon>
+                <polygon id="Fill-266" fill-opacity="0.6" fill="#A3B1BF" transform="translate(91.341749, 298.140595) rotate(22.000000) translate(-91.341749, -298.140595) " points="91.3417491 299.756514 89.7255025 298.140595 91.3417491 296.524677 92.9579956 298.140595"></polygon>
+                <polygon id="Stroke-268" transform="translate(91.341749, 298.140595) rotate(22.000000) translate(-91.341749, -298.140595) " points="91.3417491 299.756514 89.7255025 298.140595 91.3417491 296.524677 92.9579956 298.140595"></polygon>
+                <polygon id="Fill-270" fill-opacity="0.6" fill="#A3B1BF" transform="translate(83.830846, 289.223482) rotate(22.000000) translate(-83.830846, -289.223482) " points="83.8308461 290.8394 82.2145996 289.223482 83.8308461 287.607563 85.4470927 289.223482"></polygon>
+                <polygon id="Stroke-272" transform="translate(83.830846, 289.223482) rotate(22.000000) translate(-83.830846, -289.223482) " points="82.2145996 289.223482 83.8308461 287.607563 85.4470927 289.223482 83.8308461 290.8394"></polygon>
+                <polygon id="Fill-274" fill-opacity="0.6" fill="#A3B1BF" transform="translate(85.282417, 292.642318) rotate(22.000000) translate(-85.282417, -292.642318) " points="85.2824165 294.258236 83.66617 292.642318 85.2824165 291.026399 86.898663 292.642318"></polygon>
+                <polygon id="Stroke-276" transform="translate(85.282417, 292.642318) rotate(22.000000) translate(-85.282417, -292.642318) " points="85.2824165 294.258236 83.66617 292.642318 85.2824165 291.026399 86.898663 292.642318"></polygon>
+                <polygon id="Fill-278" fill-opacity="0.6" fill="#A3B1BF" transform="translate(86.734070, 296.061119) rotate(22.000000) translate(-86.734070, -296.061119) " points="86.7340696 297.677038 85.1178231 296.061119 86.7340696 294.4452 88.3503161 296.061119"></polygon>
+                <polygon id="Stroke-280" transform="translate(86.734070, 296.061119) rotate(22.000000) translate(-86.734070, -296.061119) " points="86.7340696 297.677038 85.1178231 296.061119 86.7340696 294.4452 88.3503161 296.061119"></polygon>
+                <polygon id="Fill-282" fill-opacity="0.6" fill="#A3B1BF" transform="translate(88.185664, 299.479896) rotate(22.000000) translate(-88.185664, -299.479896) " points="88.1856638 301.095815 86.5694172 299.479896 88.1856638 297.863978 89.8019103 299.479896"></polygon>
+                <polygon id="Stroke-284" transform="translate(88.185664, 299.479896) rotate(22.000000) translate(-88.185664, -299.479896) " points="88.1856638 301.095815 86.5694172 299.479896 88.1856638 297.863978 89.8019103 299.479896"></polygon>
+                <polygon id="Fill-286" transform="translate(37.779995, 163.402514) rotate(22.000000) translate(-37.779995, -163.402514) " points="51.9961666 192.018058 66.401345 177.615802 23.5644587 134.78697 9.15864501 149.189862"></polygon>
+                <polygon id="Fill-290" transform="translate(50.400318, 195.682118) rotate(22.000000) translate(-50.400318, -195.682118) " points="54.1737837 198.070743 48.0112085 191.909418 46.6268527 193.293493 52.7894279 199.454818"></polygon>
+                <polygon id="Stroke-292" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(50.400318, 195.682118) rotate(22.000000) translate(-50.400318, -195.682118) " points="54.1737837 198.070743 48.0112085 191.909418 46.6268527 193.293493 52.7894279 199.454818"></polygon>
+                <polygon id="Fill-294" fill-opacity="0.8" fill="#A3B1BF" transform="translate(52.603532, 200.871447) rotate(22.000000) translate(-52.603532, -200.871447) " points="52.712807 203.746308 55.4789773 200.980699 52.4942579 197.996585 49.7280876 200.762195"></polygon>
+                <polygon id="Stroke-296" stroke="#A3B1BF" stroke-width="1.62" fill="#FFFFFF" stroke-linejoin="round" transform="translate(52.603532, 200.871447) rotate(22.000000) translate(-52.603532, -200.871447) " points="52.712807 203.746308 55.4789773 200.980699 52.4942579 197.996585 49.7280876 200.762195"></polygon>
+                <polygon id="Fill-298" fill-opacity="0.8" fill="#A3B1BF" transform="translate(53.983257, 183.836778) rotate(22.000000) translate(-53.983257, -183.836778) " points="52.3670108 183.836778 53.9832574 185.452697 55.5995039 183.836778 53.9832574 182.22086"></polygon>
+                <polygon id="Stroke-300" transform="translate(53.983257, 183.836778) rotate(22.000000) translate(-53.983257, -183.836778) " points="52.3670108 183.836778 53.9832574 185.452697 55.5995039 183.836778 53.9832574 182.22086"></polygon>
+                <polygon id="Fill-302" fill-opacity="0.8" fill="#A3B1BF" transform="translate(52.531663, 180.418001) rotate(22.000000) translate(-52.531663, -180.418001) " points="50.9154167 180.418001 52.5316632 182.03392 54.1479097 180.418001 52.5316632 178.802082"></polygon>
+                <polygon id="Stroke-304" transform="translate(52.531663, 180.418001) rotate(22.000000) translate(-52.531663, -180.418001) " points="50.9154167 180.418001 52.5316632 182.03392 54.1479097 180.418001 52.5316632 178.802082"></polygon>
+                <polygon id="Fill-306" fill-opacity="0.8" fill="#A3B1BF" transform="translate(51.080034, 176.999141) rotate(22.000000) translate(-51.080034, -176.999141) " points="49.4637874 176.999141 51.0800339 178.61506 52.6962805 176.999141 51.0800339 175.383222"></polygon>
+                <polygon id="Stroke-308" transform="translate(51.080034, 176.999141) rotate(22.000000) translate(-51.080034, -176.999141) " points="49.4637874 176.999141 51.0800339 178.61506 52.6962805 176.999141 51.0800339 175.383222"></polygon>
+                <polygon id="Fill-310" fill-opacity="0.8" fill="#A3B1BF" transform="translate(49.628440, 173.580364) rotate(22.000000) translate(-49.628440, -173.580364) " points="48.0121932 173.580364 49.6284397 175.196282 51.2446863 173.580364 49.6284397 171.964445"></polygon>
+                <polygon id="Stroke-312" transform="translate(49.628440, 173.580364) rotate(22.000000) translate(-49.628440, -173.580364) " points="48.0121932 173.580364 49.6284397 175.196282 51.2446863 173.580364 49.6284397 171.964445"></polygon>
+                <polygon id="Fill-314" fill-opacity="0.8" fill="#A3B1BF" transform="translate(50.827172, 185.176079) rotate(22.000000) translate(-50.827172, -185.176079) " points="49.2109255 185.176079 50.8271721 186.791998 52.4434186 185.176079 50.8271721 183.560161"></polygon>
+                <polygon id="Stroke-316" transform="translate(50.827172, 185.176079) rotate(22.000000) translate(-50.827172, -185.176079) " points="49.2109255 185.176079 50.8271721 186.791998 52.4434186 185.176079 50.8271721 183.560161"></polygon>
+                <polygon id="Fill-318" fill-opacity="0.8" fill="#A3B1BF" transform="translate(49.375578, 181.757302) rotate(22.000000) translate(-49.375578, -181.757302) " points="47.7593313 181.757302 49.3755779 183.373221 50.9918244 181.757302 49.3755779 180.141383"></polygon>
+                <polygon id="Stroke-320" transform="translate(49.375578, 181.757302) rotate(22.000000) translate(-49.375578, -181.757302) " points="47.7593313 181.757302 49.3755779 183.373221 50.9918244 181.757302 49.3755779 180.141383"></polygon>
+                <polygon id="Fill-322" fill-opacity="0.8" fill="#A3B1BF" transform="translate(47.923949, 178.338442) rotate(22.000000) translate(-47.923949, -178.338442) " points="46.3077021 178.338442 47.9239486 179.954361 49.5401951 178.338442 47.9239486 176.722523"></polygon>
+                <polygon id="Stroke-324" transform="translate(47.923949, 178.338442) rotate(22.000000) translate(-47.923949, -178.338442) " points="46.3077021 178.338442 47.9239486 179.954361 49.5401951 178.338442 47.9239486 176.722523"></polygon>
+                <polygon id="Fill-326" fill-opacity="0.8" fill="#A3B1BF" transform="translate(46.472354, 174.919665) rotate(22.000000) translate(-46.472354, -174.919665) " points="44.8561079 174.919665 46.4723544 176.535583 48.088601 174.919665 46.4723544 173.303746"></polygon>
+                <polygon id="Stroke-328" transform="translate(46.472354, 174.919665) rotate(22.000000) translate(-46.472354, -174.919665) " points="44.8561079 174.919665 46.4723544 176.535583 48.088601 174.919665 46.4723544 173.303746"></polygon>
+                <polygon id="Fill-330" fill-opacity="0.8" fill="#A3B1BF" transform="translate(47.671087, 186.515380) rotate(22.000000) translate(-47.671087, -186.515380) " points="46.0548402 186.51538 47.6710867 188.131299 49.2873333 186.51538 47.6710867 184.899461"></polygon>
+                <polygon id="Stroke-332" transform="translate(47.671087, 186.515380) rotate(22.000000) translate(-47.671087, -186.515380) " points="46.0548402 186.51538 47.6710867 188.131299 49.2873333 186.51538 47.6710867 184.899461"></polygon>
+                <polygon id="Fill-334" fill-opacity="0.8" fill="#A3B1BF" transform="translate(46.219493, 183.096603) rotate(22.000000) translate(-46.219493, -183.096603) " points="44.603246 183.096603 46.2194926 184.712521 47.8357391 183.096603 46.2194926 181.480684"></polygon>
+                <polygon id="Stroke-336" transform="translate(46.219493, 183.096603) rotate(22.000000) translate(-46.219493, -183.096603) " points="44.603246 183.096603 46.2194926 184.712521 47.8357391 183.096603 46.2194926 181.480684"></polygon>
+                <polygon id="Fill-338" fill-opacity="0.8" fill="#A3B1BF" transform="translate(44.767839, 179.677802) rotate(22.000000) translate(-44.767839, -179.677802) " points="43.1515929 179.677802 44.7678395 181.29372 46.384086 179.677802 44.7678395 178.061883"></polygon>
+                <polygon id="Stroke-340" transform="translate(44.767839, 179.677802) rotate(22.000000) translate(-44.767839, -179.677802) " points="43.1515929 179.677802 44.7678395 181.29372 46.384086 179.677802 44.7678395 178.061883"></polygon>
+                <polygon id="Fill-342" fill-opacity="0.8" fill="#A3B1BF" transform="translate(43.316269, 176.258965) rotate(22.000000) translate(-43.316269, -176.258965) " points="41.7000226 176.258965 43.3162691 177.874884 44.9325156 176.258965 43.3162691 174.643047"></polygon>
+                <polygon id="Stroke-344" transform="translate(43.316269, 176.258965) rotate(22.000000) translate(-43.316269, -176.258965) " points="41.7000226 176.258965 43.3162691 177.874884 44.9325156 176.258965 43.3162691 174.643047"></polygon>
+                <polygon id="Fill-346" fill-opacity="0.8" fill="#A3B1BF" transform="translate(44.514978, 187.854740) rotate(22.000000) translate(-44.514978, -187.854740) " points="42.8987311 187.85474 44.5149776 189.470659 46.1312242 187.85474 44.5149776 186.238821"></polygon>
+                <polygon id="Stroke-348" transform="translate(44.514978, 187.854740) rotate(22.000000) translate(-44.514978, -187.854740) " points="42.8987311 187.85474 44.5149776 189.470659 46.1312242 187.85474 44.5149776 186.238821"></polygon>
+                <polygon id="Fill-350" fill-opacity="0.8" fill="#A3B1BF" transform="translate(43.063348, 184.435880) rotate(22.000000) translate(-43.063348, -184.435880) " points="41.4471018 184.43588 43.0633483 186.051799 44.6795949 184.43588 43.0633483 182.819961"></polygon>
+                <polygon id="Stroke-352" transform="translate(43.063348, 184.435880) rotate(22.000000) translate(-43.063348, -184.435880) " points="41.4471018 184.43588 43.0633483 186.051799 44.6795949 184.43588 43.0633483 182.819961"></polygon>
+                <polygon id="Fill-354" fill-opacity="0.8" fill="#A3B1BF" transform="translate(41.611754, 181.017103) rotate(22.000000) translate(-41.611754, -181.017103) " points="39.9955076 181.017103 41.6117542 182.633021 43.2280007 181.017103 41.6117542 179.401184"></polygon>
+                <polygon id="Stroke-356" transform="translate(41.611754, 181.017103) rotate(22.000000) translate(-41.611754, -181.017103) " points="39.9955076 181.017103 41.6117542 182.633021 43.2280007 181.017103 41.6117542 179.401184"></polygon>
+                <polygon id="Fill-358" fill-opacity="0.8" fill="#A3B1BF" transform="translate(40.160184, 177.598266) rotate(22.000000) translate(-40.160184, -177.598266) " points="38.5439373 177.598266 40.1601838 179.214185 41.7764303 177.598266 40.1601838 175.982348"></polygon>
+                <polygon id="Stroke-360" transform="translate(40.160184, 177.598266) rotate(22.000000) translate(-40.160184, -177.598266) " points="38.5439373 177.598266 40.1601838 179.214185 41.7764303 177.598266 40.1601838 175.982348"></polygon>
+                <polygon id="Fill-362" fill-opacity="0.8" fill="#A3B1BF" transform="translate(41.358892, 189.194041) rotate(22.000000) translate(-41.358892, -189.194041) " points="39.7426458 189.194041 41.3588923 190.80996 42.9751388 189.194041 41.3588923 187.578122"></polygon>
+                <polygon id="Stroke-364" transform="translate(41.358892, 189.194041) rotate(22.000000) translate(-41.358892, -189.194041) " points="39.7426458 189.194041 41.3588923 190.80996 42.9751388 189.194041 41.3588923 187.578122"></polygon>
+                <polygon id="Fill-366" fill-opacity="0.8" fill="#A3B1BF" transform="translate(39.907263, 185.775181) rotate(22.000000) translate(-39.907263, -185.775181) " points="38.2910165 185.775181 39.907263 187.3911 41.5235095 185.775181 39.907263 184.159262"></polygon>
+                <polygon id="Stroke-368" transform="translate(39.907263, 185.775181) rotate(22.000000) translate(-39.907263, -185.775181) " points="38.2910165 185.775181 39.907263 187.3911 41.5235095 185.775181 39.907263 184.159262"></polygon>
+                <polygon id="Fill-370" fill-opacity="0.8" fill="#A3B1BF" transform="translate(38.455669, 182.356404) rotate(22.000000) translate(-38.455669, -182.356404) " points="36.8394223 182.356404 38.4556688 183.972322 40.0719154 182.356404 38.4556688 180.740485"></polygon>
+                <polygon id="Stroke-372" transform="translate(38.455669, 182.356404) rotate(22.000000) translate(-38.455669, -182.356404) " points="36.8394223 182.356404 38.4556688 183.972322 40.0719154 182.356404 38.4556688 180.740485"></polygon>
+                <polygon id="Fill-374" fill-opacity="0.8" fill="#A3B1BF" transform="translate(37.004016, 178.937602) rotate(22.000000) translate(-37.004016, -178.937602) " points="35.3877692 178.937602 37.0040158 180.553521 38.6202623 178.937602 37.0040158 177.321684"></polygon>
+                <polygon id="Stroke-376" transform="translate(37.004016, 178.937602) rotate(22.000000) translate(-37.004016, -178.937602) " points="35.3877692 178.937602 37.0040158 180.553521 38.6202623 178.937602 37.0040158 177.321684"></polygon>
+                <polygon id="Fill-378" fill-opacity="0.8" fill="#A3B1BF" transform="translate(46.380894, 165.931897) rotate(22.000000) translate(-46.380894, -165.931897) " points="44.7646475 165.931897 46.380894 167.547816 47.9971405 165.931897 46.380894 164.315979"></polygon>
+                <polygon id="Stroke-380" transform="translate(46.380894, 165.931897) rotate(22.000000) translate(-46.380894, -165.931897) " points="44.7646475 165.931897 46.380894 167.547816 47.9971405 165.931897 46.380894 164.315979"></polygon>
+                <polygon id="Fill-382" fill-opacity="0.8" fill="#A3B1BF" transform="translate(44.929324, 162.513061) rotate(22.000000) translate(-44.929324, -162.513061) " points="43.3130771 162.513061 44.9293236 164.12898 46.5455702 162.513061 44.9293236 160.897143"></polygon>
+                <polygon id="Stroke-384" transform="translate(44.929324, 162.513061) rotate(22.000000) translate(-44.929324, -162.513061) " points="43.3130771 162.513061 44.9293236 164.12898 46.5455702 162.513061 44.9293236 160.897143"></polygon>
+                <polygon id="Fill-386" fill-opacity="0.8" fill="#A3B1BF" transform="translate(43.477729, 159.094284) rotate(22.000000) translate(-43.477729, -159.094284) " points="41.8614829 159.094284 43.4777295 160.710203 45.093976 159.094284 43.4777295 157.478365"></polygon>
+                <polygon id="Stroke-388" transform="translate(43.477729, 159.094284) rotate(22.000000) translate(-43.477729, -159.094284) " points="41.8614829 159.094284 43.4777295 160.710203 45.093976 159.094284 43.4777295 157.478365"></polygon>
+                <polygon id="Fill-390" fill-opacity="0.8" fill="#A3B1BF" transform="translate(42.026100, 155.675424) rotate(22.000000) translate(-42.026100, -155.675424) " points="40.4098536 155.675424 42.0261002 157.291342 43.6423467 155.675424 42.0261002 154.059505"></polygon>
+                <polygon id="Stroke-392" transform="translate(42.026100, 155.675424) rotate(22.000000) translate(-42.026100, -155.675424) " points="40.4098536 155.675424 42.0261002 157.291342 43.6423467 155.675424 42.0261002 154.059505"></polygon>
+                <polygon id="Fill-394" fill-opacity="0.8" fill="#A3B1BF" transform="translate(43.224809, 167.271198) rotate(22.000000) translate(-43.224809, -167.271198) " points="41.6085622 167.271198 43.2248087 168.887117 44.8410552 167.271198 43.2248087 165.65528"></polygon>
+                <polygon id="Stroke-396" transform="translate(43.224809, 167.271198) rotate(22.000000) translate(-43.224809, -167.271198) " points="41.6085622 167.271198 43.2248087 168.887117 44.8410552 167.271198 43.2248087 165.65528"></polygon>
+                <polygon id="Fill-398" fill-opacity="0.8" fill="#A3B1BF" transform="translate(41.773238, 163.852362) rotate(22.000000) translate(-41.773238, -163.852362) " points="40.1569918 163.852362 41.7732383 165.468281 43.3894848 163.852362 41.7732383 162.236443"></polygon>
+                <polygon id="Stroke-400" transform="translate(41.773238, 163.852362) rotate(22.000000) translate(-41.773238, -163.852362) " points="40.1569918 163.852362 41.7732383 165.468281 43.3894848 163.852362 41.7732383 162.236443"></polygon>
+                <polygon id="Fill-402" fill-opacity="0.8" fill="#A3B1BF" transform="translate(40.321585, 160.433561) rotate(22.000000) translate(-40.321585, -160.433561) " points="38.7053387 160.433561 40.3215852 162.04948 41.9378318 160.433561 40.3215852 158.817642"></polygon>
+                <polygon id="Stroke-404" transform="translate(40.321585, 160.433561) rotate(22.000000) translate(-40.321585, -160.433561) " points="38.7053387 160.433561 40.3215852 162.04948 41.9378318 160.433561 40.3215852 158.817642"></polygon>
+                <polygon id="Fill-406" fill-opacity="0.8" fill="#A3B1BF" transform="translate(38.869991, 157.014784) rotate(22.000000) translate(-38.869991, -157.014784) " points="37.2537445 157.014784 38.8699911 158.630702 40.4862376 157.014784 38.8699911 155.398865"></polygon>
+                <polygon id="Stroke-408" transform="translate(38.869991, 157.014784) rotate(22.000000) translate(-38.869991, -157.014784) " points="37.2537445 157.014784 38.8699911 158.630702 40.4862376 157.014784 38.8699911 155.398865"></polygon>
+                <polygon id="Fill-410" fill-opacity="0.8" fill="#A3B1BF" transform="translate(40.068723, 168.610499) rotate(22.000000) translate(-40.068723, -168.610499) " points="38.4524768 168.610499 40.0687234 170.226418 41.6849699 168.610499 40.0687234 166.994581"></polygon>
+                <polygon id="Stroke-412" transform="translate(40.068723, 168.610499) rotate(22.000000) translate(-40.068723, -168.610499) " points="38.4524768 168.610499 40.0687234 170.226418 41.6849699 168.610499 40.0687234 166.994581"></polygon>
+                <polygon id="Fill-414" fill-opacity="0.8" fill="#A3B1BF" transform="translate(38.617129, 165.191722) rotate(22.000000) translate(-38.617129, -165.191722) " points="37.0008827 165.191722 38.6171292 166.807641 40.2333757 165.191722 38.6171292 163.575803"></polygon>
+                <polygon id="Stroke-416" transform="translate(38.617129, 165.191722) rotate(22.000000) translate(-38.617129, -165.191722) " points="37.0008827 165.191722 38.6171292 166.807641 40.2333757 165.191722 38.6171292 163.575803"></polygon>
+                <polygon id="Fill-418" fill-opacity="0.8" fill="#A3B1BF" transform="translate(37.165500, 161.772862) rotate(22.000000) translate(-37.165500, -161.772862) " points="35.5492534 161.772862 37.1654999 163.388781 38.7817464 161.772862 37.1654999 160.156943"></polygon>
+                <polygon id="Stroke-420" transform="translate(37.165500, 161.772862) rotate(22.000000) translate(-37.165500, -161.772862) " points="35.5492534 161.772862 37.1654999 163.388781 38.7817464 161.772862 37.1654999 160.156943"></polygon>
+                <polygon id="Fill-422" fill-opacity="0.8" fill="#A3B1BF" transform="translate(35.713906, 158.354085) rotate(22.000000) translate(-35.713906, -158.354085) " points="34.0976592 158.354085 35.7139057 159.970003 37.3301523 158.354085 35.7139057 156.738166"></polygon>
+                <polygon id="Stroke-424" transform="translate(35.713906, 158.354085) rotate(22.000000) translate(-35.713906, -158.354085) " points="34.0976592 158.354085 35.7139057 159.970003 37.3301523 158.354085 35.7139057 156.738166"></polygon>
+                <polygon id="Fill-426" fill-opacity="0.8" fill="#A3B1BF" transform="translate(36.912638, 169.949800) rotate(22.000000) translate(-36.912638, -169.949800) " points="35.2963915 169.9498 36.912638 171.565719 38.5288846 169.9498 36.912638 168.333882"></polygon>
+                <polygon id="Stroke-428" transform="translate(36.912638, 169.949800) rotate(22.000000) translate(-36.912638, -169.949800) " points="35.2963915 169.9498 36.912638 171.565719 38.5288846 169.9498 36.912638 168.333882"></polygon>
+                <polygon id="Fill-430" fill-opacity="0.8" fill="#A3B1BF" transform="translate(35.461068, 166.530964) rotate(22.000000) translate(-35.461068, -166.530964) " points="33.8448211 166.530964 35.4610677 168.146883 37.0773142 166.530964 35.4610677 164.915045"></polygon>
+                <polygon id="Stroke-432" transform="translate(35.461068, 166.530964) rotate(22.000000) translate(-35.461068, -166.530964) " points="33.8448211 166.530964 35.4610677 168.146883 37.0773142 166.530964 35.4610677 164.915045"></polygon>
+                <polygon id="Fill-434" fill-opacity="0.8" fill="#A3B1BF" transform="translate(34.009415, 163.112163) rotate(22.000000) translate(-34.009415, -163.112163) " points="32.3931681 163.112163 34.0094146 164.728081 35.6256611 163.112163 34.0094146 161.496244"></polygon>
+                <polygon id="Stroke-436" transform="translate(34.009415, 163.112163) rotate(22.000000) translate(-34.009415, -163.112163) " points="32.3931681 163.112163 34.0094146 164.728081 35.6256611 163.112163 34.0094146 161.496244"></polygon>
+                <polygon id="Fill-438" fill-opacity="0.8" fill="#A3B1BF" transform="translate(32.557820, 159.693385) rotate(22.000000) translate(-32.557820, -159.693385) " points="30.9415739 159.693385 32.5578204 161.309304 34.174067 159.693385 32.5578204 158.077467"></polygon>
+                <polygon id="Stroke-440" transform="translate(32.557820, 159.693385) rotate(22.000000) translate(-32.557820, -159.693385) " points="30.9415739 159.693385 32.5578204 161.309304 34.174067 159.693385 32.5578204 158.077467"></polygon>
+                <polygon id="Fill-442" fill-opacity="0.8" fill="#A3B1BF" transform="translate(33.756553, 171.289101) rotate(22.000000) translate(-33.756553, -171.289101) " points="32.1403062 171.289101 33.7565527 172.90502 35.3727993 171.289101 33.7565527 169.673182"></polygon>
+                <polygon id="Stroke-444" transform="translate(33.756553, 171.289101) rotate(22.000000) translate(-33.756553, -171.289101) " points="32.1403062 171.289101 33.7565527 172.90502 35.3727993 171.289101 33.7565527 169.673182"></polygon>
+                <polygon id="Fill-446" fill-opacity="0.8" fill="#A3B1BF" transform="translate(32.304959, 167.870324) rotate(22.000000) translate(-32.304959, -167.870324) " points="30.688712 167.870324 32.3049586 169.486242 33.9212051 167.870324 32.3049586 166.254405"></polygon>
+                <polygon id="Stroke-448" transform="translate(32.304959, 167.870324) rotate(22.000000) translate(-32.304959, -167.870324) " points="30.688712 167.870324 32.3049586 169.486242 33.9212051 167.870324 32.3049586 166.254405"></polygon>
+                <polygon id="Fill-450" fill-opacity="0.8" fill="#A3B1BF" transform="translate(30.853329, 164.451464) rotate(22.000000) translate(-30.853329, -164.451464) " points="29.2370827 164.451464 30.8533293 166.067382 32.4695758 164.451464 30.8533293 162.835545"></polygon>
+                <polygon id="Stroke-452" transform="translate(30.853329, 164.451464) rotate(22.000000) translate(-30.853329, -164.451464) " points="29.2370827 164.451464 30.8533293 166.067382 32.4695758 164.451464 30.8533293 162.835545"></polygon>
+                <polygon id="Fill-454" fill-opacity="0.8" fill="#A3B1BF" transform="translate(29.401735, 161.032686) rotate(22.000000) translate(-29.401735, -161.032686) " points="27.7854886 161.032686 29.4017351 162.648605 31.0179816 161.032686 29.4017351 159.416768"></polygon>
+                <polygon id="Stroke-456" transform="translate(29.401735, 161.032686) rotate(22.000000) translate(-29.401735, -161.032686) " points="27.7854886 161.032686 29.4017351 162.648605 31.0179816 161.032686 29.4017351 159.416768"></polygon>
+                <polygon id="Fill-458" fill-opacity="0.8" fill="#A3B1BF" transform="translate(38.778613, 148.026981) rotate(22.000000) translate(-38.778613, -148.026981) " points="37.1623668 148.026981 38.7786133 149.6429 40.3948599 148.026981 38.7786133 146.411063"></polygon>
+                <polygon id="Stroke-460" transform="translate(38.778613, 148.026981) rotate(22.000000) translate(-38.778613, -148.026981) " points="37.1623668 148.026981 38.7786133 149.6429 40.3948599 148.026981 38.7786133 146.411063"></polygon>
+                <polygon id="Fill-462" fill-opacity="0.8" fill="#A3B1BF" transform="translate(37.326984, 144.608121) rotate(22.000000) translate(-37.326984, -144.608121) " points="35.7107375 144.608121 37.3269841 146.22404 38.9432306 144.608121 37.3269841 142.992203"></polygon>
+                <polygon id="Stroke-464" transform="translate(37.326984, 144.608121) rotate(22.000000) translate(-37.326984, -144.608121) " points="35.7107375 144.608121 37.3269841 146.22404 38.9432306 144.608121 37.3269841 142.992203"></polygon>
+                <polygon id="Fill-466" fill-opacity="0.8" fill="#A3B1BF" transform="translate(35.875390, 141.189344) rotate(22.000000) translate(-35.875390, -141.189344) " points="34.2591433 141.189344 35.8753899 142.805263 37.4916364 141.189344 35.8753899 139.573425"></polygon>
+                <polygon id="Stroke-468" transform="translate(35.875390, 141.189344) rotate(22.000000) translate(-35.875390, -141.189344) " points="34.2591433 141.189344 35.8753899 142.805263 37.4916364 141.189344 35.8753899 139.573425"></polygon>
+                <polygon id="Fill-470" fill-opacity="0.8" fill="#A3B1BF" transform="translate(34.423796, 137.770567) rotate(22.000000) translate(-34.423796, -137.770567) " points="32.8075492 137.770567 34.4237957 139.386485 36.0400422 137.770567 34.4237957 136.154648"></polygon>
+                <polygon id="Stroke-472" fill="#B2BECA" transform="translate(34.423796, 137.770567) rotate(22.000000) translate(-34.423796, -137.770567) " points="34.4237957 139.386485 36.0400422 137.770567 34.4237957 136.154648 32.8075492 137.770567"></polygon>
+                <polygon id="Fill-474" fill-opacity="0.8" fill="#A3B1BF" transform="translate(35.622528, 149.366282) rotate(22.000000) translate(-35.622528, -149.366282) " points="34.0062815 149.366282 35.622528 150.982201 37.2387746 149.366282 35.622528 147.750364"></polygon>
+                <polygon id="Stroke-476" transform="translate(35.622528, 149.366282) rotate(22.000000) translate(-35.622528, -149.366282) " points="34.0062815 149.366282 35.622528 150.982201 37.2387746 149.366282 35.622528 147.750364"></polygon>
+                <polygon id="Fill-478" fill-opacity="0.8" fill="#A3B1BF" transform="translate(34.170875, 145.947481) rotate(22.000000) translate(-34.170875, -145.947481) " points="32.5546284 145.947481 34.1708749 147.5634 35.7871215 145.947481 34.1708749 144.331563"></polygon>
+                <polygon id="Stroke-480" transform="translate(34.170875, 145.947481) rotate(22.000000) translate(-34.170875, -145.947481) " points="32.5546284 145.947481 34.1708749 147.5634 35.7871215 145.947481 34.1708749 144.331563"></polygon>
+                <polygon id="Fill-482" fill-opacity="0.8" fill="#A3B1BF" transform="translate(32.719305, 142.528645) rotate(22.000000) translate(-32.719305, -142.528645) " points="31.103058 142.528645 32.7193046 144.144564 34.3355511 142.528645 32.7193046 140.912726"></polygon>
+                <polygon id="Stroke-484" transform="translate(32.719305, 142.528645) rotate(22.000000) translate(-32.719305, -142.528645) " points="31.103058 142.528645 32.7193046 144.144564 34.3355511 142.528645 32.7193046 140.912726"></polygon>
+                <polygon id="Fill-486" fill-opacity="0.8" fill="#A3B1BF" transform="translate(31.267651, 139.109844) rotate(22.000000) translate(-31.267651, -139.109844) " points="29.651405 139.109844 31.2676515 140.725763 32.883898 139.109844 31.2676515 137.493925"></polygon>
+                <polygon id="Stroke-488" transform="translate(31.267651, 139.109844) rotate(22.000000) translate(-31.267651, -139.109844) " points="29.651405 139.109844 31.2676515 140.725763 32.883898 139.109844 31.2676515 137.493925"></polygon>
+                <polygon id="Fill-490" fill-opacity="0.8" fill="#A3B1BF" transform="translate(32.466384, 150.705559) rotate(22.000000) translate(-32.466384, -150.705559) " points="30.8501373 150.705559 32.4663838 152.321478 34.0826303 150.705559 32.4663838 149.089641"></polygon>
+                <polygon id="Stroke-492" transform="translate(32.466384, 150.705559) rotate(22.000000) translate(-32.466384, -150.705559) " points="30.8501373 150.705559 32.4663838 152.321478 34.0826303 150.705559 32.4663838 149.089641"></polygon>
+                <polygon id="Fill-494" fill-opacity="0.8" fill="#A3B1BF" transform="translate(31.014790, 147.286782) rotate(22.000000) translate(-31.014790, -147.286782) " points="29.3985431 147.286782 31.0147896 148.902701 32.6310362 147.286782 31.0147896 145.670863"></polygon>
+                <polygon id="Stroke-496" transform="translate(31.014790, 147.286782) rotate(22.000000) translate(-31.014790, -147.286782) " points="29.3985431 147.286782 31.0147896 148.902701 32.6310362 147.286782 31.0147896 145.670863"></polygon>
+                <polygon id="Fill-498" fill-opacity="0.8" fill="#A3B1BF" transform="translate(29.563219, 143.867946) rotate(22.000000) translate(-29.563219, -143.867946) " points="27.9469727 143.867946 29.5632192 145.483865 31.1794658 143.867946 29.5632192 142.252027"></polygon>
+                <polygon id="Stroke-500" transform="translate(29.563219, 143.867946) rotate(22.000000) translate(-29.563219, -143.867946) " points="27.9469727 143.867946 29.5632192 145.483865 31.1794658 143.867946 29.5632192 142.252027"></polygon>
+                <polygon id="Fill-502" fill-opacity="0.8" fill="#A3B1BF" transform="translate(28.111566, 140.449145) rotate(22.000000) translate(-28.111566, -140.449145) " points="26.4953196 140.449145 28.1115662 142.065063 29.7278127 140.449145 28.1115662 138.833226"></polygon>
+                <polygon id="Stroke-504" transform="translate(28.111566, 140.449145) rotate(22.000000) translate(-28.111566, -140.449145) " points="26.4953196 140.449145 28.1115662 142.065063 29.7278127 140.449145 28.1115662 138.833226"></polygon>
+                <polygon id="Fill-506" fill-opacity="0.8" fill="#A3B1BF" transform="translate(29.310298, 152.044860) rotate(22.000000) translate(-29.310298, -152.044860) " points="27.6940519 152.04486 29.3102985 153.660779 30.926545 152.04486 29.3102985 150.428942"></polygon>
+                <polygon id="Stroke-508" transform="translate(29.310298, 152.044860) rotate(22.000000) translate(-29.310298, -152.044860) " points="27.6940519 152.04486 29.3102985 153.660779 30.926545 152.04486 29.3102985 150.428942"></polygon>
+                <polygon id="Fill-510" fill-opacity="0.8" fill="#A3B1BF" transform="translate(27.858704, 148.626083) rotate(22.000000) translate(-27.858704, -148.626083) " points="26.2424578 148.626083 27.8587043 150.242002 29.4749508 148.626083 27.8587043 147.010164"></polygon>
+                <polygon id="Stroke-512" transform="translate(27.858704, 148.626083) rotate(22.000000) translate(-27.858704, -148.626083) " points="26.2424578 148.626083 27.8587043 150.242002 29.4749508 148.626083 27.8587043 147.010164"></polygon>
+                <polygon id="Fill-514" fill-opacity="0.8" fill="#A3B1BF" transform="translate(26.407134, 145.207247) rotate(22.000000) translate(-26.407134, -145.207247) " points="24.7908874 145.207247 26.4071339 146.823166 28.0233805 145.207247 26.4071339 143.591328"></polygon>
+                <polygon id="Stroke-516" transform="translate(26.407134, 145.207247) rotate(22.000000) translate(-26.407134, -145.207247) " points="24.7908874 145.207247 26.4071339 146.823166 28.0233805 145.207247 26.4071339 143.591328"></polygon>
+                <polygon id="Fill-518" fill-opacity="0.8" fill="#A3B1BF" transform="translate(24.955481, 141.788446) rotate(22.000000) translate(-24.955481, -141.788446) " points="23.3392343 141.788446 24.9554808 143.404364 26.5717274 141.788446 24.9554808 140.172527"></polygon>
+                <polygon id="Stroke-520" transform="translate(24.955481, 141.788446) rotate(22.000000) translate(-24.955481, -141.788446) " points="23.3392343 141.788446 24.9554808 143.404364 26.5717274 141.788446 24.9554808 140.172527"></polygon>
+                <polygon id="Fill-522" fill-opacity="0.8" fill="#A3B1BF" transform="translate(26.154213, 153.384161) rotate(22.000000) translate(-26.154213, -153.384161) " points="24.5379666 153.384161 26.1542132 155.00008 27.7704597 153.384161 26.1542132 151.768243"></polygon>
+                <polygon id="Stroke-524" transform="translate(26.154213, 153.384161) rotate(22.000000) translate(-26.154213, -153.384161) " points="24.5379666 153.384161 26.1542132 155.00008 27.7704597 153.384161 26.1542132 151.768243"></polygon>
+                <polygon id="Fill-526" fill-opacity="0.8" fill="#A3B1BF" transform="translate(24.702619, 149.965384) rotate(22.000000) translate(-24.702619, -149.965384) " points="23.0863724 149.965384 24.702619 151.581303 26.3188655 149.965384 24.702619 148.349465"></polygon>
+                <polygon id="Stroke-528" transform="translate(24.702619, 149.965384) rotate(22.000000) translate(-24.702619, -149.965384) " points="23.0863724 149.965384 24.702619 151.581303 26.3188655 149.965384 24.702619 148.349465"></polygon>
+                <polygon id="Fill-530" fill-opacity="0.8" fill="#A3B1BF" transform="translate(23.250966, 146.546583) rotate(22.000000) translate(-23.250966, -146.546583) " points="21.6347194 146.546583 23.2509659 148.162502 24.8672124 146.546583 23.2509659 144.930664"></polygon>
+                <polygon id="Stroke-532" transform="translate(23.250966, 146.546583) rotate(22.000000) translate(-23.250966, -146.546583) " points="21.6347194 146.546583 23.2509659 148.162502 24.8672124 146.546583 23.2509659 144.930664"></polygon>
+                <polygon id="Fill-534" fill-opacity="0.8" fill="#A3B1BF" transform="translate(21.799396, 143.127747) rotate(22.000000) translate(-21.799396, -143.127747) " points="20.183149 143.127747 21.7993955 144.743665 23.4156421 143.127747 21.7993955 141.511828"></polygon>
+                <polygon id="Stroke-536" transform="translate(21.799396, 143.127747) rotate(22.000000) translate(-21.799396, -143.127747) " points="20.183149 143.127747 21.7993955 144.743665 23.4156421 143.127747 21.7993955 141.511828"></polygon>
+                <path d="M129.314819,189.942425 C126.372666,187.000233 124.490222,184.112668 125.110927,183.492089 C125.731631,182.87151 128.619783,184.753573 131.562571,187.695129 C134.504724,190.637321 136.387169,193.524886 135.766464,194.145465 C135.145759,194.766044 132.257608,192.883981 129.314819,189.942425 Z" id="Fill-538" fill="#F5F5F5" transform="translate(130.438695, 188.818777) rotate(22.000000) translate(-130.438695, -188.818777) "></path>
+                <path d="M129.314819,189.942425 C126.372666,187.000233 124.490222,184.112668 125.110927,183.492089 C125.731631,182.87151 128.619783,184.753573 131.562571,187.695129 C134.504724,190.637321 136.387169,193.524886 135.766464,194.145465 C135.145759,194.766044 132.257608,192.883981 129.314819,189.942425 Z" id="Stroke-540" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(130.438695, 188.818777) rotate(22.000000) translate(-130.438695, -188.818777) "></path>
+                <path d="M136.083433,187.715086 C130.20421,181.837055 126.443133,176.067006 127.683272,174.827118 C128.92341,173.587231 134.69463,177.347545 140.573854,183.225576 C146.453713,189.104243 150.21479,194.874292 148.974651,196.114179 C147.734513,197.354066 141.963293,193.593752 136.083433,187.715086 Z" id="Fill-542" fill="#F5F5F5" transform="translate(138.328961, 185.470648) rotate(22.000000) translate(-138.328961, -185.470648) "></path>
+                <path d="M136.083433,187.715086 C130.20421,181.837055 126.443133,176.067006 127.683272,174.827118 C128.92341,173.587231 134.69463,177.347545 140.573854,183.225576 C146.453713,189.104243 150.21479,194.874292 148.974651,196.114179 C147.734513,197.354066 141.963293,193.593752 136.083433,187.715086 Z" id="Stroke-544" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(138.328961, 185.470648) rotate(22.000000) translate(-138.328961, -185.470648) "></path>
+                <path d="M146.697288,183.650834 C138.818086,175.773231 133.777481,168.04045 135.43947,166.378798 C137.101459,164.717146 144.835809,169.756729 152.715011,177.634332 C160.594213,185.511936 165.634818,193.244716 163.972829,194.906369 C162.310839,196.568021 154.57649,191.528438 146.697288,183.650834 Z" id="Fill-546" fill-opacity="0.35" fill="#F5F5F5" transform="translate(149.706149, 180.642583) rotate(22.000000) translate(-149.706149, -180.642583) "></path>
+                <path d="M146.697288,183.650834 C138.818086,175.773231 133.777481,168.04045 135.43947,166.378798 C137.101459,164.717146 144.835809,169.756729 152.715011,177.634332 C160.594213,185.511936 165.634818,193.244716 163.972829,194.906369 C162.310839,196.568021 154.57649,191.528438 146.697288,183.650834 Z" id="Stroke-548" stroke="#A3B1BF" stroke-width="1.62" stroke-linejoin="round" transform="translate(149.706149, 180.642583) rotate(22.000000) translate(-149.706149, -180.642583) "></path>
+                <path d="M65.2279553,90.2345285 C62.4548336,90.0320836 60.4105231,89.3345405 60.4105231,88.5051511 C60.4105231,87.676673 62.4503446,86.9797514 65.2188187,86.7764428 C65.4149139,84.0068366 66.0879499,81.9659221 66.8880741,81.9659221 C67.6881984,81.9659221 68.3612344,84.0068366 68.5573295,86.7764428 C71.3258036,86.9797514 73.3656251,87.676673 73.3656251,88.5051511 C73.3656251,89.3345405 71.3213146,90.0320836 68.548193,90.2345285 C68.3410329,92.9408238 67.6762073,94.9210242 66.8880741,94.9210242 C66.0999409,94.9210242 65.4351154,92.9408238 65.2279553,90.2345285 Z" id="Oval-80-Copy-3" fill-opacity="0.4" fill="#A3B1BF" opacity="0.85" transform="translate(66.888074, 88.443473) rotate(-340.000000) translate(-66.888074, -88.443473) "></path>
+                <path d="M118.775569,329.140492 L118.424988,329.526146 C117.522244,330.5192 115.985396,330.592411 114.992341,329.689667 C114.596934,329.330218 114.331035,328.850456 114.235803,328.324641 L114.143075,327.812647 L113.669257,327.599091 C112.445737,327.047635 111.900921,325.608734 112.452377,324.385214 C112.672015,323.8979 113.046204,323.496601 113.516991,323.243469 L113.97521,322.997095 L114.032158,322.478985 C114.178786,321.144967 115.379087,320.182398 116.713105,320.329026 C117.24418,320.387399 117.741214,320.61917 118.127299,320.988476 L118.503957,321.348765 L119.01334,321.242962 C120.327346,320.970031 121.613813,321.813989 121.886744,323.127995 C121.995449,323.651349 121.928561,324.195943 121.696437,324.677436 L121.470742,325.145594 L121.728812,325.597409 C122.394441,326.762759 121.989337,328.247061 120.823987,328.91269 C120.359975,329.177726 119.82154,329.282421 119.292023,329.21057 L118.775569,329.140492 Z" id="Star-1-Copy-16" fill-opacity="0.4" fill="#A3B1BF"></path>
+                <path d="M432.83752,120.004816 L432.837087,120.005044 L432.837087,120.005044 C432.092472,120.396429 431.171561,120.110079 430.780176,119.365464 C430.624337,119.068978 430.570573,118.729391 430.627206,118.399266 L430.627206,118.399266 L430.627206,118.399266 L430.627206,118.399266 C430.024845,117.812233 430.01242,116.848039 430.599453,116.245678 C430.833262,116.005765 431.139652,115.849637 431.471171,115.801474 L431.471471,115.801431 L431.471471,115.801431 L431.471471,115.801431 C431.843891,115.046982 432.757399,114.737288 433.511848,115.109709 C433.812195,115.25797 434.055308,115.501083 434.20357,115.801431 L434.20357,115.801431 L434.203869,115.801474 L434.203869,115.801474 C435.036229,115.922398 435.612963,116.695187 435.492039,117.527547 C435.443876,117.859067 435.287748,118.165457 435.047835,118.399266 L435.047835,118.399266 L435.047835,118.399266 L435.047835,118.399266 C435.190066,119.228364 434.63325,120.015783 433.804152,120.158014 C433.474027,120.214647 433.134439,120.160883 432.837954,120.005044 L432.83752,120.004816 Z" id="Star-1-Copy-18" fill-opacity="0.4" fill="#A3B1BF" transform="translate(432.837619, 117.566125) rotate(-3.000000) translate(-432.837619, -117.566125) "></path>
+                <path d="M99.7727703,38.762372 L99.0266308,39.1545584 L99.0266308,39.1545584 C97.8386845,39.7789675 96.36948,39.3221304 95.7450708,38.134184 C95.4964477,37.6611755 95.4106732,37.1194035 95.5010241,36.5927278 L95.6433921,35.7628333 L95.0407812,35.1755563 L95.0407812,35.1755563 C94.0796578,34.2388893 94.059832,32.7004261 94.996499,31.7393027 C95.369563,31.3564979 95.8584376,31.1073808 96.3874089,31.0305329 L97.2206742,30.9094778 L97.5937913,30.1536188 L97.5937913,30.1536188 C98.1878378,28.950202 99.6449697,28.4562097 100.848387,29.0502562 C101.327469,29.2867472 101.715258,29.6745363 101.951749,30.1536188 L102.324866,30.9094778 L103.158132,31.0305329 L103.158132,31.0305329 C104.486241,31.223478 105.406474,32.4565366 105.213529,33.7846464 C105.136681,34.3136177 104.887564,34.8024923 104.504759,35.1755563 L103.902148,35.7628333 L104.044516,36.5927278 L104.044516,36.5927278 C104.27143,37.9154575 103.383095,39.1716915 102.060366,39.398605 C101.53369,39.4889559 100.991918,39.4031814 100.51891,39.1545584 L99.7727703,38.762372 Z" id="Star-1-Copy-19" fill-opacity="0.4" fill="#A3B1BF" transform="translate(99.772928, 34.116388) rotate(19.000000) translate(-99.772928, -34.116388) "></path>
+                <path d="M396.631073,305.744172 L396.098125,305.608596 C394.797498,305.277731 394.01135,303.955146 394.342215,302.654518 C394.473956,302.136643 394.772729,301.676633 395.192288,301.345694 L395.623376,301.00566 L395.587617,300.458372 C395.500116,299.119176 396.514815,297.962609 397.854012,297.875108 C398.387399,297.840257 398.917395,297.982247 399.361919,298.279089 L399.818473,298.583965 L400.329362,298.380373 C401.576068,297.883555 402.989473,298.491459 403.486291,299.738164 C403.684076,300.23448 403.712777,300.782145 403.567956,301.296416 L403.418882,301.825788 L403.76981,302.247972 C404.627682,303.280038 404.486471,304.812135 403.454406,305.670007 C403.043346,306.011688 402.531095,306.208301 401.996987,306.229395 L401.44896,306.251039 L401.15585,306.715309 C400.439401,307.850123 398.938655,308.189275 397.80384,307.472826 C397.351988,307.187555 397.006767,306.761296 396.821614,306.260029 L396.631073,305.744172 Z" id="Star-1-Copy-20" fill-opacity="0.4" fill="#A3B1BF"></path>
+                <path d="M439.755536,146.347757 L439.755103,146.347984 L439.755103,146.347984 C439.010488,146.739369 438.089577,146.45302 437.698192,145.708405 C437.542353,145.411919 437.488589,145.072331 437.545222,144.742206 L437.545222,144.742206 L437.545222,144.742206 L437.545222,144.742206 C436.942861,144.155173 436.930436,143.190979 437.517469,142.588619 C437.751277,142.348705 438.057668,142.192577 438.389187,142.144415 L438.389487,142.144371 L438.389487,142.144371 L438.389487,142.144371 C438.761907,141.389923 439.675415,141.080228 440.429864,141.452649 C440.730211,141.600911 440.973324,141.844024 441.121586,142.144371 L441.121586,142.144371 L441.121885,142.144415 L441.121885,142.144415 C441.954245,142.265338 442.530978,143.038128 442.410055,143.870488 C442.361892,144.202007 442.205764,144.508398 441.965851,144.742206 L441.965851,144.742206 L441.965851,144.742206 L441.965851,144.742206 C442.108082,145.571305 441.551266,146.358723 440.722168,146.500955 C440.392043,146.557588 440.052455,146.503823 439.755969,146.347984 L439.755536,146.347757 Z" id="Star-1-Copy-21" fill-opacity="0.4" fill="#A3B1BF" transform="translate(439.755635, 143.909066) rotate(-12.000000) translate(-439.755635, -143.909066) "></path>
+                <path d="M244.621971,220.61341 C277.15945,220.61341 303.536288,194.242112 303.536288,161.711467 C303.536288,129.180822 277.15945,102.809524 244.621971,102.809524 C212.084491,102.809524 185.707653,129.180822 185.707653,161.711467 C185.707653,194.242112 212.084491,220.61341 244.621971,220.61341 Z" id="Oval-8-Copy-2" fill-opacity="0.66" fill="#A3B1BF"></path>
+                <path d="M245.345696,141.060063 C241.146656,141.060063 237.880736,142.342349 235.547936,144.906921 C233.215136,147.354921 232.107056,150.618921 232.107056,154.698921 L236.714336,154.698921 C236.714336,151.842921 237.355856,149.628063 238.638896,147.996063 C240.038576,146.072635 242.196416,145.140063 245.112416,145.140063 C247.561856,145.140063 249.486416,145.781206 250.827776,147.180063 C252.110816,148.462349 252.810656,150.269206 252.810656,152.600635 C252.810656,154.232635 252.227456,155.748063 251.061056,157.205206 C250.711136,157.671492 250.011296,158.370921 249.078176,159.303492 C245.928896,162.101206 244.004336,164.316063 243.187856,166.064635 C242.488016,167.521778 242.138096,169.212063 242.138096,171.135492 L242.138096,172.476063 L246.803696,172.476063 L246.803696,171.135492 C246.803696,169.561778 247.153616,168.162921 247.911776,166.880635 C248.494976,165.831492 249.369776,164.782349 250.652816,163.674921 C253.218896,161.401778 254.793536,159.886349 255.376736,159.186921 C256.834736,157.263492 257.592896,154.990349 257.592896,152.367492 C257.592896,148.870349 256.484816,146.130921 254.326976,144.149206 C252.052496,142.050921 249.078176,141.060063 245.345696,141.060063 Z M244.470896,176.556063 C243.479456,176.556063 242.662976,176.847492 241.963136,177.546921 C241.263296,178.188063 240.971696,179.004063 240.971696,179.994921 C240.971696,180.985778 241.263296,181.801778 241.963136,182.501206 C242.662976,183.142349 243.479456,183.492063 244.470896,183.492063 C245.462336,183.492063 246.278816,183.142349 246.978656,182.501206 C247.678496,181.860063 248.028416,181.044063 248.028416,179.994921 C248.028416,179.004063 247.678496,178.188063 247.036976,177.546921 C246.337136,176.847492 245.462336,176.556063 244.470896,176.556063 Z" id="?" fill="#FFFFFF"></path>
+                <path d="M223.261662,133.139924 C229.077338,129.782947 239.631808,125.828273 236.274126,120.013819 C232.916444,114.199364 220.565868,115.043746 214.750193,118.400722 C208.934517,121.757699 202.729834,131.623951 206.087516,137.438405 C209.445198,143.252859 217.445986,136.4969 223.261662,133.139924" id="Oval-8-Copy-2" fill="#FAFAFA"></path>
+                <path d="M249.679003,119.820589 C252.365149,119.820589 254.5427,117.643495 254.5427,114.957913 C254.5427,112.272332 252.365149,110.095238 249.679003,110.095238 C246.992857,110.095238 244.815306,112.272332 244.815306,114.957913 C244.815306,117.643495 246.992857,119.820589 249.679003,119.820589 Z" id="Oval-10-Copy" fill="#FAFAFA"></path>
+                <path d="M421.5,321.5 L423,323" id="Line-2" stroke="#979797" stroke-linecap="square"></path>
+            </g>
+        </g>
+    </g>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 191 - 0
admin/images/500.svg


BIN
admin/images/act.jpg


BIN
admin/images/avatar.jpg


+ 33 - 0
admin/images/background.svg

@@ -0,0 +1,33 @@
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="100%" height="100%" viewBox="0 0 1400 800">
+
+  <rect x="1300" y="400" rx="40" ry="40" width="300" height="300" stroke="rgb(129, 201, 149)" fill="rgb(129, 201, 149)">
+    <animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="0 1450 550" to="360 1450 550" repeatCount="indefinite"/>
+  </rect>
+
+  <path d="M 100 350 A 150 150 0 1 1 400 350 Q400 370 380 370 L 250 370 L 120 370 Q100 370 100 350" stroke="rgb(253, 214, 99)" fill="rgb(253, 214, 99)">
+    <animateMotion path="M 800 -200 L 800 -300 L 800 -200" dur="20s" begin="0s" repeatCount="indefinite"/>
+    <animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="30s" type="rotate" values="0 210 530 ; -30 210 530 ; 0 210 530" keyTimes="0 ; 0.5 ; 1" repeatCount="indefinite"/>
+  </path>
+
+  <circle cx="200" cy="150" r="20" stroke="#1a73e8" fill="#1a73e8">
+    <animateMotion path="M 0 0 L 40 20 Z" dur="5s" repeatCount="indefinite"/>
+  </circle>
+
+  <!-- 三角形 -->
+  <path d="M 165 580 L 270 580 Q275 578 270 570 L 223 483 Q220 480 217 483 L 165 570 Q160 578 165 580" stroke="rgb(238, 103, 92)" fill="rgb(238, 103, 92)">
+    <animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="0 210 530" to="360 210 530" repeatCount="indefinite"/>
+  </path>
+
+  <circle cx="1200" cy="600" r="30" stroke="rgb(241, 243, 244)" fill="rgb(241, 243, 244)">
+    <animateMotion path="M 0 0 L -20 40 Z" dur="9s" repeatCount="indefinite"/>
+  </circle>
+
+  <path d="M 100 350 A 40 40 0 1 1 180 350 L 180 430 A 40 40 0 1 1 100 430 Z" stroke="rgb(241, 243, 244)" fill="rgb(241, 243, 244)">
+    <animateMotion path="M 140 390 L 180 360 L 140 390" dur="20s" begin="0s" repeatCount="indefinite"/>
+    <animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="30s" type="rotate" values="0 140 390; -60 140 390; 0 140 390" keyTimes="0 ; 0.5 ; 1" repeatCount="indefinite"/>
+  </path>
+
+  <rect x="400" y="600" rx="40" ry="40" width="100" height="100" stroke="rgb(129, 201, 149)" fill="rgb(129, 201, 149)">
+    <animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="-30 550 750" to="330 550 750" repeatCount="indefinite"/>
+  </rect>
+</svg>

BIN
admin/images/captcha.gif


BIN
admin/images/logo.png


BIN
admin/images/show.png


+ 623 - 0
app/app.js

@@ -0,0 +1,623 @@
+window.rootUrl = window.location.protocol + '//' + window.location.host;
+window._AUTH_INFO_ = "AUTH_MANAGER";
+window._CONFIG_ = {};   // 后台管理配置.
+window._UPLOAD_TOKEN_ = 'GAkucH8';  // 上传通信token
+window._UPLOAD_SERVER_CONFIG_ = {}; // 上传服务器配置信息.
+window._PLUP_PATH_ = rootUrl + 'app/assets/js/plupload-2.3.7/';   // Plupload 引用资源相对路径.
+window._PLUP_SERVER_URI_ = ''; // Plupload服务端URI,有配置以来,预先空字符串.
+window._PLUP_FILE_FIELD_NAME_ = 'upload_files';    // 上传文件的表单字段名
+window._AES_KEY_ = 'Iz9IhtcyKbYJynAd'; // AES加密的key
+
+
+layui.extend({
+	mhttp: "{/}"+ rootUrl +"/app/modules/mhttp",			// ajax请求组件
+	madmin: "{/}"+ rootUrl +"/app/modules/madmin",			// admin组件
+});
+
+
+String.prototype.trim = function (char, type) {
+    if (char) {
+        if (type == 'left') {
+            return this.replace(new RegExp('^\\'+char+'+', 'g'), '');
+        } else if (type == 'right') {
+            return this.replace(new RegExp('\\'+char+'+$', 'g'), '');
+        }
+        return this.replace(new RegExp('^\\'+char+'+|\\'+char+'+$', 'g'), '');
+    }
+    return this.replace(/^\s+|\s+$/g, '');
+};
+String.prototype.rtrim = function (s) {
+    return this.trim(s, 'right');
+};
+String.prototype.ltrim = function (s) {
+    return this.trim(s, 'left');
+};
+
+/**
+ * 获取应用环境.
+ * @returns 
+ */
+function getAppEnv()
+{
+	var appEnv = 'prod';
+	var hostAndPort = window.location.host;
+	var devReg = /(127\.0\.0\.1|localhost)/;
+	var qaReg = /(test)/;
+	// 设置应用所在环境.
+	if (devReg.test(hostAndPort)) {
+		appEnv = 'dev';
+	} else if (qaReg.test(hostAndPort)) {
+		appEnv = 'test';
+	} else {
+		appEnv = 'prod';
+	}
+
+	return appEnv;
+}
+
+/**
+ * 获取应用配置.
+ * @returns 
+ */
+function getAppConfigPath()
+{
+    var path = 'config/ignore/pear.config.yml';
+    var url = window.location.protocol + '//' + window.location.host + '/' + path;
+	return url;
+}
+
+/**
+ * 格式化时长,格式00:00:00
+ * @param {*} duration 
+ * @returns 
+ */
+function formatDuration(duration)
+{
+    duration = parseFloat(duration);
+    var hour = 60 * 60;
+    var pHour = duration / hour;
+    var strHour = '0';
+    if (pHour > 0) {
+        strHour = parseInt(pHour).toString()
+    }
+	strHour = strHour.padStart(2, '0');
+    var pMinute = parseInt(duration % hour / 60);
+    var strMinute = pMinute.toString().padStart(2, '0');
+    var pSecond = parseInt(duration % hour % 60);
+    var strSecond = pSecond.toString().padStart(2, '0');
+
+    var result = strHour + ":" + strMinute + ":" + strSecond;
+
+    return result;
+}
+
+function httpRequestPostData(data)
+{
+    return {
+        "data": data,
+        "handshake": ""
+    };
+}
+
+function httpRequestPagesParseData(res)
+{
+    return {
+        "code": res.code,
+        "msg": res.message,
+        "data" : res.data.data,
+        "count": res.data.total ?? 0
+    };
+}
+
+function cbRespnseRedirectLogin(data)
+{
+    localStorage.removeItem(window._AUTH_INFO_);
+    layer.alert('['+ data.code +']' + data.message + ', 请重新登陆', {
+        title: '错误信息',
+        icon: 2,
+        closeBtn: 1,
+        shade: 0.5,
+        shadeClose: false,
+        end: function () {
+            parent.location.href = window.rootUrl + '/login.html';
+        }
+    });
+}
+
+
+function cbRespnse401(data)
+{
+    // refreshToken();
+    localStorage.removeItem(window._AUTH_INFO_);
+    layer.alert('['+ data.code +']' + data.message + ', 请重新登陆', {
+        title: '错误信息',
+        icon: 2,
+        closeBtn: 1,
+        shade: 0.5,
+        shadeClose: false,
+        end: function () {
+            parent.location.href = window.rootUrl + '/login.html';
+        }
+    });
+    
+}
+
+
+function cbRespnseReloadPage(data, message)
+{
+    // localStorage.removeItem(window._AUTH_INFO_);
+    layer.alert('请求异常,请联系管理员!', {
+        title: '错误信息',
+        icon: 2,
+        closeBtn: 1,
+        shade: 0.5,
+        shadeClose: false,
+        end: function () {
+            // parent.location.reload();
+        }
+    });
+}
+
+function getMyDetail()
+{
+    var info = localStorage.getItem(window._AUTH_INFO_);
+    return JSON.parse(info);
+}
+
+function getMyUid()
+{
+    var detail = getMyDetail();
+    if (detail) {
+        return detail.manager_uid;
+    } else {
+        return '';
+    }
+}
+
+function refreshToken()
+{
+    layui.use(['mhttp', 'popup'], function () {
+        var mhttp = layui.mhttp;
+        var popup = layui.popup;
+
+        var postData = {
+            "manager_uid": getMyUid(),
+            "old_token": mhttp.ajax.getToken()
+        };
+        var ret = mhttp.ajax({
+            url: "/auth/refresh/token",
+            data : postData,
+            // 同步.
+            async: false
+        });
+
+        ret.then((data) => {
+            if (data.code == 200) {
+                // 设置token
+                mhttp.ajax.setToken(data.data.token);
+            } else {
+                console.log('刷新token');
+                // 错误提示.
+                popup.failure('['+ data.code +']' + data.message);
+            }
+        });
+    });
+}
+
+function threadBizCodeNoParams(code, func)
+{
+    // if (code == 401) {
+    //     func.call(null);
+    // }
+}
+
+
+/**
+ * 格式化为相对协议.
+ * @param {*} url 
+ * @returns 
+ */
+ function slashesUrl(url)
+ {
+    var pattern = /^(http|https)\:\/\/(.*?)$/i;
+    var arr = url.match(pattern);
+    if (arr) {
+        return '//' + arr[2];
+    } else {
+        return url;
+    }
+ }
+
+/**
+ * 把buffer转b64
+ * 参考1:https://stackoverflow.com/questions/27375908/crypto-js-read-and-decrypt-file
+ * 擦靠2:https://gist.github.com/jonleighton/958841
+ * @param {*} arrayBuffer 
+ * @returns 
+ */
+function base64ArrayBuffer(arrayBuffer) {
+    var base64    = ''
+    var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+  
+    var bytes         = new Uint8Array(arrayBuffer)
+    var byteLength    = bytes.byteLength
+    var byteRemainder = byteLength % 3
+    var mainLength    = byteLength - byteRemainder
+  
+    var a, b, c, d
+    var chunk
+  
+    // Main loop deals with bytes in chunks of 3
+    for (var i = 0; i < mainLength; i = i + 3) {
+      // Combine the three bytes into a single integer
+      chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
+  
+      // Use bitmasks to extract 6-bit segments from the triplet
+      a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
+      b = (chunk & 258048)   >> 12 // 258048   = (2^6 - 1) << 12
+      c = (chunk & 4032)     >>  6 // 4032     = (2^6 - 1) << 6
+      d = chunk & 63               // 63       = 2^6 - 1
+  
+      // Convert the raw binary segments to the appropriate ASCII encoding
+      base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
+    }
+  
+    // Deal with the remaining bytes and padding
+    if (byteRemainder == 1) {
+      chunk = bytes[mainLength]
+  
+      a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
+  
+      // Set the 4 least significant bits to zero
+      b = (chunk & 3)   << 4 // 3   = 2^2 - 1
+  
+      base64 += encodings[a] + encodings[b] + '=='
+    } else if (byteRemainder == 2) {
+      chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
+  
+      a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
+      b = (chunk & 1008)  >>  4 // 1008  = (2^6 - 1) << 4
+  
+      // Set the 2 least significant bits to zero
+      c = (chunk & 15)    <<  2 // 15    = 2^4 - 1
+  
+      base64 += encodings[a] + encodings[b] + encodings[c] + '='
+    }
+    
+    return base64
+}
+
+/**
+ * 调试log,只有_DEBUG_全局变量为true才会输出.
+ */
+function debugLog()
+{
+    if (typeof(_DEBUG_) != 'undefined') {
+        if (_DEBUG_ == true) {
+            console.log(...arguments)
+        }
+    }
+}
+
+/**
+ * 获取自己的上传服务的url。
+ * @param {*} url 
+ * @returns 
+ */
+function getMyUploadUrl(url)
+{
+    return slashesUrl(window._CONFIG_.sysconfig.uploadServerBaseUrl + url);
+}
+
+/**
+ * 获取自己的后台API服务url
+ * @param {*} url 
+ * @returns 
+ */
+function getMyApiUrl(url)
+{
+    return slashesUrl(window._CONFIG_.sysconfig.apiServerBaseUrl + url);
+}
+
+
+/**
+ * 获取存储服务器组配置信息.
+ */
+ function getStorageServersConfig()
+ {
+    layui.use(['jquery', 'madmin', 'popup'], function () {
+        let $ = layui.jquery;
+        let madmin = layui.madmin;
+        let popup = layui.popup;
+        let config = madmin.getConfig();
+        window._PLUP_SERVER_URI_ = getMyUploadUrl('/uploader.php');   // 依赖 getConfig
+        $.ajax(
+            {
+                type:'GET',
+                url: getMyUploadUrl('/sg_server_config.php?upload_token='+ window._UPLOAD_TOKEN_),
+                data: {},
+                async: false,   // 注意,因为初始化,优先这里要同步.
+                dataType: 'json',
+                beforeSend : function() {
+                },
+                complete: function() {
+                },
+                error : function() {
+                    popup.failure('获取上传服务器请求出错');
+                },
+                success: function(s) {
+                    if (s.code == 200) {
+                        window._UPLOAD_SERVER_CONFIG_ = s.data;
+                    } else {
+                        popup.failure('['+ data.code +']' + data.message);
+                    }
+                }
+                
+            }
+        );
+    });
+ }
+
+
+ /**
+  * 拼接待解密的完整URL.
+  * @param {*} url 
+  * @param {*} convertSlashes 
+  * @returns 
+  */
+  function concatUrl(url, convertSlashes)
+  {
+     let baseUrl = '';
+     if (url.lastIndexOf('|') > -1) {
+         // 找到分隔符.
+         let arrData = url.split('|');
+         let flag = arrData[0];
+         let relativeUrl = arrData[1];
+         if (window._UPLOAD_SERVER_CONFIG_.servers.hasOwnProperty(flag)) {
+             baseUrl = window._UPLOAD_SERVER_CONFIG_.servers[flag]['url'];
+             var resultUrl = baseUrl + relativeUrl;
+             if (convertSlashes) {
+                 resultUrl = slashesUrl(resultUrl);
+             }
+             return resultUrl;
+         } else {
+             return '';
+         }
+     } else {
+         return '';
+     }
+  }
+ 
+ /**
+  * 在属性里获取url.
+  * @param {*} ele 
+  * @returns 
+  */
+ function getUrlInAttrs(ele)
+ {
+     return layui.use(['jquery'], function () {
+        let $ = layui.jquery;
+        let b64 = $(ele).attr('data-b64');
+        if (b64) {
+            return $(ele).attr('data-b64');
+        } else {
+            return '';
+        }
+     });
+ }
+
+/**
+ * 解密基于arrayBuffer数据.
+ * @param {*} buffers 
+ * @returns 
+ */
+function aes128ecbDecodeByBuffer(buffers)
+{
+    let encodedData = base64ArrayBuffer(buffers);   // 这个地方很重要!
+    let options = {
+        iv: '',
+        mode: CryptoJS.mode.ECB,
+        padding: CryptoJS.pad.Pkcs7
+    };
+    let keyObj = CryptoJS.enc.Utf8.parse(window._AES_KEY_);    // 必须是对象key
+    let decrypted = CryptoJS.AES.decrypt(encodedData, keyObj, options);
+
+    return decrypted;
+}
+
+/**
+ * 拼接dataURL.
+ * @param {*} b64 
+ * @returns 
+ */
+ function concatImageDataUrl(b64)
+ {
+     return "data:image/png;base64," + b64;
+ }
+
+/**
+ * 现代浏览器Fetch异步下载并解密图片.
+ * @param {*} url 
+ * @returns 
+ */
+function fetchImageFile(url)
+{
+    return fetch(url, {
+        method: 'GET'
+        // headers: {
+        //     Authorization: 'Bearer ' + token,
+        //     'Accept': 'application/json'
+        // }
+    }).then(
+        // 必须是arrayBuffer
+        response => {
+            if (response.ok) {
+                return response.arrayBuffer();
+            } else {
+                return Promise.reject({
+                    status: response.status,
+                    statusText: response.statusText
+                });
+            }
+        }
+    ).then(respRaw => {
+        let ext = getFileExt(url);
+        let strB64 = "";
+        if (ext == 'ceb') {
+            // 仅对ceb扩展名,进行解密.
+            let decrypted = aes128ecbDecodeByBuffer(respRaw);
+            strB64 = decrypted.toString(CryptoJS.enc.Base64);
+        } else {
+            strB64 = base64ArrayBuffer(respRaw);
+        }
+        let dataUrl = concatImageDataUrl(strB64);
+        return dataUrl;
+    }).catch(error => {
+    });
+    
+}
+
+/**
+ * 获取文件扩展名,不包括dot.
+ * @param {*} file 
+ * @returns 
+ */
+function getFileExt(file)
+{
+    let ext = file.substring(file.lastIndexOf('.') + 1);
+    return ext.toLowerCase();
+}
+
+
+/**
+ * 渲染datahref
+ * @param {*} ele 
+ * @param {*} dataHref
+ */
+ function renderDataHref(ele, dataHref)
+ {
+    layui.use(['jquery'], function () {
+        let $ = layui.jquery;
+        $(ele).attr('href', dataHref);
+    });
+ }
+
+/**
+ * 渲染data
+ * @param {*} ele
+ * @param {*} dataUrl
+ */
+ function renderDataUrl(ele, dataUrl)
+ {
+    layui.use(['jquery'], function () {
+        let $ = layui.jquery;
+        $(ele).attr('src', dataUrl);
+    });
+ }
+ 
+ /**
+  * 单个对象渲染图片(依赖jQuery)
+  * @param {*} ele 
+  */
+ function onceRender(ele)
+ {
+    layui.use(['jquery'], function () {
+        let $ = layui.jquery;
+        let originUrl = '';
+        let dataCebUrl = $(ele).attr('data-ceb-url');
+        let srcValue = $(ele).attr('src');
+        // 优先取data-ceb-url值,因为直接放src属性里的图片,会报404.
+        if (typeof(dataCebUrl) != 'undefined' && dataCebUrl != '') {
+            originUrl = dataCebUrl;
+        } else if (typeof(srcValue) != 'undefined' && srcValue != '') {
+            originUrl = srcValue;
+        }
+        if (originUrl.lastIndexOf('|') > -1) {
+            let b64Url = originUrl;
+            let convertSlashes = 1;
+            // let b64Url = $(ele).attr('data-b64');
+            let fullUrl = concatUrl(b64Url, convertSlashes);
+            if (fullUrl != '') {
+                // 备份一次原始图片地址
+                $(ele).attr('data-ceb-url', originUrl);
+                // 合法的才渲染.
+                let promiseResult = fetchImageFile(fullUrl);
+                promiseResult.then(dataUrl =>  {
+                    renderDataUrl(ele, dataUrl);
+                });
+            }
+        }
+    });
+ }
+
+/**
+ * 下载app地址处理
+ * @param ele
+ */
+function appDownloadRender(ele){
+    layui.use(['jquery'], function () {
+        let $ = layui.jquery;
+        let dataHref = $(ele).attr('href');
+        if (typeof(dataHref) == 'undefined' || dataHref === '') {
+            return false;
+        }
+        // 拆分
+        if (dataHref.lastIndexOf('|') > -1) {
+            let arrData = dataHref.split('|');
+            let flag = arrData[0];
+            let relativeUrl = arrData[1];
+            // 合并
+            if (window._UPLOAD_SERVER_CONFIG_.servers.hasOwnProperty(flag)) {
+                let baseUrl = window._UPLOAD_SERVER_CONFIG_.servers[flag]['url'];
+                var resultUrl = baseUrl + relativeUrl;
+                $(ele).attr('href',resultUrl);
+            }
+        }
+    });
+ }
+ /**
+  * 页面初始化dom加载完毕后渲染所有img标签.
+  */
+function onloadRender()
+{
+layui.use(['jquery'], function () {
+    let $ = layui.jquery;
+    $(function() {
+        $('img').each(function (index, ele) {
+            onceRender(ele);
+        });
+        //app下载地址修改
+        $('.app-download').each(function (index,ele){
+            appDownloadRender(ele);
+        });
+    });
+});
+}
+
+/**
+ * 获取同字段名数组的值.
+ * 因为layui表单获取同字段名数组时,无法正常给数组结构。
+ * @param {*} fieldName 
+ * @param {*} fieldItems 
+ * @returns 
+ */
+function getLayuiArrFieldValue(fieldName, fieldItems)
+{
+    let arrFields = [];
+    let arrData = [];
+    if (fieldItems && Object.keys(fieldItems).length > 0) {
+        for (const keyName in fieldItems) {
+            if (fieldItems.hasOwnProperty(keyName)) {
+                var strPattern = '^(' + fieldName +')\\[\\d+\\]$';
+                var reg = new RegExp(strPattern, 'i')
+                var result = keyName.match(reg);
+                if (result) {
+                    arrFields.push(result[0]);
+                    arrData.push(fieldItems[keyName]);
+                }
+            }
+        }
+    }
+
+    return arrData;
+}

+ 6191 - 0
app/assets/js/crypto/crypto-js.js

@@ -0,0 +1,6191 @@
+;(function (root, factory) {
+	if (typeof exports === "object") {
+		// CommonJS
+		module.exports = exports = factory();
+	}
+	else if (typeof define === "function" && define.amd) {
+		// AMD
+		define([], factory);
+	}
+	else {
+		// Global (browser)
+		root.CryptoJS = factory();
+	}
+}(this, function () {
+
+	/*globals window, global, require*/
+
+	/**
+	 * CryptoJS core components.
+	 */
+	var CryptoJS = CryptoJS || (function (Math, undefined) {
+
+	    var crypto;
+
+	    // Native crypto from window (Browser)
+	    if (typeof window !== 'undefined' && window.crypto) {
+	        crypto = window.crypto;
+	    }
+
+	    // Native crypto in web worker (Browser)
+	    if (typeof self !== 'undefined' && self.crypto) {
+	        crypto = self.crypto;
+	    }
+
+	    // Native crypto from worker
+	    if (typeof globalThis !== 'undefined' && globalThis.crypto) {
+	        crypto = globalThis.crypto;
+	    }
+
+	    // Native (experimental IE 11) crypto from window (Browser)
+	    if (!crypto && typeof window !== 'undefined' && window.msCrypto) {
+	        crypto = window.msCrypto;
+	    }
+
+	    // Native crypto from global (NodeJS)
+	    if (!crypto && typeof global !== 'undefined' && global.crypto) {
+	        crypto = global.crypto;
+	    }
+
+	    // Native crypto import via require (NodeJS)
+	    if (!crypto && typeof require === 'function') {
+	        try {
+	            crypto = require('crypto');
+	        } catch (err) {}
+	    }
+
+	    /*
+	     * Cryptographically secure pseudorandom number generator
+	     *
+	     * As Math.random() is cryptographically not safe to use
+	     */
+	    var cryptoSecureRandomInt = function () {
+	        if (crypto) {
+	            // Use getRandomValues method (Browser)
+	            if (typeof crypto.getRandomValues === 'function') {
+	                try {
+	                    return crypto.getRandomValues(new Uint32Array(1))[0];
+	                } catch (err) {}
+	            }
+
+	            // Use randomBytes method (NodeJS)
+	            if (typeof crypto.randomBytes === 'function') {
+	                try {
+	                    return crypto.randomBytes(4).readInt32LE();
+	                } catch (err) {}
+	            }
+	        }
+
+	        throw new Error('Native crypto module could not be used to get secure random number.');
+	    };
+
+	    /*
+	     * Local polyfill of Object.create
+
+	     */
+	    var create = Object.create || (function () {
+	        function F() {}
+
+	        return function (obj) {
+	            var subtype;
+
+	            F.prototype = obj;
+
+	            subtype = new F();
+
+	            F.prototype = null;
+
+	            return subtype;
+	        };
+	    }());
+
+	    /**
+	     * CryptoJS namespace.
+	     */
+	    var C = {};
+
+	    /**
+	     * Library namespace.
+	     */
+	    var C_lib = C.lib = {};
+
+	    /**
+	     * Base object for prototypal inheritance.
+	     */
+	    var Base = C_lib.Base = (function () {
+
+
+	        return {
+	            /**
+	             * Creates a new object that inherits from this object.
+	             *
+	             * @param {Object} overrides Properties to copy into the new object.
+	             *
+	             * @return {Object} The new object.
+	             *
+	             * @static
+	             *
+	             * @example
+	             *
+	             *     var MyType = CryptoJS.lib.Base.extend({
+	             *         field: 'value',
+	             *
+	             *         method: function () {
+	             *         }
+	             *     });
+	             */
+	            extend: function (overrides) {
+	                // Spawn
+	                var subtype = create(this);
+
+	                // Augment
+	                if (overrides) {
+	                    subtype.mixIn(overrides);
+	                }
+
+	                // Create default initializer
+	                if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
+	                    subtype.init = function () {
+	                        subtype.$super.init.apply(this, arguments);
+	                    };
+	                }
+
+	                // Initializer's prototype is the subtype object
+	                subtype.init.prototype = subtype;
+
+	                // Reference supertype
+	                subtype.$super = this;
+
+	                return subtype;
+	            },
+
+	            /**
+	             * Extends this object and runs the init method.
+	             * Arguments to create() will be passed to init().
+	             *
+	             * @return {Object} The new object.
+	             *
+	             * @static
+	             *
+	             * @example
+	             *
+	             *     var instance = MyType.create();
+	             */
+	            create: function () {
+	                var instance = this.extend();
+	                instance.init.apply(instance, arguments);
+
+	                return instance;
+	            },
+
+	            /**
+	             * Initializes a newly created object.
+	             * Override this method to add some logic when your objects are created.
+	             *
+	             * @example
+	             *
+	             *     var MyType = CryptoJS.lib.Base.extend({
+	             *         init: function () {
+	             *             // ...
+	             *         }
+	             *     });
+	             */
+	            init: function () {
+	            },
+
+	            /**
+	             * Copies properties into this object.
+	             *
+	             * @param {Object} properties The properties to mix in.
+	             *
+	             * @example
+	             *
+	             *     MyType.mixIn({
+	             *         field: 'value'
+	             *     });
+	             */
+	            mixIn: function (properties) {
+	                for (var propertyName in properties) {
+	                    if (properties.hasOwnProperty(propertyName)) {
+	                        this[propertyName] = properties[propertyName];
+	                    }
+	                }
+
+	                // IE won't copy toString using the loop above
+	                if (properties.hasOwnProperty('toString')) {
+	                    this.toString = properties.toString;
+	                }
+	            },
+
+	            /**
+	             * Creates a copy of this object.
+	             *
+	             * @return {Object} The clone.
+	             *
+	             * @example
+	             *
+	             *     var clone = instance.clone();
+	             */
+	            clone: function () {
+	                return this.init.prototype.extend(this);
+	            }
+	        };
+	    }());
+
+	    /**
+	     * An array of 32-bit words.
+	     *
+	     * @property {Array} words The array of 32-bit words.
+	     * @property {number} sigBytes The number of significant bytes in this word array.
+	     */
+	    var WordArray = C_lib.WordArray = Base.extend({
+	        /**
+	         * Initializes a newly created word array.
+	         *
+	         * @param {Array} words (Optional) An array of 32-bit words.
+	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.lib.WordArray.create();
+	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
+	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
+	         */
+	        init: function (words, sigBytes) {
+	            words = this.words = words || [];
+
+	            if (sigBytes != undefined) {
+	                this.sigBytes = sigBytes;
+	            } else {
+	                this.sigBytes = words.length * 4;
+	            }
+	        },
+
+	        /**
+	         * Converts this word array to a string.
+	         *
+	         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
+	         *
+	         * @return {string} The stringified word array.
+	         *
+	         * @example
+	         *
+	         *     var string = wordArray + '';
+	         *     var string = wordArray.toString();
+	         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
+	         */
+	        toString: function (encoder) {
+	            return (encoder || Hex).stringify(this);
+	        },
+
+	        /**
+	         * Concatenates a word array to this word array.
+	         *
+	         * @param {WordArray} wordArray The word array to append.
+	         *
+	         * @return {WordArray} This word array.
+	         *
+	         * @example
+	         *
+	         *     wordArray1.concat(wordArray2);
+	         */
+	        concat: function (wordArray) {
+	            // Shortcuts
+	            var thisWords = this.words;
+	            var thatWords = wordArray.words;
+	            var thisSigBytes = this.sigBytes;
+	            var thatSigBytes = wordArray.sigBytes;
+
+	            // Clamp excess bits
+	            this.clamp();
+
+	            // Concat
+	            if (thisSigBytes % 4) {
+	                // Copy one byte at a time
+	                for (var i = 0; i < thatSigBytes; i++) {
+	                    var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                    thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
+	                }
+	            } else {
+	                // Copy one word at a time
+	                for (var j = 0; j < thatSigBytes; j += 4) {
+	                    thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2];
+	                }
+	            }
+	            this.sigBytes += thatSigBytes;
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Removes insignificant bits.
+	         *
+	         * @example
+	         *
+	         *     wordArray.clamp();
+	         */
+	        clamp: function () {
+	            // Shortcuts
+	            var words = this.words;
+	            var sigBytes = this.sigBytes;
+
+	            // Clamp
+	            words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
+	            words.length = Math.ceil(sigBytes / 4);
+	        },
+
+	        /**
+	         * Creates a copy of this word array.
+	         *
+	         * @return {WordArray} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = wordArray.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+	            clone.words = this.words.slice(0);
+
+	            return clone;
+	        },
+
+	        /**
+	         * Creates a word array filled with random bytes.
+	         *
+	         * @param {number} nBytes The number of random bytes to generate.
+	         *
+	         * @return {WordArray} The random word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.lib.WordArray.random(16);
+	         */
+	        random: function (nBytes) {
+	            var words = [];
+
+	            for (var i = 0; i < nBytes; i += 4) {
+	                words.push(cryptoSecureRandomInt());
+	            }
+
+	            return new WordArray.init(words, nBytes);
+	        }
+	    });
+
+	    /**
+	     * Encoder namespace.
+	     */
+	    var C_enc = C.enc = {};
+
+	    /**
+	     * Hex encoding strategy.
+	     */
+	    var Hex = C_enc.Hex = {
+	        /**
+	         * Converts a word array to a hex string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The hex string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var hexChars = [];
+	            for (var i = 0; i < sigBytes; i++) {
+	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                hexChars.push((bite >>> 4).toString(16));
+	                hexChars.push((bite & 0x0f).toString(16));
+	            }
+
+	            return hexChars.join('');
+	        },
+
+	        /**
+	         * Converts a hex string to a word array.
+	         *
+	         * @param {string} hexStr The hex string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
+	         */
+	        parse: function (hexStr) {
+	            // Shortcut
+	            var hexStrLength = hexStr.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < hexStrLength; i += 2) {
+	                words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
+	            }
+
+	            return new WordArray.init(words, hexStrLength / 2);
+	        }
+	    };
+
+	    /**
+	     * Latin1 encoding strategy.
+	     */
+	    var Latin1 = C_enc.Latin1 = {
+	        /**
+	         * Converts a word array to a Latin1 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The Latin1 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var latin1Chars = [];
+	            for (var i = 0; i < sigBytes; i++) {
+	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                latin1Chars.push(String.fromCharCode(bite));
+	            }
+
+	            return latin1Chars.join('');
+	        },
+
+	        /**
+	         * Converts a Latin1 string to a word array.
+	         *
+	         * @param {string} latin1Str The Latin1 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
+	         */
+	        parse: function (latin1Str) {
+	            // Shortcut
+	            var latin1StrLength = latin1Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < latin1StrLength; i++) {
+	                words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
+	            }
+
+	            return new WordArray.init(words, latin1StrLength);
+	        }
+	    };
+
+	    /**
+	     * UTF-8 encoding strategy.
+	     */
+	    var Utf8 = C_enc.Utf8 = {
+	        /**
+	         * Converts a word array to a UTF-8 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-8 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            try {
+	                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
+	            } catch (e) {
+	                throw new Error('Malformed UTF-8 data');
+	            }
+	        },
+
+	        /**
+	         * Converts a UTF-8 string to a word array.
+	         *
+	         * @param {string} utf8Str The UTF-8 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
+	         */
+	        parse: function (utf8Str) {
+	            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
+	        }
+	    };
+
+	    /**
+	     * Abstract buffered block algorithm template.
+	     *
+	     * The property blockSize must be implemented in a concrete subtype.
+	     *
+	     * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
+	     */
+	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
+	        /**
+	         * Resets this block algorithm's data buffer to its initial state.
+	         *
+	         * @example
+	         *
+	         *     bufferedBlockAlgorithm.reset();
+	         */
+	        reset: function () {
+	            // Initial values
+	            this._data = new WordArray.init();
+	            this._nDataBytes = 0;
+	        },
+
+	        /**
+	         * Adds new data to this block algorithm's buffer.
+	         *
+	         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
+	         *
+	         * @example
+	         *
+	         *     bufferedBlockAlgorithm._append('data');
+	         *     bufferedBlockAlgorithm._append(wordArray);
+	         */
+	        _append: function (data) {
+	            // Convert string to WordArray, else assume WordArray already
+	            if (typeof data == 'string') {
+	                data = Utf8.parse(data);
+	            }
+
+	            // Append
+	            this._data.concat(data);
+	            this._nDataBytes += data.sigBytes;
+	        },
+
+	        /**
+	         * Processes available data blocks.
+	         *
+	         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
+	         *
+	         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
+	         *
+	         * @return {WordArray} The processed data.
+	         *
+	         * @example
+	         *
+	         *     var processedData = bufferedBlockAlgorithm._process();
+	         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
+	         */
+	        _process: function (doFlush) {
+	            var processedWords;
+
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+	            var dataSigBytes = data.sigBytes;
+	            var blockSize = this.blockSize;
+	            var blockSizeBytes = blockSize * 4;
+
+	            // Count blocks ready
+	            var nBlocksReady = dataSigBytes / blockSizeBytes;
+	            if (doFlush) {
+	                // Round up to include partial blocks
+	                nBlocksReady = Math.ceil(nBlocksReady);
+	            } else {
+	                // Round down to include only full blocks,
+	                // less the number of blocks that must remain in the buffer
+	                nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
+	            }
+
+	            // Count words ready
+	            var nWordsReady = nBlocksReady * blockSize;
+
+	            // Count bytes ready
+	            var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
+
+	            // Process blocks
+	            if (nWordsReady) {
+	                for (var offset = 0; offset < nWordsReady; offset += blockSize) {
+	                    // Perform concrete-algorithm logic
+	                    this._doProcessBlock(dataWords, offset);
+	                }
+
+	                // Remove processed words
+	                processedWords = dataWords.splice(0, nWordsReady);
+	                data.sigBytes -= nBytesReady;
+	            }
+
+	            // Return processed words
+	            return new WordArray.init(processedWords, nBytesReady);
+	        },
+
+	        /**
+	         * Creates a copy of this object.
+	         *
+	         * @return {Object} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = bufferedBlockAlgorithm.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+	            clone._data = this._data.clone();
+
+	            return clone;
+	        },
+
+	        _minBufferSize: 0
+	    });
+
+	    /**
+	     * Abstract hasher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
+	     */
+	    var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
+	        /**
+	         * Configuration options.
+	         */
+	        cfg: Base.extend(),
+
+	        /**
+	         * Initializes a newly created hasher.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
+	         *
+	         * @example
+	         *
+	         *     var hasher = CryptoJS.algo.SHA256.create();
+	         */
+	        init: function (cfg) {
+	            // Apply config defaults
+	            this.cfg = this.cfg.extend(cfg);
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this hasher to its initial state.
+	         *
+	         * @example
+	         *
+	         *     hasher.reset();
+	         */
+	        reset: function () {
+	            // Reset data buffer
+	            BufferedBlockAlgorithm.reset.call(this);
+
+	            // Perform concrete-hasher logic
+	            this._doReset();
+	        },
+
+	        /**
+	         * Updates this hasher with a message.
+	         *
+	         * @param {WordArray|string} messageUpdate The message to append.
+	         *
+	         * @return {Hasher} This hasher.
+	         *
+	         * @example
+	         *
+	         *     hasher.update('message');
+	         *     hasher.update(wordArray);
+	         */
+	        update: function (messageUpdate) {
+	            // Append
+	            this._append(messageUpdate);
+
+	            // Update the hash
+	            this._process();
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Finalizes the hash computation.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
+	         *
+	         * @return {WordArray} The hash.
+	         *
+	         * @example
+	         *
+	         *     var hash = hasher.finalize();
+	         *     var hash = hasher.finalize('message');
+	         *     var hash = hasher.finalize(wordArray);
+	         */
+	        finalize: function (messageUpdate) {
+	            // Final message update
+	            if (messageUpdate) {
+	                this._append(messageUpdate);
+	            }
+
+	            // Perform concrete-hasher logic
+	            var hash = this._doFinalize();
+
+	            return hash;
+	        },
+
+	        blockSize: 512/32,
+
+	        /**
+	         * Creates a shortcut function to a hasher's object interface.
+	         *
+	         * @param {Hasher} hasher The hasher to create a helper for.
+	         *
+	         * @return {Function} The shortcut function.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
+	         */
+	        _createHelper: function (hasher) {
+	            return function (message, cfg) {
+	                return new hasher.init(cfg).finalize(message);
+	            };
+	        },
+
+	        /**
+	         * Creates a shortcut function to the HMAC's object interface.
+	         *
+	         * @param {Hasher} hasher The hasher to use in this HMAC helper.
+	         *
+	         * @return {Function} The shortcut function.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
+	         */
+	        _createHmacHelper: function (hasher) {
+	            return function (message, key) {
+	                return new C_algo.HMAC.init(hasher, key).finalize(message);
+	            };
+	        }
+	    });
+
+	    /**
+	     * Algorithm namespace.
+	     */
+	    var C_algo = C.algo = {};
+
+	    return C;
+	}(Math));
+
+
+	(function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var X32WordArray = C_lib.WordArray;
+
+	    /**
+	     * x64 namespace.
+	     */
+	    var C_x64 = C.x64 = {};
+
+	    /**
+	     * A 64-bit word.
+	     */
+	    var X64Word = C_x64.Word = Base.extend({
+	        /**
+	         * Initializes a newly created 64-bit word.
+	         *
+	         * @param {number} high The high 32 bits.
+	         * @param {number} low The low 32 bits.
+	         *
+	         * @example
+	         *
+	         *     var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607);
+	         */
+	        init: function (high, low) {
+	            this.high = high;
+	            this.low = low;
+	        }
+
+	        /**
+	         * Bitwise NOTs this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after negating.
+	         *
+	         * @example
+	         *
+	         *     var negated = x64Word.not();
+	         */
+	        // not: function () {
+	            // var high = ~this.high;
+	            // var low = ~this.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise ANDs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to AND with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after ANDing.
+	         *
+	         * @example
+	         *
+	         *     var anded = x64Word.and(anotherX64Word);
+	         */
+	        // and: function (word) {
+	            // var high = this.high & word.high;
+	            // var low = this.low & word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise ORs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to OR with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after ORing.
+	         *
+	         * @example
+	         *
+	         *     var ored = x64Word.or(anotherX64Word);
+	         */
+	        // or: function (word) {
+	            // var high = this.high | word.high;
+	            // var low = this.low | word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise XORs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to XOR with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after XORing.
+	         *
+	         * @example
+	         *
+	         *     var xored = x64Word.xor(anotherX64Word);
+	         */
+	        // xor: function (word) {
+	            // var high = this.high ^ word.high;
+	            // var low = this.low ^ word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Shifts this word n bits to the left.
+	         *
+	         * @param {number} n The number of bits to shift.
+	         *
+	         * @return {X64Word} A new x64-Word object after shifting.
+	         *
+	         * @example
+	         *
+	         *     var shifted = x64Word.shiftL(25);
+	         */
+	        // shiftL: function (n) {
+	            // if (n < 32) {
+	                // var high = (this.high << n) | (this.low >>> (32 - n));
+	                // var low = this.low << n;
+	            // } else {
+	                // var high = this.low << (n - 32);
+	                // var low = 0;
+	            // }
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Shifts this word n bits to the right.
+	         *
+	         * @param {number} n The number of bits to shift.
+	         *
+	         * @return {X64Word} A new x64-Word object after shifting.
+	         *
+	         * @example
+	         *
+	         *     var shifted = x64Word.shiftR(7);
+	         */
+	        // shiftR: function (n) {
+	            // if (n < 32) {
+	                // var low = (this.low >>> n) | (this.high << (32 - n));
+	                // var high = this.high >>> n;
+	            // } else {
+	                // var low = this.high >>> (n - 32);
+	                // var high = 0;
+	            // }
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Rotates this word n bits to the left.
+	         *
+	         * @param {number} n The number of bits to rotate.
+	         *
+	         * @return {X64Word} A new x64-Word object after rotating.
+	         *
+	         * @example
+	         *
+	         *     var rotated = x64Word.rotL(25);
+	         */
+	        // rotL: function (n) {
+	            // return this.shiftL(n).or(this.shiftR(64 - n));
+	        // },
+
+	        /**
+	         * Rotates this word n bits to the right.
+	         *
+	         * @param {number} n The number of bits to rotate.
+	         *
+	         * @return {X64Word} A new x64-Word object after rotating.
+	         *
+	         * @example
+	         *
+	         *     var rotated = x64Word.rotR(7);
+	         */
+	        // rotR: function (n) {
+	            // return this.shiftR(n).or(this.shiftL(64 - n));
+	        // },
+
+	        /**
+	         * Adds this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to add with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after adding.
+	         *
+	         * @example
+	         *
+	         *     var added = x64Word.add(anotherX64Word);
+	         */
+	        // add: function (word) {
+	            // var low = (this.low + word.low) | 0;
+	            // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0;
+	            // var high = (this.high + word.high + carry) | 0;
+
+	            // return X64Word.create(high, low);
+	        // }
+	    });
+
+	    /**
+	     * An array of 64-bit words.
+	     *
+	     * @property {Array} words The array of CryptoJS.x64.Word objects.
+	     * @property {number} sigBytes The number of significant bytes in this word array.
+	     */
+	    var X64WordArray = C_x64.WordArray = Base.extend({
+	        /**
+	         * Initializes a newly created word array.
+	         *
+	         * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects.
+	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create();
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create([
+	         *         CryptoJS.x64.Word.create(0x00010203, 0x04050607),
+	         *         CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
+	         *     ]);
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create([
+	         *         CryptoJS.x64.Word.create(0x00010203, 0x04050607),
+	         *         CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
+	         *     ], 10);
+	         */
+	        init: function (words, sigBytes) {
+	            words = this.words = words || [];
+
+	            if (sigBytes != undefined) {
+	                this.sigBytes = sigBytes;
+	            } else {
+	                this.sigBytes = words.length * 8;
+	            }
+	        },
+
+	        /**
+	         * Converts this 64-bit word array to a 32-bit word array.
+	         *
+	         * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array.
+	         *
+	         * @example
+	         *
+	         *     var x32WordArray = x64WordArray.toX32();
+	         */
+	        toX32: function () {
+	            // Shortcuts
+	            var x64Words = this.words;
+	            var x64WordsLength = x64Words.length;
+
+	            // Convert
+	            var x32Words = [];
+	            for (var i = 0; i < x64WordsLength; i++) {
+	                var x64Word = x64Words[i];
+	                x32Words.push(x64Word.high);
+	                x32Words.push(x64Word.low);
+	            }
+
+	            return X32WordArray.create(x32Words, this.sigBytes);
+	        },
+
+	        /**
+	         * Creates a copy of this word array.
+	         *
+	         * @return {X64WordArray} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = x64WordArray.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+
+	            // Clone "words" array
+	            var words = clone.words = this.words.slice(0);
+
+	            // Clone each X64Word object
+	            var wordsLength = words.length;
+	            for (var i = 0; i < wordsLength; i++) {
+	                words[i] = words[i].clone();
+	            }
+
+	            return clone;
+	        }
+	    });
+	}());
+
+
+	(function () {
+	    // Check if typed arrays are supported
+	    if (typeof ArrayBuffer != 'function') {
+	        return;
+	    }
+
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+
+	    // Reference original init
+	    var superInit = WordArray.init;
+
+	    // Augment WordArray.init to handle typed arrays
+	    var subInit = WordArray.init = function (typedArray) {
+	        // Convert buffers to uint8
+	        if (typedArray instanceof ArrayBuffer) {
+	            typedArray = new Uint8Array(typedArray);
+	        }
+
+	        // Convert other array views to uint8
+	        if (
+	            typedArray instanceof Int8Array ||
+	            (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) ||
+	            typedArray instanceof Int16Array ||
+	            typedArray instanceof Uint16Array ||
+	            typedArray instanceof Int32Array ||
+	            typedArray instanceof Uint32Array ||
+	            typedArray instanceof Float32Array ||
+	            typedArray instanceof Float64Array
+	        ) {
+	            typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);
+	        }
+
+	        // Handle Uint8Array
+	        if (typedArray instanceof Uint8Array) {
+	            // Shortcut
+	            var typedArrayByteLength = typedArray.byteLength;
+
+	            // Extract bytes
+	            var words = [];
+	            for (var i = 0; i < typedArrayByteLength; i++) {
+	                words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);
+	            }
+
+	            // Initialize this word array
+	            superInit.call(this, words, typedArrayByteLength);
+	        } else {
+	            // Else call normal init
+	            superInit.apply(this, arguments);
+	        }
+	    };
+
+	    subInit.prototype = WordArray;
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_enc = C.enc;
+
+	    /**
+	     * UTF-16 BE encoding strategy.
+	     */
+	    var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = {
+	        /**
+	         * Converts a word array to a UTF-16 BE string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-16 BE string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf16String = CryptoJS.enc.Utf16.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var utf16Chars = [];
+	            for (var i = 0; i < sigBytes; i += 2) {
+	                var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff;
+	                utf16Chars.push(String.fromCharCode(codePoint));
+	            }
+
+	            return utf16Chars.join('');
+	        },
+
+	        /**
+	         * Converts a UTF-16 BE string to a word array.
+	         *
+	         * @param {string} utf16Str The UTF-16 BE string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf16.parse(utf16String);
+	         */
+	        parse: function (utf16Str) {
+	            // Shortcut
+	            var utf16StrLength = utf16Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < utf16StrLength; i++) {
+	                words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16);
+	            }
+
+	            return WordArray.create(words, utf16StrLength * 2);
+	        }
+	    };
+
+	    /**
+	     * UTF-16 LE encoding strategy.
+	     */
+	    C_enc.Utf16LE = {
+	        /**
+	         * Converts a word array to a UTF-16 LE string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-16 LE string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var utf16Chars = [];
+	            for (var i = 0; i < sigBytes; i += 2) {
+	                var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff);
+	                utf16Chars.push(String.fromCharCode(codePoint));
+	            }
+
+	            return utf16Chars.join('');
+	        },
+
+	        /**
+	         * Converts a UTF-16 LE string to a word array.
+	         *
+	         * @param {string} utf16Str The UTF-16 LE string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str);
+	         */
+	        parse: function (utf16Str) {
+	            // Shortcut
+	            var utf16StrLength = utf16Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < utf16StrLength; i++) {
+	                words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16));
+	            }
+
+	            return WordArray.create(words, utf16StrLength * 2);
+	        }
+	    };
+
+	    function swapEndian(word) {
+	        return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff);
+	    }
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_enc = C.enc;
+
+	    /**
+	     * Base64 encoding strategy.
+	     */
+	    var Base64 = C_enc.Base64 = {
+	        /**
+	         * Converts a word array to a Base64 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The Base64 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var base64String = CryptoJS.enc.Base64.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+	            var map = this._map;
+
+	            // Clamp excess bits
+	            wordArray.clamp();
+
+	            // Convert
+	            var base64Chars = [];
+	            for (var i = 0; i < sigBytes; i += 3) {
+	                var byte1 = (words[i >>> 2]       >>> (24 - (i % 4) * 8))       & 0xff;
+	                var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;
+	                var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;
+
+	                var triplet = (byte1 << 16) | (byte2 << 8) | byte3;
+
+	                for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {
+	                    base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));
+	                }
+	            }
+
+	            // Add padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                while (base64Chars.length % 4) {
+	                    base64Chars.push(paddingChar);
+	                }
+	            }
+
+	            return base64Chars.join('');
+	        },
+
+	        /**
+	         * Converts a Base64 string to a word array.
+	         *
+	         * @param {string} base64Str The Base64 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Base64.parse(base64String);
+	         */
+	        parse: function (base64Str) {
+	            // Shortcuts
+	            var base64StrLength = base64Str.length;
+	            var map = this._map;
+	            var reverseMap = this._reverseMap;
+
+	            if (!reverseMap) {
+	                    reverseMap = this._reverseMap = [];
+	                    for (var j = 0; j < map.length; j++) {
+	                        reverseMap[map.charCodeAt(j)] = j;
+	                    }
+	            }
+
+	            // Ignore padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                var paddingIndex = base64Str.indexOf(paddingChar);
+	                if (paddingIndex !== -1) {
+	                    base64StrLength = paddingIndex;
+	                }
+	            }
+
+	            // Convert
+	            return parseLoop(base64Str, base64StrLength, reverseMap);
+
+	        },
+
+	        _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
+	    };
+
+	    function parseLoop(base64Str, base64StrLength, reverseMap) {
+	      var words = [];
+	      var nBytes = 0;
+	      for (var i = 0; i < base64StrLength; i++) {
+	          if (i % 4) {
+	              var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);
+	              var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);
+	              var bitsCombined = bits1 | bits2;
+	              words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8);
+	              nBytes++;
+	          }
+	      }
+	      return WordArray.create(words, nBytes);
+	    }
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_enc = C.enc;
+
+	    /**
+	     * Base64url encoding strategy.
+	     */
+	    var Base64url = C_enc.Base64url = {
+	        /**
+	         * Converts a word array to a Base64url string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @param {boolean} urlSafe Whether to use url safe
+	         *
+	         * @return {string} The Base64url string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var base64String = CryptoJS.enc.Base64url.stringify(wordArray);
+	         */
+	        stringify: function (wordArray, urlSafe=true) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+	            var map = urlSafe ? this._safe_map : this._map;
+
+	            // Clamp excess bits
+	            wordArray.clamp();
+
+	            // Convert
+	            var base64Chars = [];
+	            for (var i = 0; i < sigBytes; i += 3) {
+	                var byte1 = (words[i >>> 2]       >>> (24 - (i % 4) * 8))       & 0xff;
+	                var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;
+	                var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;
+
+	                var triplet = (byte1 << 16) | (byte2 << 8) | byte3;
+
+	                for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {
+	                    base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));
+	                }
+	            }
+
+	            // Add padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                while (base64Chars.length % 4) {
+	                    base64Chars.push(paddingChar);
+	                }
+	            }
+
+	            return base64Chars.join('');
+	        },
+
+	        /**
+	         * Converts a Base64url string to a word array.
+	         *
+	         * @param {string} base64Str The Base64url string.
+	         *
+	         * @param {boolean} urlSafe Whether to use url safe
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Base64url.parse(base64String);
+	         */
+	        parse: function (base64Str, urlSafe=true) {
+	            // Shortcuts
+	            var base64StrLength = base64Str.length;
+	            var map = urlSafe ? this._safe_map : this._map;
+	            var reverseMap = this._reverseMap;
+
+	            if (!reverseMap) {
+	                reverseMap = this._reverseMap = [];
+	                for (var j = 0; j < map.length; j++) {
+	                    reverseMap[map.charCodeAt(j)] = j;
+	                }
+	            }
+
+	            // Ignore padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                var paddingIndex = base64Str.indexOf(paddingChar);
+	                if (paddingIndex !== -1) {
+	                    base64StrLength = paddingIndex;
+	                }
+	            }
+
+	            // Convert
+	            return parseLoop(base64Str, base64StrLength, reverseMap);
+
+	        },
+
+	        _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
+	        _safe_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
+	    };
+
+	    function parseLoop(base64Str, base64StrLength, reverseMap) {
+	        var words = [];
+	        var nBytes = 0;
+	        for (var i = 0; i < base64StrLength; i++) {
+	            if (i % 4) {
+	                var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);
+	                var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);
+	                var bitsCombined = bits1 | bits2;
+	                words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8);
+	                nBytes++;
+	            }
+	        }
+	        return WordArray.create(words, nBytes);
+	    }
+	}());
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Constants table
+	    var T = [];
+
+	    // Compute constants
+	    (function () {
+	        for (var i = 0; i < 64; i++) {
+	            T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
+	        }
+	    }());
+
+	    /**
+	     * MD5 hash algorithm.
+	     */
+	    var MD5 = C_algo.MD5 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0x67452301, 0xefcdab89,
+	                0x98badcfe, 0x10325476
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Swap endian
+	            for (var i = 0; i < 16; i++) {
+	                // Shortcuts
+	                var offset_i = offset + i;
+	                var M_offset_i = M[offset_i];
+
+	                M[offset_i] = (
+	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
+	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
+	                );
+	            }
+
+	            // Shortcuts
+	            var H = this._hash.words;
+
+	            var M_offset_0  = M[offset + 0];
+	            var M_offset_1  = M[offset + 1];
+	            var M_offset_2  = M[offset + 2];
+	            var M_offset_3  = M[offset + 3];
+	            var M_offset_4  = M[offset + 4];
+	            var M_offset_5  = M[offset + 5];
+	            var M_offset_6  = M[offset + 6];
+	            var M_offset_7  = M[offset + 7];
+	            var M_offset_8  = M[offset + 8];
+	            var M_offset_9  = M[offset + 9];
+	            var M_offset_10 = M[offset + 10];
+	            var M_offset_11 = M[offset + 11];
+	            var M_offset_12 = M[offset + 12];
+	            var M_offset_13 = M[offset + 13];
+	            var M_offset_14 = M[offset + 14];
+	            var M_offset_15 = M[offset + 15];
+
+	            // Working varialbes
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+
+	            // Computation
+	            a = FF(a, b, c, d, M_offset_0,  7,  T[0]);
+	            d = FF(d, a, b, c, M_offset_1,  12, T[1]);
+	            c = FF(c, d, a, b, M_offset_2,  17, T[2]);
+	            b = FF(b, c, d, a, M_offset_3,  22, T[3]);
+	            a = FF(a, b, c, d, M_offset_4,  7,  T[4]);
+	            d = FF(d, a, b, c, M_offset_5,  12, T[5]);
+	            c = FF(c, d, a, b, M_offset_6,  17, T[6]);
+	            b = FF(b, c, d, a, M_offset_7,  22, T[7]);
+	            a = FF(a, b, c, d, M_offset_8,  7,  T[8]);
+	            d = FF(d, a, b, c, M_offset_9,  12, T[9]);
+	            c = FF(c, d, a, b, M_offset_10, 17, T[10]);
+	            b = FF(b, c, d, a, M_offset_11, 22, T[11]);
+	            a = FF(a, b, c, d, M_offset_12, 7,  T[12]);
+	            d = FF(d, a, b, c, M_offset_13, 12, T[13]);
+	            c = FF(c, d, a, b, M_offset_14, 17, T[14]);
+	            b = FF(b, c, d, a, M_offset_15, 22, T[15]);
+
+	            a = GG(a, b, c, d, M_offset_1,  5,  T[16]);
+	            d = GG(d, a, b, c, M_offset_6,  9,  T[17]);
+	            c = GG(c, d, a, b, M_offset_11, 14, T[18]);
+	            b = GG(b, c, d, a, M_offset_0,  20, T[19]);
+	            a = GG(a, b, c, d, M_offset_5,  5,  T[20]);
+	            d = GG(d, a, b, c, M_offset_10, 9,  T[21]);
+	            c = GG(c, d, a, b, M_offset_15, 14, T[22]);
+	            b = GG(b, c, d, a, M_offset_4,  20, T[23]);
+	            a = GG(a, b, c, d, M_offset_9,  5,  T[24]);
+	            d = GG(d, a, b, c, M_offset_14, 9,  T[25]);
+	            c = GG(c, d, a, b, M_offset_3,  14, T[26]);
+	            b = GG(b, c, d, a, M_offset_8,  20, T[27]);
+	            a = GG(a, b, c, d, M_offset_13, 5,  T[28]);
+	            d = GG(d, a, b, c, M_offset_2,  9,  T[29]);
+	            c = GG(c, d, a, b, M_offset_7,  14, T[30]);
+	            b = GG(b, c, d, a, M_offset_12, 20, T[31]);
+
+	            a = HH(a, b, c, d, M_offset_5,  4,  T[32]);
+	            d = HH(d, a, b, c, M_offset_8,  11, T[33]);
+	            c = HH(c, d, a, b, M_offset_11, 16, T[34]);
+	            b = HH(b, c, d, a, M_offset_14, 23, T[35]);
+	            a = HH(a, b, c, d, M_offset_1,  4,  T[36]);
+	            d = HH(d, a, b, c, M_offset_4,  11, T[37]);
+	            c = HH(c, d, a, b, M_offset_7,  16, T[38]);
+	            b = HH(b, c, d, a, M_offset_10, 23, T[39]);
+	            a = HH(a, b, c, d, M_offset_13, 4,  T[40]);
+	            d = HH(d, a, b, c, M_offset_0,  11, T[41]);
+	            c = HH(c, d, a, b, M_offset_3,  16, T[42]);
+	            b = HH(b, c, d, a, M_offset_6,  23, T[43]);
+	            a = HH(a, b, c, d, M_offset_9,  4,  T[44]);
+	            d = HH(d, a, b, c, M_offset_12, 11, T[45]);
+	            c = HH(c, d, a, b, M_offset_15, 16, T[46]);
+	            b = HH(b, c, d, a, M_offset_2,  23, T[47]);
+
+	            a = II(a, b, c, d, M_offset_0,  6,  T[48]);
+	            d = II(d, a, b, c, M_offset_7,  10, T[49]);
+	            c = II(c, d, a, b, M_offset_14, 15, T[50]);
+	            b = II(b, c, d, a, M_offset_5,  21, T[51]);
+	            a = II(a, b, c, d, M_offset_12, 6,  T[52]);
+	            d = II(d, a, b, c, M_offset_3,  10, T[53]);
+	            c = II(c, d, a, b, M_offset_10, 15, T[54]);
+	            b = II(b, c, d, a, M_offset_1,  21, T[55]);
+	            a = II(a, b, c, d, M_offset_8,  6,  T[56]);
+	            d = II(d, a, b, c, M_offset_15, 10, T[57]);
+	            c = II(c, d, a, b, M_offset_6,  15, T[58]);
+	            b = II(b, c, d, a, M_offset_13, 21, T[59]);
+	            a = II(a, b, c, d, M_offset_4,  6,  T[60]);
+	            d = II(d, a, b, c, M_offset_11, 10, T[61]);
+	            c = II(c, d, a, b, M_offset_2,  15, T[62]);
+	            b = II(b, c, d, a, M_offset_9,  21, T[63]);
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+
+	            var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
+	            var nBitsTotalL = nBitsTotal;
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
+	                (((nBitsTotalH << 8)  | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotalH << 24) | (nBitsTotalH >>> 8))  & 0xff00ff00)
+	            );
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
+	                (((nBitsTotalL << 8)  | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotalL << 24) | (nBitsTotalL >>> 8))  & 0xff00ff00)
+	            );
+
+	            data.sigBytes = (dataWords.length + 1) * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var hash = this._hash;
+	            var H = hash.words;
+
+	            // Swap endian
+	            for (var i = 0; i < 4; i++) {
+	                // Shortcut
+	                var H_i = H[i];
+
+	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
+	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    function FF(a, b, c, d, x, s, t) {
+	        var n = a + ((b & c) | (~b & d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function GG(a, b, c, d, x, s, t) {
+	        var n = a + ((b & d) | (c & ~d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function HH(a, b, c, d, x, s, t) {
+	        var n = a + (b ^ c ^ d) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function II(a, b, c, d, x, s, t) {
+	        var n = a + (c ^ (b | ~d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.MD5('message');
+	     *     var hash = CryptoJS.MD5(wordArray);
+	     */
+	    C.MD5 = Hasher._createHelper(MD5);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacMD5(message, key);
+	     */
+	    C.HmacMD5 = Hasher._createHmacHelper(MD5);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Reusable object
+	    var W = [];
+
+	    /**
+	     * SHA-1 hash algorithm.
+	     */
+	    var SHA1 = C_algo.SHA1 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0x67452301, 0xefcdab89,
+	                0x98badcfe, 0x10325476,
+	                0xc3d2e1f0
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var H = this._hash.words;
+
+	            // Working variables
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+	            var e = H[4];
+
+	            // Computation
+	            for (var i = 0; i < 80; i++) {
+	                if (i < 16) {
+	                    W[i] = M[offset + i] | 0;
+	                } else {
+	                    var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
+	                    W[i] = (n << 1) | (n >>> 31);
+	                }
+
+	                var t = ((a << 5) | (a >>> 27)) + e + W[i];
+	                if (i < 20) {
+	                    t += ((b & c) | (~b & d)) + 0x5a827999;
+	                } else if (i < 40) {
+	                    t += (b ^ c ^ d) + 0x6ed9eba1;
+	                } else if (i < 60) {
+	                    t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;
+	                } else /* if (i < 80) */ {
+	                    t += (b ^ c ^ d) - 0x359d3e2a;
+	                }
+
+	                e = d;
+	                d = c;
+	                c = (b << 30) | (b >>> 2);
+	                b = a;
+	                a = t;
+	            }
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	            H[4] = (H[4] + e) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Return final computed hash
+	            return this._hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA1('message');
+	     *     var hash = CryptoJS.SHA1(wordArray);
+	     */
+	    C.SHA1 = Hasher._createHelper(SHA1);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA1(message, key);
+	     */
+	    C.HmacSHA1 = Hasher._createHmacHelper(SHA1);
+	}());
+
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Initialization and round constants tables
+	    var H = [];
+	    var K = [];
+
+	    // Compute constants
+	    (function () {
+	        function isPrime(n) {
+	            var sqrtN = Math.sqrt(n);
+	            for (var factor = 2; factor <= sqrtN; factor++) {
+	                if (!(n % factor)) {
+	                    return false;
+	                }
+	            }
+
+	            return true;
+	        }
+
+	        function getFractionalBits(n) {
+	            return ((n - (n | 0)) * 0x100000000) | 0;
+	        }
+
+	        var n = 2;
+	        var nPrime = 0;
+	        while (nPrime < 64) {
+	            if (isPrime(n)) {
+	                if (nPrime < 8) {
+	                    H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
+	                }
+	                K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));
+
+	                nPrime++;
+	            }
+
+	            n++;
+	        }
+	    }());
+
+	    // Reusable object
+	    var W = [];
+
+	    /**
+	     * SHA-256 hash algorithm.
+	     */
+	    var SHA256 = C_algo.SHA256 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init(H.slice(0));
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var H = this._hash.words;
+
+	            // Working variables
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+	            var e = H[4];
+	            var f = H[5];
+	            var g = H[6];
+	            var h = H[7];
+
+	            // Computation
+	            for (var i = 0; i < 64; i++) {
+	                if (i < 16) {
+	                    W[i] = M[offset + i] | 0;
+	                } else {
+	                    var gamma0x = W[i - 15];
+	                    var gamma0  = ((gamma0x << 25) | (gamma0x >>> 7))  ^
+	                                  ((gamma0x << 14) | (gamma0x >>> 18)) ^
+	                                   (gamma0x >>> 3);
+
+	                    var gamma1x = W[i - 2];
+	                    var gamma1  = ((gamma1x << 15) | (gamma1x >>> 17)) ^
+	                                  ((gamma1x << 13) | (gamma1x >>> 19)) ^
+	                                   (gamma1x >>> 10);
+
+	                    W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
+	                }
+
+	                var ch  = (e & f) ^ (~e & g);
+	                var maj = (a & b) ^ (a & c) ^ (b & c);
+
+	                var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
+	                var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7)  | (e >>> 25));
+
+	                var t1 = h + sigma1 + ch + K[i] + W[i];
+	                var t2 = sigma0 + maj;
+
+	                h = g;
+	                g = f;
+	                f = e;
+	                e = (d + t1) | 0;
+	                d = c;
+	                c = b;
+	                b = a;
+	                a = (t1 + t2) | 0;
+	            }
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	            H[4] = (H[4] + e) | 0;
+	            H[5] = (H[5] + f) | 0;
+	            H[6] = (H[6] + g) | 0;
+	            H[7] = (H[7] + h) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Return final computed hash
+	            return this._hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA256('message');
+	     *     var hash = CryptoJS.SHA256(wordArray);
+	     */
+	    C.SHA256 = Hasher._createHelper(SHA256);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA256(message, key);
+	     */
+	    C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var SHA256 = C_algo.SHA256;
+
+	    /**
+	     * SHA-224 hash algorithm.
+	     */
+	    var SHA224 = C_algo.SHA224 = SHA256.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+	                0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
+	            ]);
+	        },
+
+	        _doFinalize: function () {
+	            var hash = SHA256._doFinalize.call(this);
+
+	            hash.sigBytes -= 4;
+
+	            return hash;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA224('message');
+	     *     var hash = CryptoJS.SHA224(wordArray);
+	     */
+	    C.SHA224 = SHA256._createHelper(SHA224);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA224(message, key);
+	     */
+	    C.HmacSHA224 = SHA256._createHmacHelper(SHA224);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Hasher = C_lib.Hasher;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var X64WordArray = C_x64.WordArray;
+	    var C_algo = C.algo;
+
+	    function X64Word_create() {
+	        return X64Word.create.apply(X64Word, arguments);
+	    }
+
+	    // Constants
+	    var K = [
+	        X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd),
+	        X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc),
+	        X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019),
+	        X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118),
+	        X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe),
+	        X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2),
+	        X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1),
+	        X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694),
+	        X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3),
+	        X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65),
+	        X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483),
+	        X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5),
+	        X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210),
+	        X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4),
+	        X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725),
+	        X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70),
+	        X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926),
+	        X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df),
+	        X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8),
+	        X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b),
+	        X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001),
+	        X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30),
+	        X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910),
+	        X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8),
+	        X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53),
+	        X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8),
+	        X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb),
+	        X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3),
+	        X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60),
+	        X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec),
+	        X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9),
+	        X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b),
+	        X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207),
+	        X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178),
+	        X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6),
+	        X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b),
+	        X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493),
+	        X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c),
+	        X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a),
+	        X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817)
+	    ];
+
+	    // Reusable objects
+	    var W = [];
+	    (function () {
+	        for (var i = 0; i < 80; i++) {
+	            W[i] = X64Word_create();
+	        }
+	    }());
+
+	    /**
+	     * SHA-512 hash algorithm.
+	     */
+	    var SHA512 = C_algo.SHA512 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new X64WordArray.init([
+	                new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b),
+	                new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1),
+	                new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f),
+	                new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179)
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcuts
+	            var H = this._hash.words;
+
+	            var H0 = H[0];
+	            var H1 = H[1];
+	            var H2 = H[2];
+	            var H3 = H[3];
+	            var H4 = H[4];
+	            var H5 = H[5];
+	            var H6 = H[6];
+	            var H7 = H[7];
+
+	            var H0h = H0.high;
+	            var H0l = H0.low;
+	            var H1h = H1.high;
+	            var H1l = H1.low;
+	            var H2h = H2.high;
+	            var H2l = H2.low;
+	            var H3h = H3.high;
+	            var H3l = H3.low;
+	            var H4h = H4.high;
+	            var H4l = H4.low;
+	            var H5h = H5.high;
+	            var H5l = H5.low;
+	            var H6h = H6.high;
+	            var H6l = H6.low;
+	            var H7h = H7.high;
+	            var H7l = H7.low;
+
+	            // Working variables
+	            var ah = H0h;
+	            var al = H0l;
+	            var bh = H1h;
+	            var bl = H1l;
+	            var ch = H2h;
+	            var cl = H2l;
+	            var dh = H3h;
+	            var dl = H3l;
+	            var eh = H4h;
+	            var el = H4l;
+	            var fh = H5h;
+	            var fl = H5l;
+	            var gh = H6h;
+	            var gl = H6l;
+	            var hh = H7h;
+	            var hl = H7l;
+
+	            // Rounds
+	            for (var i = 0; i < 80; i++) {
+	                var Wil;
+	                var Wih;
+
+	                // Shortcut
+	                var Wi = W[i];
+
+	                // Extend message
+	                if (i < 16) {
+	                    Wih = Wi.high = M[offset + i * 2]     | 0;
+	                    Wil = Wi.low  = M[offset + i * 2 + 1] | 0;
+	                } else {
+	                    // Gamma0
+	                    var gamma0x  = W[i - 15];
+	                    var gamma0xh = gamma0x.high;
+	                    var gamma0xl = gamma0x.low;
+	                    var gamma0h  = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7);
+	                    var gamma0l  = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25));
+
+	                    // Gamma1
+	                    var gamma1x  = W[i - 2];
+	                    var gamma1xh = gamma1x.high;
+	                    var gamma1xl = gamma1x.low;
+	                    var gamma1h  = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6);
+	                    var gamma1l  = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26));
+
+	                    // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]
+	                    var Wi7  = W[i - 7];
+	                    var Wi7h = Wi7.high;
+	                    var Wi7l = Wi7.low;
+
+	                    var Wi16  = W[i - 16];
+	                    var Wi16h = Wi16.high;
+	                    var Wi16l = Wi16.low;
+
+	                    Wil = gamma0l + Wi7l;
+	                    Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0);
+	                    Wil = Wil + gamma1l;
+	                    Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0);
+	                    Wil = Wil + Wi16l;
+	                    Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0);
+
+	                    Wi.high = Wih;
+	                    Wi.low  = Wil;
+	                }
+
+	                var chh  = (eh & fh) ^ (~eh & gh);
+	                var chl  = (el & fl) ^ (~el & gl);
+	                var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);
+	                var majl = (al & bl) ^ (al & cl) ^ (bl & cl);
+
+	                var sigma0h = ((ah >>> 28) | (al << 4))  ^ ((ah << 30)  | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));
+	                var sigma0l = ((al >>> 28) | (ah << 4))  ^ ((al << 30)  | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));
+	                var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9));
+	                var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9));
+
+	                // t1 = h + sigma1 + ch + K[i] + W[i]
+	                var Ki  = K[i];
+	                var Kih = Ki.high;
+	                var Kil = Ki.low;
+
+	                var t1l = hl + sigma1l;
+	                var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);
+	                var t1l = t1l + chl;
+	                var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
+	                var t1l = t1l + Kil;
+	                var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0);
+	                var t1l = t1l + Wil;
+	                var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0);
+
+	                // t2 = sigma0 + maj
+	                var t2l = sigma0l + majl;
+	                var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);
+
+	                // Update working variables
+	                hh = gh;
+	                hl = gl;
+	                gh = fh;
+	                gl = fl;
+	                fh = eh;
+	                fl = el;
+	                el = (dl + t1l) | 0;
+	                eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+	                dh = ch;
+	                dl = cl;
+	                ch = bh;
+	                cl = bl;
+	                bh = ah;
+	                bl = al;
+	                al = (t1l + t2l) | 0;
+	                ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;
+	            }
+
+	            // Intermediate hash value
+	            H0l = H0.low  = (H0l + al);
+	            H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0));
+	            H1l = H1.low  = (H1l + bl);
+	            H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0));
+	            H2l = H2.low  = (H2l + cl);
+	            H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0));
+	            H3l = H3.low  = (H3l + dl);
+	            H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0));
+	            H4l = H4.low  = (H4l + el);
+	            H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0));
+	            H5l = H5.low  = (H5l + fl);
+	            H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0));
+	            H6l = H6.low  = (H6l + gl);
+	            H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0));
+	            H7l = H7.low  = (H7l + hl);
+	            H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0));
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Convert hash to 32-bit word array before returning
+	            var hash = this._hash.toX32();
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        },
+
+	        blockSize: 1024/32
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA512('message');
+	     *     var hash = CryptoJS.SHA512(wordArray);
+	     */
+	    C.SHA512 = Hasher._createHelper(SHA512);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA512(message, key);
+	     */
+	    C.HmacSHA512 = Hasher._createHmacHelper(SHA512);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var X64WordArray = C_x64.WordArray;
+	    var C_algo = C.algo;
+	    var SHA512 = C_algo.SHA512;
+
+	    /**
+	     * SHA-384 hash algorithm.
+	     */
+	    var SHA384 = C_algo.SHA384 = SHA512.extend({
+	        _doReset: function () {
+	            this._hash = new X64WordArray.init([
+	                new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507),
+	                new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939),
+	                new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511),
+	                new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4)
+	            ]);
+	        },
+
+	        _doFinalize: function () {
+	            var hash = SHA512._doFinalize.call(this);
+
+	            hash.sigBytes -= 16;
+
+	            return hash;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA384('message');
+	     *     var hash = CryptoJS.SHA384(wordArray);
+	     */
+	    C.SHA384 = SHA512._createHelper(SHA384);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA384(message, key);
+	     */
+	    C.HmacSHA384 = SHA512._createHmacHelper(SHA384);
+	}());
+
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var C_algo = C.algo;
+
+	    // Constants tables
+	    var RHO_OFFSETS = [];
+	    var PI_INDEXES  = [];
+	    var ROUND_CONSTANTS = [];
+
+	    // Compute Constants
+	    (function () {
+	        // Compute rho offset constants
+	        var x = 1, y = 0;
+	        for (var t = 0; t < 24; t++) {
+	            RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64;
+
+	            var newX = y % 5;
+	            var newY = (2 * x + 3 * y) % 5;
+	            x = newX;
+	            y = newY;
+	        }
+
+	        // Compute pi index constants
+	        for (var x = 0; x < 5; x++) {
+	            for (var y = 0; y < 5; y++) {
+	                PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5;
+	            }
+	        }
+
+	        // Compute round constants
+	        var LFSR = 0x01;
+	        for (var i = 0; i < 24; i++) {
+	            var roundConstantMsw = 0;
+	            var roundConstantLsw = 0;
+
+	            for (var j = 0; j < 7; j++) {
+	                if (LFSR & 0x01) {
+	                    var bitPosition = (1 << j) - 1;
+	                    if (bitPosition < 32) {
+	                        roundConstantLsw ^= 1 << bitPosition;
+	                    } else /* if (bitPosition >= 32) */ {
+	                        roundConstantMsw ^= 1 << (bitPosition - 32);
+	                    }
+	                }
+
+	                // Compute next LFSR
+	                if (LFSR & 0x80) {
+	                    // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1
+	                    LFSR = (LFSR << 1) ^ 0x71;
+	                } else {
+	                    LFSR <<= 1;
+	                }
+	            }
+
+	            ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw);
+	        }
+	    }());
+
+	    // Reusable objects for temporary values
+	    var T = [];
+	    (function () {
+	        for (var i = 0; i < 25; i++) {
+	            T[i] = X64Word.create();
+	        }
+	    }());
+
+	    /**
+	     * SHA-3 hash algorithm.
+	     */
+	    var SHA3 = C_algo.SHA3 = Hasher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} outputLength
+	         *   The desired number of bits in the output hash.
+	         *   Only values permitted are: 224, 256, 384, 512.
+	         *   Default: 512
+	         */
+	        cfg: Hasher.cfg.extend({
+	            outputLength: 512
+	        }),
+
+	        _doReset: function () {
+	            var state = this._state = []
+	            for (var i = 0; i < 25; i++) {
+	                state[i] = new X64Word.init();
+	            }
+
+	            this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32;
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcuts
+	            var state = this._state;
+	            var nBlockSizeLanes = this.blockSize / 2;
+
+	            // Absorb
+	            for (var i = 0; i < nBlockSizeLanes; i++) {
+	                // Shortcuts
+	                var M2i  = M[offset + 2 * i];
+	                var M2i1 = M[offset + 2 * i + 1];
+
+	                // Swap endian
+	                M2i = (
+	                    (((M2i << 8)  | (M2i >>> 24)) & 0x00ff00ff) |
+	                    (((M2i << 24) | (M2i >>> 8))  & 0xff00ff00)
+	                );
+	                M2i1 = (
+	                    (((M2i1 << 8)  | (M2i1 >>> 24)) & 0x00ff00ff) |
+	                    (((M2i1 << 24) | (M2i1 >>> 8))  & 0xff00ff00)
+	                );
+
+	                // Absorb message into state
+	                var lane = state[i];
+	                lane.high ^= M2i1;
+	                lane.low  ^= M2i;
+	            }
+
+	            // Rounds
+	            for (var round = 0; round < 24; round++) {
+	                // Theta
+	                for (var x = 0; x < 5; x++) {
+	                    // Mix column lanes
+	                    var tMsw = 0, tLsw = 0;
+	                    for (var y = 0; y < 5; y++) {
+	                        var lane = state[x + 5 * y];
+	                        tMsw ^= lane.high;
+	                        tLsw ^= lane.low;
+	                    }
+
+	                    // Temporary values
+	                    var Tx = T[x];
+	                    Tx.high = tMsw;
+	                    Tx.low  = tLsw;
+	                }
+	                for (var x = 0; x < 5; x++) {
+	                    // Shortcuts
+	                    var Tx4 = T[(x + 4) % 5];
+	                    var Tx1 = T[(x + 1) % 5];
+	                    var Tx1Msw = Tx1.high;
+	                    var Tx1Lsw = Tx1.low;
+
+	                    // Mix surrounding columns
+	                    var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));
+	                    var tLsw = Tx4.low  ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));
+	                    for (var y = 0; y < 5; y++) {
+	                        var lane = state[x + 5 * y];
+	                        lane.high ^= tMsw;
+	                        lane.low  ^= tLsw;
+	                    }
+	                }
+
+	                // Rho Pi
+	                for (var laneIndex = 1; laneIndex < 25; laneIndex++) {
+	                    var tMsw;
+	                    var tLsw;
+
+	                    // Shortcuts
+	                    var lane = state[laneIndex];
+	                    var laneMsw = lane.high;
+	                    var laneLsw = lane.low;
+	                    var rhoOffset = RHO_OFFSETS[laneIndex];
+
+	                    // Rotate lanes
+	                    if (rhoOffset < 32) {
+	                        tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));
+	                        tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));
+	                    } else /* if (rhoOffset >= 32) */ {
+	                        tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));
+	                        tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));
+	                    }
+
+	                    // Transpose lanes
+	                    var TPiLane = T[PI_INDEXES[laneIndex]];
+	                    TPiLane.high = tMsw;
+	                    TPiLane.low  = tLsw;
+	                }
+
+	                // Rho pi at x = y = 0
+	                var T0 = T[0];
+	                var state0 = state[0];
+	                T0.high = state0.high;
+	                T0.low  = state0.low;
+
+	                // Chi
+	                for (var x = 0; x < 5; x++) {
+	                    for (var y = 0; y < 5; y++) {
+	                        // Shortcuts
+	                        var laneIndex = x + 5 * y;
+	                        var lane = state[laneIndex];
+	                        var TLane = T[laneIndex];
+	                        var Tx1Lane = T[((x + 1) % 5) + 5 * y];
+	                        var Tx2Lane = T[((x + 2) % 5) + 5 * y];
+
+	                        // Mix rows
+	                        lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);
+	                        lane.low  = TLane.low  ^ (~Tx1Lane.low  & Tx2Lane.low);
+	                    }
+	                }
+
+	                // Iota
+	                var lane = state[0];
+	                var roundConstant = ROUND_CONSTANTS[round];
+	                lane.high ^= roundConstant.high;
+	                lane.low  ^= roundConstant.low;
+	            }
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+	            var blockSizeBits = this.blockSize * 32;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32);
+	            dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var state = this._state;
+	            var outputLengthBytes = this.cfg.outputLength / 8;
+	            var outputLengthLanes = outputLengthBytes / 8;
+
+	            // Squeeze
+	            var hashWords = [];
+	            for (var i = 0; i < outputLengthLanes; i++) {
+	                // Shortcuts
+	                var lane = state[i];
+	                var laneMsw = lane.high;
+	                var laneLsw = lane.low;
+
+	                // Swap endian
+	                laneMsw = (
+	                    (((laneMsw << 8)  | (laneMsw >>> 24)) & 0x00ff00ff) |
+	                    (((laneMsw << 24) | (laneMsw >>> 8))  & 0xff00ff00)
+	                );
+	                laneLsw = (
+	                    (((laneLsw << 8)  | (laneLsw >>> 24)) & 0x00ff00ff) |
+	                    (((laneLsw << 24) | (laneLsw >>> 8))  & 0xff00ff00)
+	                );
+
+	                // Squeeze state to retrieve hash
+	                hashWords.push(laneLsw);
+	                hashWords.push(laneMsw);
+	            }
+
+	            // Return final computed hash
+	            return new WordArray.init(hashWords, outputLengthBytes);
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+
+	            var state = clone._state = this._state.slice(0);
+	            for (var i = 0; i < 25; i++) {
+	                state[i] = state[i].clone();
+	            }
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA3('message');
+	     *     var hash = CryptoJS.SHA3(wordArray);
+	     */
+	    C.SHA3 = Hasher._createHelper(SHA3);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA3(message, key);
+	     */
+	    C.HmacSHA3 = Hasher._createHmacHelper(SHA3);
+	}(Math));
+
+
+	/** @preserve
+	(c) 2012 by Cédric Mesnil. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+	    - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+	    - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+	*/
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Constants table
+	    var _zl = WordArray.create([
+	        0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	        7,  4, 13,  1, 10,  6, 15,  3, 12,  0,  9,  5,  2, 14, 11,  8,
+	        3, 10, 14,  4,  9, 15,  8,  1,  2,  7,  0,  6, 13, 11,  5, 12,
+	        1,  9, 11, 10,  0,  8, 12,  4, 13,  3,  7, 15, 14,  5,  6,  2,
+	        4,  0,  5,  9,  7, 12,  2, 10, 14,  1,  3,  8, 11,  6, 15, 13]);
+	    var _zr = WordArray.create([
+	        5, 14,  7,  0,  9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
+	        6, 11,  3,  7,  0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
+	        15,  5,  1,  3,  7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
+	        8,  6,  4,  1,  3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
+	        12, 15, 10,  4,  1,  5,  8,  7,  6,  2, 13, 14,  0,  3,  9, 11]);
+	    var _sl = WordArray.create([
+	         11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
+	        7, 6,   8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
+	        11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
+	          11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
+	        9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6 ]);
+	    var _sr = WordArray.create([
+	        8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
+	        9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
+	        9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
+	        15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
+	        8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11 ]);
+
+	    var _hl =  WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]);
+	    var _hr =  WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]);
+
+	    /**
+	     * RIPEMD160 hash algorithm.
+	     */
+	    var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash  = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+
+	            // Swap endian
+	            for (var i = 0; i < 16; i++) {
+	                // Shortcuts
+	                var offset_i = offset + i;
+	                var M_offset_i = M[offset_i];
+
+	                // Swap
+	                M[offset_i] = (
+	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
+	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
+	                );
+	            }
+	            // Shortcut
+	            var H  = this._hash.words;
+	            var hl = _hl.words;
+	            var hr = _hr.words;
+	            var zl = _zl.words;
+	            var zr = _zr.words;
+	            var sl = _sl.words;
+	            var sr = _sr.words;
+
+	            // Working variables
+	            var al, bl, cl, dl, el;
+	            var ar, br, cr, dr, er;
+
+	            ar = al = H[0];
+	            br = bl = H[1];
+	            cr = cl = H[2];
+	            dr = dl = H[3];
+	            er = el = H[4];
+	            // Computation
+	            var t;
+	            for (var i = 0; i < 80; i += 1) {
+	                t = (al +  M[offset+zl[i]])|0;
+	                if (i<16){
+		            t +=  f1(bl,cl,dl) + hl[0];
+	                } else if (i<32) {
+		            t +=  f2(bl,cl,dl) + hl[1];
+	                } else if (i<48) {
+		            t +=  f3(bl,cl,dl) + hl[2];
+	                } else if (i<64) {
+		            t +=  f4(bl,cl,dl) + hl[3];
+	                } else {// if (i<80) {
+		            t +=  f5(bl,cl,dl) + hl[4];
+	                }
+	                t = t|0;
+	                t =  rotl(t,sl[i]);
+	                t = (t+el)|0;
+	                al = el;
+	                el = dl;
+	                dl = rotl(cl, 10);
+	                cl = bl;
+	                bl = t;
+
+	                t = (ar + M[offset+zr[i]])|0;
+	                if (i<16){
+		            t +=  f5(br,cr,dr) + hr[0];
+	                } else if (i<32) {
+		            t +=  f4(br,cr,dr) + hr[1];
+	                } else if (i<48) {
+		            t +=  f3(br,cr,dr) + hr[2];
+	                } else if (i<64) {
+		            t +=  f2(br,cr,dr) + hr[3];
+	                } else {// if (i<80) {
+		            t +=  f1(br,cr,dr) + hr[4];
+	                }
+	                t = t|0;
+	                t =  rotl(t,sr[i]) ;
+	                t = (t+er)|0;
+	                ar = er;
+	                er = dr;
+	                dr = rotl(cr, 10);
+	                cr = br;
+	                br = t;
+	            }
+	            // Intermediate hash value
+	            t    = (H[1] + cl + dr)|0;
+	            H[1] = (H[2] + dl + er)|0;
+	            H[2] = (H[3] + el + ar)|0;
+	            H[3] = (H[4] + al + br)|0;
+	            H[4] = (H[0] + bl + cr)|0;
+	            H[0] =  t;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
+	                (((nBitsTotal << 8)  | (nBitsTotal >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotal << 24) | (nBitsTotal >>> 8))  & 0xff00ff00)
+	            );
+	            data.sigBytes = (dataWords.length + 1) * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var hash = this._hash;
+	            var H = hash.words;
+
+	            // Swap endian
+	            for (var i = 0; i < 5; i++) {
+	                // Shortcut
+	                var H_i = H[i];
+
+	                // Swap
+	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
+	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+
+	    function f1(x, y, z) {
+	        return ((x) ^ (y) ^ (z));
+
+	    }
+
+	    function f2(x, y, z) {
+	        return (((x)&(y)) | ((~x)&(z)));
+	    }
+
+	    function f3(x, y, z) {
+	        return (((x) | (~(y))) ^ (z));
+	    }
+
+	    function f4(x, y, z) {
+	        return (((x) & (z)) | ((y)&(~(z))));
+	    }
+
+	    function f5(x, y, z) {
+	        return ((x) ^ ((y) |(~(z))));
+
+	    }
+
+	    function rotl(x,n) {
+	        return (x<<n) | (x>>>(32-n));
+	    }
+
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.RIPEMD160('message');
+	     *     var hash = CryptoJS.RIPEMD160(wordArray);
+	     */
+	    C.RIPEMD160 = Hasher._createHelper(RIPEMD160);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacRIPEMD160(message, key);
+	     */
+	    C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var C_enc = C.enc;
+	    var Utf8 = C_enc.Utf8;
+	    var C_algo = C.algo;
+
+	    /**
+	     * HMAC algorithm.
+	     */
+	    var HMAC = C_algo.HMAC = Base.extend({
+	        /**
+	         * Initializes a newly created HMAC.
+	         *
+	         * @param {Hasher} hasher The hash algorithm to use.
+	         * @param {WordArray|string} key The secret key.
+	         *
+	         * @example
+	         *
+	         *     var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
+	         */
+	        init: function (hasher, key) {
+	            // Init hasher
+	            hasher = this._hasher = new hasher.init();
+
+	            // Convert string to WordArray, else assume WordArray already
+	            if (typeof key == 'string') {
+	                key = Utf8.parse(key);
+	            }
+
+	            // Shortcuts
+	            var hasherBlockSize = hasher.blockSize;
+	            var hasherBlockSizeBytes = hasherBlockSize * 4;
+
+	            // Allow arbitrary length keys
+	            if (key.sigBytes > hasherBlockSizeBytes) {
+	                key = hasher.finalize(key);
+	            }
+
+	            // Clamp excess bits
+	            key.clamp();
+
+	            // Clone key for inner and outer pads
+	            var oKey = this._oKey = key.clone();
+	            var iKey = this._iKey = key.clone();
+
+	            // Shortcuts
+	            var oKeyWords = oKey.words;
+	            var iKeyWords = iKey.words;
+
+	            // XOR keys with pad constants
+	            for (var i = 0; i < hasherBlockSize; i++) {
+	                oKeyWords[i] ^= 0x5c5c5c5c;
+	                iKeyWords[i] ^= 0x36363636;
+	            }
+	            oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this HMAC to its initial state.
+	         *
+	         * @example
+	         *
+	         *     hmacHasher.reset();
+	         */
+	        reset: function () {
+	            // Shortcut
+	            var hasher = this._hasher;
+
+	            // Reset
+	            hasher.reset();
+	            hasher.update(this._iKey);
+	        },
+
+	        /**
+	         * Updates this HMAC with a message.
+	         *
+	         * @param {WordArray|string} messageUpdate The message to append.
+	         *
+	         * @return {HMAC} This HMAC instance.
+	         *
+	         * @example
+	         *
+	         *     hmacHasher.update('message');
+	         *     hmacHasher.update(wordArray);
+	         */
+	        update: function (messageUpdate) {
+	            this._hasher.update(messageUpdate);
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Finalizes the HMAC computation.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
+	         *
+	         * @return {WordArray} The HMAC.
+	         *
+	         * @example
+	         *
+	         *     var hmac = hmacHasher.finalize();
+	         *     var hmac = hmacHasher.finalize('message');
+	         *     var hmac = hmacHasher.finalize(wordArray);
+	         */
+	        finalize: function (messageUpdate) {
+	            // Shortcut
+	            var hasher = this._hasher;
+
+	            // Compute HMAC
+	            var innerHash = hasher.finalize(messageUpdate);
+	            hasher.reset();
+	            var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));
+
+	            return hmac;
+	        }
+	    });
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var SHA1 = C_algo.SHA1;
+	    var HMAC = C_algo.HMAC;
+
+	    /**
+	     * Password-Based Key Derivation Function 2 algorithm.
+	     */
+	    var PBKDF2 = C_algo.PBKDF2 = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)
+	         * @property {Hasher} hasher The hasher to use. Default: SHA1
+	         * @property {number} iterations The number of iterations to perform. Default: 1
+	         */
+	        cfg: Base.extend({
+	            keySize: 128/32,
+	            hasher: SHA1,
+	            iterations: 1
+	        }),
+
+	        /**
+	         * Initializes a newly created key derivation function.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for the derivation.
+	         *
+	         * @example
+	         *
+	         *     var kdf = CryptoJS.algo.PBKDF2.create();
+	         *     var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 });
+	         *     var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 });
+	         */
+	        init: function (cfg) {
+	            this.cfg = this.cfg.extend(cfg);
+	        },
+
+	        /**
+	         * Computes the Password-Based Key Derivation Function 2.
+	         *
+	         * @param {WordArray|string} password The password.
+	         * @param {WordArray|string} salt A salt.
+	         *
+	         * @return {WordArray} The derived key.
+	         *
+	         * @example
+	         *
+	         *     var key = kdf.compute(password, salt);
+	         */
+	        compute: function (password, salt) {
+	            // Shortcut
+	            var cfg = this.cfg;
+
+	            // Init HMAC
+	            var hmac = HMAC.create(cfg.hasher, password);
+
+	            // Initial values
+	            var derivedKey = WordArray.create();
+	            var blockIndex = WordArray.create([0x00000001]);
+
+	            // Shortcuts
+	            var derivedKeyWords = derivedKey.words;
+	            var blockIndexWords = blockIndex.words;
+	            var keySize = cfg.keySize;
+	            var iterations = cfg.iterations;
+
+	            // Generate key
+	            while (derivedKeyWords.length < keySize) {
+	                var block = hmac.update(salt).finalize(blockIndex);
+	                hmac.reset();
+
+	                // Shortcuts
+	                var blockWords = block.words;
+	                var blockWordsLength = blockWords.length;
+
+	                // Iterations
+	                var intermediate = block;
+	                for (var i = 1; i < iterations; i++) {
+	                    intermediate = hmac.finalize(intermediate);
+	                    hmac.reset();
+
+	                    // Shortcut
+	                    var intermediateWords = intermediate.words;
+
+	                    // XOR intermediate with block
+	                    for (var j = 0; j < blockWordsLength; j++) {
+	                        blockWords[j] ^= intermediateWords[j];
+	                    }
+	                }
+
+	                derivedKey.concat(block);
+	                blockIndexWords[0]++;
+	            }
+	            derivedKey.sigBytes = keySize * 4;
+
+	            return derivedKey;
+	        }
+	    });
+
+	    /**
+	     * Computes the Password-Based Key Derivation Function 2.
+	     *
+	     * @param {WordArray|string} password The password.
+	     * @param {WordArray|string} salt A salt.
+	     * @param {Object} cfg (Optional) The configuration options to use for this computation.
+	     *
+	     * @return {WordArray} The derived key.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var key = CryptoJS.PBKDF2(password, salt);
+	     *     var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 });
+	     *     var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 });
+	     */
+	    C.PBKDF2 = function (password, salt, cfg) {
+	        return PBKDF2.create(cfg).compute(password, salt);
+	    };
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var MD5 = C_algo.MD5;
+
+	    /**
+	     * This key derivation function is meant to conform with EVP_BytesToKey.
+	     * www.openssl.org/docs/crypto/EVP_BytesToKey.html
+	     */
+	    var EvpKDF = C_algo.EvpKDF = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)
+	         * @property {Hasher} hasher The hash algorithm to use. Default: MD5
+	         * @property {number} iterations The number of iterations to perform. Default: 1
+	         */
+	        cfg: Base.extend({
+	            keySize: 128/32,
+	            hasher: MD5,
+	            iterations: 1
+	        }),
+
+	        /**
+	         * Initializes a newly created key derivation function.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for the derivation.
+	         *
+	         * @example
+	         *
+	         *     var kdf = CryptoJS.algo.EvpKDF.create();
+	         *     var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 });
+	         *     var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 });
+	         */
+	        init: function (cfg) {
+	            this.cfg = this.cfg.extend(cfg);
+	        },
+
+	        /**
+	         * Derives a key from a password.
+	         *
+	         * @param {WordArray|string} password The password.
+	         * @param {WordArray|string} salt A salt.
+	         *
+	         * @return {WordArray} The derived key.
+	         *
+	         * @example
+	         *
+	         *     var key = kdf.compute(password, salt);
+	         */
+	        compute: function (password, salt) {
+	            var block;
+
+	            // Shortcut
+	            var cfg = this.cfg;
+
+	            // Init hasher
+	            var hasher = cfg.hasher.create();
+
+	            // Initial values
+	            var derivedKey = WordArray.create();
+
+	            // Shortcuts
+	            var derivedKeyWords = derivedKey.words;
+	            var keySize = cfg.keySize;
+	            var iterations = cfg.iterations;
+
+	            // Generate key
+	            while (derivedKeyWords.length < keySize) {
+	                if (block) {
+	                    hasher.update(block);
+	                }
+	                block = hasher.update(password).finalize(salt);
+	                hasher.reset();
+
+	                // Iterations
+	                for (var i = 1; i < iterations; i++) {
+	                    block = hasher.finalize(block);
+	                    hasher.reset();
+	                }
+
+	                derivedKey.concat(block);
+	            }
+	            derivedKey.sigBytes = keySize * 4;
+
+	            return derivedKey;
+	        }
+	    });
+
+	    /**
+	     * Derives a key from a password.
+	     *
+	     * @param {WordArray|string} password The password.
+	     * @param {WordArray|string} salt A salt.
+	     * @param {Object} cfg (Optional) The configuration options to use for this computation.
+	     *
+	     * @return {WordArray} The derived key.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var key = CryptoJS.EvpKDF(password, salt);
+	     *     var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 });
+	     *     var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 });
+	     */
+	    C.EvpKDF = function (password, salt, cfg) {
+	        return EvpKDF.create(cfg).compute(password, salt);
+	    };
+	}());
+
+
+	/**
+	 * Cipher core components.
+	 */
+	CryptoJS.lib.Cipher || (function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm;
+	    var C_enc = C.enc;
+	    var Utf8 = C_enc.Utf8;
+	    var Base64 = C_enc.Base64;
+	    var C_algo = C.algo;
+	    var EvpKDF = C_algo.EvpKDF;
+
+	    /**
+	     * Abstract base cipher template.
+	     *
+	     * @property {number} keySize This cipher's key size. Default: 4 (128 bits)
+	     * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits)
+	     * @property {number} _ENC_XFORM_MODE A constant representing encryption mode.
+	     * @property {number} _DEC_XFORM_MODE A constant representing decryption mode.
+	     */
+	    var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {WordArray} iv The IV to use for this operation.
+	         */
+	        cfg: Base.extend(),
+
+	        /**
+	         * Creates this cipher in encryption mode.
+	         *
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {Cipher} A cipher instance.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });
+	         */
+	        createEncryptor: function (key, cfg) {
+	            return this.create(this._ENC_XFORM_MODE, key, cfg);
+	        },
+
+	        /**
+	         * Creates this cipher in decryption mode.
+	         *
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {Cipher} A cipher instance.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });
+	         */
+	        createDecryptor: function (key, cfg) {
+	            return this.create(this._DEC_XFORM_MODE, key, cfg);
+	        },
+
+	        /**
+	         * Initializes a newly created cipher.
+	         *
+	         * @param {number} xformMode Either the encryption or decryption transormation mode constant.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray });
+	         */
+	        init: function (xformMode, key, cfg) {
+	            // Apply config defaults
+	            this.cfg = this.cfg.extend(cfg);
+
+	            // Store transform mode and key
+	            this._xformMode = xformMode;
+	            this._key = key;
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this cipher to its initial state.
+	         *
+	         * @example
+	         *
+	         *     cipher.reset();
+	         */
+	        reset: function () {
+	            // Reset data buffer
+	            BufferedBlockAlgorithm.reset.call(this);
+
+	            // Perform concrete-cipher logic
+	            this._doReset();
+	        },
+
+	        /**
+	         * Adds data to be encrypted or decrypted.
+	         *
+	         * @param {WordArray|string} dataUpdate The data to encrypt or decrypt.
+	         *
+	         * @return {WordArray} The data after processing.
+	         *
+	         * @example
+	         *
+	         *     var encrypted = cipher.process('data');
+	         *     var encrypted = cipher.process(wordArray);
+	         */
+	        process: function (dataUpdate) {
+	            // Append
+	            this._append(dataUpdate);
+
+	            // Process available blocks
+	            return this._process();
+	        },
+
+	        /**
+	         * Finalizes the encryption or decryption process.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt.
+	         *
+	         * @return {WordArray} The data after final processing.
+	         *
+	         * @example
+	         *
+	         *     var encrypted = cipher.finalize();
+	         *     var encrypted = cipher.finalize('data');
+	         *     var encrypted = cipher.finalize(wordArray);
+	         */
+	        finalize: function (dataUpdate) {
+	            // Final data update
+	            if (dataUpdate) {
+	                this._append(dataUpdate);
+	            }
+
+	            // Perform concrete-cipher logic
+	            var finalProcessedData = this._doFinalize();
+
+	            return finalProcessedData;
+	        },
+
+	        keySize: 128/32,
+
+	        ivSize: 128/32,
+
+	        _ENC_XFORM_MODE: 1,
+
+	        _DEC_XFORM_MODE: 2,
+
+	        /**
+	         * Creates shortcut functions to a cipher's object interface.
+	         *
+	         * @param {Cipher} cipher The cipher to create a helper for.
+	         *
+	         * @return {Object} An object with encrypt and decrypt shortcut functions.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);
+	         */
+	        _createHelper: (function () {
+	            function selectCipherStrategy(key) {
+	                if (typeof key == 'string') {
+	                    return PasswordBasedCipher;
+	                } else {
+	                    return SerializableCipher;
+	                }
+	            }
+
+	            return function (cipher) {
+	                return {
+	                    encrypt: function (message, key, cfg) {
+	                        return selectCipherStrategy(key).encrypt(cipher, message, key, cfg);
+	                    },
+
+	                    decrypt: function (ciphertext, key, cfg) {
+	                        return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg);
+	                    }
+	                };
+	            };
+	        }())
+	    });
+
+	    /**
+	     * Abstract base stream cipher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits)
+	     */
+	    var StreamCipher = C_lib.StreamCipher = Cipher.extend({
+	        _doFinalize: function () {
+	            // Process partial blocks
+	            var finalProcessedBlocks = this._process(!!'flush');
+
+	            return finalProcessedBlocks;
+	        },
+
+	        blockSize: 1
+	    });
+
+	    /**
+	     * Mode namespace.
+	     */
+	    var C_mode = C.mode = {};
+
+	    /**
+	     * Abstract base block cipher mode template.
+	     */
+	    var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({
+	        /**
+	         * Creates this mode for encryption.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);
+	         */
+	        createEncryptor: function (cipher, iv) {
+	            return this.Encryptor.create(cipher, iv);
+	        },
+
+	        /**
+	         * Creates this mode for decryption.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);
+	         */
+	        createDecryptor: function (cipher, iv) {
+	            return this.Decryptor.create(cipher, iv);
+	        },
+
+	        /**
+	         * Initializes a newly created mode.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);
+	         */
+	        init: function (cipher, iv) {
+	            this._cipher = cipher;
+	            this._iv = iv;
+	        }
+	    });
+
+	    /**
+	     * Cipher Block Chaining mode.
+	     */
+	    var CBC = C_mode.CBC = (function () {
+	        /**
+	         * Abstract base CBC mode.
+	         */
+	        var CBC = BlockCipherMode.extend();
+
+	        /**
+	         * CBC encryptor.
+	         */
+	        CBC.Encryptor = CBC.extend({
+	            /**
+	             * Processes the data block at offset.
+	             *
+	             * @param {Array} words The data words to operate on.
+	             * @param {number} offset The offset where the block starts.
+	             *
+	             * @example
+	             *
+	             *     mode.processBlock(data.words, offset);
+	             */
+	            processBlock: function (words, offset) {
+	                // Shortcuts
+	                var cipher = this._cipher;
+	                var blockSize = cipher.blockSize;
+
+	                // XOR and encrypt
+	                xorBlock.call(this, words, offset, blockSize);
+	                cipher.encryptBlock(words, offset);
+
+	                // Remember this block to use with next block
+	                this._prevBlock = words.slice(offset, offset + blockSize);
+	            }
+	        });
+
+	        /**
+	         * CBC decryptor.
+	         */
+	        CBC.Decryptor = CBC.extend({
+	            /**
+	             * Processes the data block at offset.
+	             *
+	             * @param {Array} words The data words to operate on.
+	             * @param {number} offset The offset where the block starts.
+	             *
+	             * @example
+	             *
+	             *     mode.processBlock(data.words, offset);
+	             */
+	            processBlock: function (words, offset) {
+	                // Shortcuts
+	                var cipher = this._cipher;
+	                var blockSize = cipher.blockSize;
+
+	                // Remember this block to use with next block
+	                var thisBlock = words.slice(offset, offset + blockSize);
+
+	                // Decrypt and XOR
+	                cipher.decryptBlock(words, offset);
+	                xorBlock.call(this, words, offset, blockSize);
+
+	                // This block becomes the previous block
+	                this._prevBlock = thisBlock;
+	            }
+	        });
+
+	        function xorBlock(words, offset, blockSize) {
+	            var block;
+
+	            // Shortcut
+	            var iv = this._iv;
+
+	            // Choose mixing block
+	            if (iv) {
+	                block = iv;
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            } else {
+	                block = this._prevBlock;
+	            }
+
+	            // XOR blocks
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= block[i];
+	            }
+	        }
+
+	        return CBC;
+	    }());
+
+	    /**
+	     * Padding namespace.
+	     */
+	    var C_pad = C.pad = {};
+
+	    /**
+	     * PKCS #5/7 padding strategy.
+	     */
+	    var Pkcs7 = C_pad.Pkcs7 = {
+	        /**
+	         * Pads data using the algorithm defined in PKCS #5/7.
+	         *
+	         * @param {WordArray} data The data to pad.
+	         * @param {number} blockSize The multiple that the data should be padded to.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     CryptoJS.pad.Pkcs7.pad(wordArray, 4);
+	         */
+	        pad: function (data, blockSize) {
+	            // Shortcut
+	            var blockSizeBytes = blockSize * 4;
+
+	            // Count padding bytes
+	            var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
+
+	            // Create padding word
+	            var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes;
+
+	            // Create padding
+	            var paddingWords = [];
+	            for (var i = 0; i < nPaddingBytes; i += 4) {
+	                paddingWords.push(paddingWord);
+	            }
+	            var padding = WordArray.create(paddingWords, nPaddingBytes);
+
+	            // Add padding
+	            data.concat(padding);
+	        },
+
+	        /**
+	         * Unpads data that had been padded using the algorithm defined in PKCS #5/7.
+	         *
+	         * @param {WordArray} data The data to unpad.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     CryptoJS.pad.Pkcs7.unpad(wordArray);
+	         */
+	        unpad: function (data) {
+	            // Get number of padding bytes from last byte
+	            var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	            // Remove padding
+	            data.sigBytes -= nPaddingBytes;
+	        }
+	    };
+
+	    /**
+	     * Abstract base block cipher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits)
+	     */
+	    var BlockCipher = C_lib.BlockCipher = Cipher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {Mode} mode The block mode to use. Default: CBC
+	         * @property {Padding} padding The padding strategy to use. Default: Pkcs7
+	         */
+	        cfg: Cipher.cfg.extend({
+	            mode: CBC,
+	            padding: Pkcs7
+	        }),
+
+	        reset: function () {
+	            var modeCreator;
+
+	            // Reset cipher
+	            Cipher.reset.call(this);
+
+	            // Shortcuts
+	            var cfg = this.cfg;
+	            var iv = cfg.iv;
+	            var mode = cfg.mode;
+
+	            // Reset block mode
+	            if (this._xformMode == this._ENC_XFORM_MODE) {
+	                modeCreator = mode.createEncryptor;
+	            } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
+	                modeCreator = mode.createDecryptor;
+	                // Keep at least one block in the buffer for unpadding
+	                this._minBufferSize = 1;
+	            }
+
+	            if (this._mode && this._mode.__creator == modeCreator) {
+	                this._mode.init(this, iv && iv.words);
+	            } else {
+	                this._mode = modeCreator.call(mode, this, iv && iv.words);
+	                this._mode.__creator = modeCreator;
+	            }
+	        },
+
+	        _doProcessBlock: function (words, offset) {
+	            this._mode.processBlock(words, offset);
+	        },
+
+	        _doFinalize: function () {
+	            var finalProcessedBlocks;
+
+	            // Shortcut
+	            var padding = this.cfg.padding;
+
+	            // Finalize
+	            if (this._xformMode == this._ENC_XFORM_MODE) {
+	                // Pad data
+	                padding.pad(this._data, this.blockSize);
+
+	                // Process final blocks
+	                finalProcessedBlocks = this._process(!!'flush');
+	            } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
+	                // Process final blocks
+	                finalProcessedBlocks = this._process(!!'flush');
+
+	                // Unpad data
+	                padding.unpad(finalProcessedBlocks);
+	            }
+
+	            return finalProcessedBlocks;
+	        },
+
+	        blockSize: 128/32
+	    });
+
+	    /**
+	     * A collection of cipher parameters.
+	     *
+	     * @property {WordArray} ciphertext The raw ciphertext.
+	     * @property {WordArray} key The key to this ciphertext.
+	     * @property {WordArray} iv The IV used in the ciphering operation.
+	     * @property {WordArray} salt The salt used with a key derivation function.
+	     * @property {Cipher} algorithm The cipher algorithm.
+	     * @property {Mode} mode The block mode used in the ciphering operation.
+	     * @property {Padding} padding The padding scheme used in the ciphering operation.
+	     * @property {number} blockSize The block size of the cipher.
+	     * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string.
+	     */
+	    var CipherParams = C_lib.CipherParams = Base.extend({
+	        /**
+	         * Initializes a newly created cipher params object.
+	         *
+	         * @param {Object} cipherParams An object with any of the possible cipher parameters.
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.lib.CipherParams.create({
+	         *         ciphertext: ciphertextWordArray,
+	         *         key: keyWordArray,
+	         *         iv: ivWordArray,
+	         *         salt: saltWordArray,
+	         *         algorithm: CryptoJS.algo.AES,
+	         *         mode: CryptoJS.mode.CBC,
+	         *         padding: CryptoJS.pad.PKCS7,
+	         *         blockSize: 4,
+	         *         formatter: CryptoJS.format.OpenSSL
+	         *     });
+	         */
+	        init: function (cipherParams) {
+	            this.mixIn(cipherParams);
+	        },
+
+	        /**
+	         * Converts this cipher params object to a string.
+	         *
+	         * @param {Format} formatter (Optional) The formatting strategy to use.
+	         *
+	         * @return {string} The stringified cipher params.
+	         *
+	         * @throws Error If neither the formatter nor the default formatter is set.
+	         *
+	         * @example
+	         *
+	         *     var string = cipherParams + '';
+	         *     var string = cipherParams.toString();
+	         *     var string = cipherParams.toString(CryptoJS.format.OpenSSL);
+	         */
+	        toString: function (formatter) {
+	            return (formatter || this.formatter).stringify(this);
+	        }
+	    });
+
+	    /**
+	     * Format namespace.
+	     */
+	    var C_format = C.format = {};
+
+	    /**
+	     * OpenSSL formatting strategy.
+	     */
+	    var OpenSSLFormatter = C_format.OpenSSL = {
+	        /**
+	         * Converts a cipher params object to an OpenSSL-compatible string.
+	         *
+	         * @param {CipherParams} cipherParams The cipher params object.
+	         *
+	         * @return {string} The OpenSSL-compatible string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);
+	         */
+	        stringify: function (cipherParams) {
+	            var wordArray;
+
+	            // Shortcuts
+	            var ciphertext = cipherParams.ciphertext;
+	            var salt = cipherParams.salt;
+
+	            // Format
+	            if (salt) {
+	                wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
+	            } else {
+	                wordArray = ciphertext;
+	            }
+
+	            return wordArray.toString(Base64);
+	        },
+
+	        /**
+	         * Converts an OpenSSL-compatible string to a cipher params object.
+	         *
+	         * @param {string} openSSLStr The OpenSSL-compatible string.
+	         *
+	         * @return {CipherParams} The cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);
+	         */
+	        parse: function (openSSLStr) {
+	            var salt;
+
+	            // Parse base64
+	            var ciphertext = Base64.parse(openSSLStr);
+
+	            // Shortcut
+	            var ciphertextWords = ciphertext.words;
+
+	            // Test for salt
+	            if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) {
+	                // Extract salt
+	                salt = WordArray.create(ciphertextWords.slice(2, 4));
+
+	                // Remove salt from ciphertext
+	                ciphertextWords.splice(0, 4);
+	                ciphertext.sigBytes -= 16;
+	            }
+
+	            return CipherParams.create({ ciphertext: ciphertext, salt: salt });
+	        }
+	    };
+
+	    /**
+	     * A cipher wrapper that returns ciphertext as a serializable cipher params object.
+	     */
+	    var SerializableCipher = C_lib.SerializableCipher = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL
+	         */
+	        cfg: Base.extend({
+	            format: OpenSSLFormatter
+	        }),
+
+	        /**
+	         * Encrypts a message.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {WordArray|string} message The message to encrypt.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {CipherParams} A cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key);
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv });
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         */
+	        encrypt: function (cipher, message, key, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Encrypt
+	            var encryptor = cipher.createEncryptor(key, cfg);
+	            var ciphertext = encryptor.finalize(message);
+
+	            // Shortcut
+	            var cipherCfg = encryptor.cfg;
+
+	            // Create and return serializable cipher params
+	            return CipherParams.create({
+	                ciphertext: ciphertext,
+	                key: key,
+	                iv: cipherCfg.iv,
+	                algorithm: cipher,
+	                mode: cipherCfg.mode,
+	                padding: cipherCfg.padding,
+	                blockSize: cipher.blockSize,
+	                formatter: cfg.format
+	            });
+	        },
+
+	        /**
+	         * Decrypts serialized ciphertext.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {WordArray} The plaintext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         *     var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         */
+	        decrypt: function (cipher, ciphertext, key, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Convert string to CipherParams
+	            ciphertext = this._parse(ciphertext, cfg.format);
+
+	            // Decrypt
+	            var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext);
+
+	            return plaintext;
+	        },
+
+	        /**
+	         * Converts serialized ciphertext to CipherParams,
+	         * else assumed CipherParams already and returns ciphertext unchanged.
+	         *
+	         * @param {CipherParams|string} ciphertext The ciphertext.
+	         * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext.
+	         *
+	         * @return {CipherParams} The unserialized ciphertext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);
+	         */
+	        _parse: function (ciphertext, format) {
+	            if (typeof ciphertext == 'string') {
+	                return format.parse(ciphertext, this);
+	            } else {
+	                return ciphertext;
+	            }
+	        }
+	    });
+
+	    /**
+	     * Key derivation function namespace.
+	     */
+	    var C_kdf = C.kdf = {};
+
+	    /**
+	     * OpenSSL key derivation function.
+	     */
+	    var OpenSSLKdf = C_kdf.OpenSSL = {
+	        /**
+	         * Derives a key and IV from a password.
+	         *
+	         * @param {string} password The password to derive from.
+	         * @param {number} keySize The size in words of the key to generate.
+	         * @param {number} ivSize The size in words of the IV to generate.
+	         * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.
+	         *
+	         * @return {CipherParams} A cipher params object with the key, IV, and salt.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
+	         *     var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
+	         */
+	        execute: function (password, keySize, ivSize, salt) {
+	            // Generate random salt
+	            if (!salt) {
+	                salt = WordArray.random(64/8);
+	            }
+
+	            // Derive key and IV
+	            var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
+
+	            // Separate key and IV
+	            var iv = WordArray.create(key.words.slice(keySize), ivSize * 4);
+	            key.sigBytes = keySize * 4;
+
+	            // Return params
+	            return CipherParams.create({ key: key, iv: iv, salt: salt });
+	        }
+	    };
+
+	    /**
+	     * A serializable cipher wrapper that derives the key from a password,
+	     * and returns ciphertext as a serializable cipher params object.
+	     */
+	    var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL
+	         */
+	        cfg: SerializableCipher.cfg.extend({
+	            kdf: OpenSSLKdf
+	        }),
+
+	        /**
+	         * Encrypts a message using a password.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {WordArray|string} message The message to encrypt.
+	         * @param {string} password The password.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {CipherParams} A cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password');
+	         *     var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });
+	         */
+	        encrypt: function (cipher, message, password, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Derive key and other params
+	            var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize);
+
+	            // Add IV to config
+	            cfg.iv = derivedParams.iv;
+
+	            // Encrypt
+	            var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg);
+
+	            // Mix in derived params
+	            ciphertext.mixIn(derivedParams);
+
+	            return ciphertext;
+	        },
+
+	        /**
+	         * Decrypts serialized ciphertext using a password.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
+	         * @param {string} password The password.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {WordArray} The plaintext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL });
+	         *     var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL });
+	         */
+	        decrypt: function (cipher, ciphertext, password, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Convert string to CipherParams
+	            ciphertext = this._parse(ciphertext, cfg.format);
+
+	            // Derive key and other params
+	            var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt);
+
+	            // Add IV to config
+	            cfg.iv = derivedParams.iv;
+
+	            // Decrypt
+	            var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg);
+
+	            return plaintext;
+	        }
+	    });
+	}());
+
+
+	/**
+	 * Cipher Feedback block mode.
+	 */
+	CryptoJS.mode.CFB = (function () {
+	    var CFB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    CFB.Encryptor = CFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher;
+	            var blockSize = cipher.blockSize;
+
+	            generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher);
+
+	            // Remember this block to use with next block
+	            this._prevBlock = words.slice(offset, offset + blockSize);
+	        }
+	    });
+
+	    CFB.Decryptor = CFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher;
+	            var blockSize = cipher.blockSize;
+
+	            // Remember this block to use with next block
+	            var thisBlock = words.slice(offset, offset + blockSize);
+
+	            generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher);
+
+	            // This block becomes the previous block
+	            this._prevBlock = thisBlock;
+	        }
+	    });
+
+	    function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) {
+	        var keystream;
+
+	        // Shortcut
+	        var iv = this._iv;
+
+	        // Generate keystream
+	        if (iv) {
+	            keystream = iv.slice(0);
+
+	            // Remove IV for subsequent blocks
+	            this._iv = undefined;
+	        } else {
+	            keystream = this._prevBlock;
+	        }
+	        cipher.encryptBlock(keystream, 0);
+
+	        // Encrypt
+	        for (var i = 0; i < blockSize; i++) {
+	            words[offset + i] ^= keystream[i];
+	        }
+	    }
+
+	    return CFB;
+	}());
+
+
+	/**
+	 * Counter block mode.
+	 */
+	CryptoJS.mode.CTR = (function () {
+	    var CTR = CryptoJS.lib.BlockCipherMode.extend();
+
+	    var Encryptor = CTR.Encryptor = CTR.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var counter = this._counter;
+
+	            // Generate keystream
+	            if (iv) {
+	                counter = this._counter = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+	            var keystream = counter.slice(0);
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Increment counter
+	            counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    CTR.Decryptor = Encryptor;
+
+	    return CTR;
+	}());
+
+
+	/** @preserve
+	 * Counter block mode compatible with  Dr Brian Gladman fileenc.c
+	 * derived from CryptoJS.mode.CTR
+	 * Jan Hruby jhruby.web@gmail.com
+	 */
+	CryptoJS.mode.CTRGladman = (function () {
+	    var CTRGladman = CryptoJS.lib.BlockCipherMode.extend();
+
+		function incWord(word)
+		{
+			if (((word >> 24) & 0xff) === 0xff) { //overflow
+			var b1 = (word >> 16)&0xff;
+			var b2 = (word >> 8)&0xff;
+			var b3 = word & 0xff;
+
+			if (b1 === 0xff) // overflow b1
+			{
+			b1 = 0;
+			if (b2 === 0xff)
+			{
+				b2 = 0;
+				if (b3 === 0xff)
+				{
+					b3 = 0;
+				}
+				else
+				{
+					++b3;
+				}
+			}
+			else
+			{
+				++b2;
+			}
+			}
+			else
+			{
+			++b1;
+			}
+
+			word = 0;
+			word += (b1 << 16);
+			word += (b2 << 8);
+			word += b3;
+			}
+			else
+			{
+			word += (0x01 << 24);
+			}
+			return word;
+		}
+
+		function incCounter(counter)
+		{
+			if ((counter[0] = incWord(counter[0])) === 0)
+			{
+				// encr_data in fileenc.c from  Dr Brian Gladman's counts only with DWORD j < 8
+				counter[1] = incWord(counter[1]);
+			}
+			return counter;
+		}
+
+	    var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var counter = this._counter;
+
+	            // Generate keystream
+	            if (iv) {
+	                counter = this._counter = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+
+				incCounter(counter);
+
+				var keystream = counter.slice(0);
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    CTRGladman.Decryptor = Encryptor;
+
+	    return CTRGladman;
+	}());
+
+
+
+
+	/**
+	 * Output Feedback block mode.
+	 */
+	CryptoJS.mode.OFB = (function () {
+	    var OFB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    var Encryptor = OFB.Encryptor = OFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var keystream = this._keystream;
+
+	            // Generate keystream
+	            if (iv) {
+	                keystream = this._keystream = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    OFB.Decryptor = Encryptor;
+
+	    return OFB;
+	}());
+
+
+	/**
+	 * Electronic Codebook block mode.
+	 */
+	CryptoJS.mode.ECB = (function () {
+	    var ECB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    ECB.Encryptor = ECB.extend({
+	        processBlock: function (words, offset) {
+	            this._cipher.encryptBlock(words, offset);
+	        }
+	    });
+
+	    ECB.Decryptor = ECB.extend({
+	        processBlock: function (words, offset) {
+	            this._cipher.decryptBlock(words, offset);
+	        }
+	    });
+
+	    return ECB;
+	}());
+
+
+	/**
+	 * ANSI X.923 padding strategy.
+	 */
+	CryptoJS.pad.AnsiX923 = {
+	    pad: function (data, blockSize) {
+	        // Shortcuts
+	        var dataSigBytes = data.sigBytes;
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Count padding bytes
+	        var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes;
+
+	        // Compute last byte position
+	        var lastBytePos = dataSigBytes + nPaddingBytes - 1;
+
+	        // Pad
+	        data.clamp();
+	        data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8);
+	        data.sigBytes += nPaddingBytes;
+	    },
+
+	    unpad: function (data) {
+	        // Get number of padding bytes from last byte
+	        var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	        // Remove padding
+	        data.sigBytes -= nPaddingBytes;
+	    }
+	};
+
+
+	/**
+	 * ISO 10126 padding strategy.
+	 */
+	CryptoJS.pad.Iso10126 = {
+	    pad: function (data, blockSize) {
+	        // Shortcut
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Count padding bytes
+	        var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
+
+	        // Pad
+	        data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)).
+	             concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1));
+	    },
+
+	    unpad: function (data) {
+	        // Get number of padding bytes from last byte
+	        var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	        // Remove padding
+	        data.sigBytes -= nPaddingBytes;
+	    }
+	};
+
+
+	/**
+	 * ISO/IEC 9797-1 Padding Method 2.
+	 */
+	CryptoJS.pad.Iso97971 = {
+	    pad: function (data, blockSize) {
+	        // Add 0x80 byte
+	        data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1));
+
+	        // Zero pad the rest
+	        CryptoJS.pad.ZeroPadding.pad(data, blockSize);
+	    },
+
+	    unpad: function (data) {
+	        // Remove zero padding
+	        CryptoJS.pad.ZeroPadding.unpad(data);
+
+	        // Remove one more byte -- the 0x80 byte
+	        data.sigBytes--;
+	    }
+	};
+
+
+	/**
+	 * Zero padding strategy.
+	 */
+	CryptoJS.pad.ZeroPadding = {
+	    pad: function (data, blockSize) {
+	        // Shortcut
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Pad
+	        data.clamp();
+	        data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes);
+	    },
+
+	    unpad: function (data) {
+	        // Shortcut
+	        var dataWords = data.words;
+
+	        // Unpad
+	        var i = data.sigBytes - 1;
+	        for (var i = data.sigBytes - 1; i >= 0; i--) {
+	            if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) {
+	                data.sigBytes = i + 1;
+	                break;
+	            }
+	        }
+	    }
+	};
+
+
+	/**
+	 * A noop padding strategy.
+	 */
+	CryptoJS.pad.NoPadding = {
+	    pad: function () {
+	    },
+
+	    unpad: function () {
+	    }
+	};
+
+
+	(function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var CipherParams = C_lib.CipherParams;
+	    var C_enc = C.enc;
+	    var Hex = C_enc.Hex;
+	    var C_format = C.format;
+
+	    var HexFormatter = C_format.Hex = {
+	        /**
+	         * Converts the ciphertext of a cipher params object to a hexadecimally encoded string.
+	         *
+	         * @param {CipherParams} cipherParams The cipher params object.
+	         *
+	         * @return {string} The hexadecimally encoded string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var hexString = CryptoJS.format.Hex.stringify(cipherParams);
+	         */
+	        stringify: function (cipherParams) {
+	            return cipherParams.ciphertext.toString(Hex);
+	        },
+
+	        /**
+	         * Converts a hexadecimally encoded ciphertext string to a cipher params object.
+	         *
+	         * @param {string} input The hexadecimally encoded string.
+	         *
+	         * @return {CipherParams} The cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.format.Hex.parse(hexString);
+	         */
+	        parse: function (input) {
+	            var ciphertext = Hex.parse(input);
+	            return CipherParams.create({ ciphertext: ciphertext });
+	        }
+	    };
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var BlockCipher = C_lib.BlockCipher;
+	    var C_algo = C.algo;
+
+	    // Lookup tables
+	    var SBOX = [];
+	    var INV_SBOX = [];
+	    var SUB_MIX_0 = [];
+	    var SUB_MIX_1 = [];
+	    var SUB_MIX_2 = [];
+	    var SUB_MIX_3 = [];
+	    var INV_SUB_MIX_0 = [];
+	    var INV_SUB_MIX_1 = [];
+	    var INV_SUB_MIX_2 = [];
+	    var INV_SUB_MIX_3 = [];
+
+	    // Compute lookup tables
+	    (function () {
+	        // Compute double table
+	        var d = [];
+	        for (var i = 0; i < 256; i++) {
+	            if (i < 128) {
+	                d[i] = i << 1;
+	            } else {
+	                d[i] = (i << 1) ^ 0x11b;
+	            }
+	        }
+
+	        // Walk GF(2^8)
+	        var x = 0;
+	        var xi = 0;
+	        for (var i = 0; i < 256; i++) {
+	            // Compute sbox
+	            var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4);
+	            sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63;
+	            SBOX[x] = sx;
+	            INV_SBOX[sx] = x;
+
+	            // Compute multiplication
+	            var x2 = d[x];
+	            var x4 = d[x2];
+	            var x8 = d[x4];
+
+	            // Compute sub bytes, mix columns tables
+	            var t = (d[sx] * 0x101) ^ (sx * 0x1010100);
+	            SUB_MIX_0[x] = (t << 24) | (t >>> 8);
+	            SUB_MIX_1[x] = (t << 16) | (t >>> 16);
+	            SUB_MIX_2[x] = (t << 8)  | (t >>> 24);
+	            SUB_MIX_3[x] = t;
+
+	            // Compute inv sub bytes, inv mix columns tables
+	            var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100);
+	            INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8);
+	            INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16);
+	            INV_SUB_MIX_2[sx] = (t << 8)  | (t >>> 24);
+	            INV_SUB_MIX_3[sx] = t;
+
+	            // Compute next counter
+	            if (!x) {
+	                x = xi = 1;
+	            } else {
+	                x = x2 ^ d[d[d[x8 ^ x2]]];
+	                xi ^= d[d[xi]];
+	            }
+	        }
+	    }());
+
+	    // Precomputed Rcon lookup
+	    var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
+
+	    /**
+	     * AES block cipher algorithm.
+	     */
+	    var AES = C_algo.AES = BlockCipher.extend({
+	        _doReset: function () {
+	            var t;
+
+	            // Skip reset of nRounds has been set before and key did not change
+	            if (this._nRounds && this._keyPriorReset === this._key) {
+	                return;
+	            }
+
+	            // Shortcuts
+	            var key = this._keyPriorReset = this._key;
+	            var keyWords = key.words;
+	            var keySize = key.sigBytes / 4;
+
+	            // Compute number of rounds
+	            var nRounds = this._nRounds = keySize + 6;
+
+	            // Compute number of key schedule rows
+	            var ksRows = (nRounds + 1) * 4;
+
+	            // Compute key schedule
+	            var keySchedule = this._keySchedule = [];
+	            for (var ksRow = 0; ksRow < ksRows; ksRow++) {
+	                if (ksRow < keySize) {
+	                    keySchedule[ksRow] = keyWords[ksRow];
+	                } else {
+	                    t = keySchedule[ksRow - 1];
+
+	                    if (!(ksRow % keySize)) {
+	                        // Rot word
+	                        t = (t << 8) | (t >>> 24);
+
+	                        // Sub word
+	                        t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
+
+	                        // Mix Rcon
+	                        t ^= RCON[(ksRow / keySize) | 0] << 24;
+	                    } else if (keySize > 6 && ksRow % keySize == 4) {
+	                        // Sub word
+	                        t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
+	                    }
+
+	                    keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t;
+	                }
+	            }
+
+	            // Compute inv key schedule
+	            var invKeySchedule = this._invKeySchedule = [];
+	            for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) {
+	                var ksRow = ksRows - invKsRow;
+
+	                if (invKsRow % 4) {
+	                    var t = keySchedule[ksRow];
+	                } else {
+	                    var t = keySchedule[ksRow - 4];
+	                }
+
+	                if (invKsRow < 4 || ksRow <= 4) {
+	                    invKeySchedule[invKsRow] = t;
+	                } else {
+	                    invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^
+	                                               INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]];
+	                }
+	            }
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            // Swap 2nd and 4th rows
+	            var t = M[offset + 1];
+	            M[offset + 1] = M[offset + 3];
+	            M[offset + 3] = t;
+
+	            this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX);
+
+	            // Inv swap 2nd and 4th rows
+	            var t = M[offset + 1];
+	            M[offset + 1] = M[offset + 3];
+	            M[offset + 3] = t;
+	        },
+
+	        _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) {
+	            // Shortcut
+	            var nRounds = this._nRounds;
+
+	            // Get input, add round key
+	            var s0 = M[offset]     ^ keySchedule[0];
+	            var s1 = M[offset + 1] ^ keySchedule[1];
+	            var s2 = M[offset + 2] ^ keySchedule[2];
+	            var s3 = M[offset + 3] ^ keySchedule[3];
+
+	            // Key schedule row counter
+	            var ksRow = 4;
+
+	            // Rounds
+	            for (var round = 1; round < nRounds; round++) {
+	                // Shift rows, sub bytes, mix columns, add round key
+	                var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++];
+	                var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++];
+	                var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++];
+	                var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++];
+
+	                // Update state
+	                s0 = t0;
+	                s1 = t1;
+	                s2 = t2;
+	                s3 = t3;
+	            }
+
+	            // Shift rows, sub bytes, add round key
+	            var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++];
+	            var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++];
+	            var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++];
+	            var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++];
+
+	            // Set output
+	            M[offset]     = t0;
+	            M[offset + 1] = t1;
+	            M[offset + 2] = t2;
+	            M[offset + 3] = t3;
+	        },
+
+	        keySize: 256/32
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.AES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.AES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.AES = BlockCipher._createHelper(AES);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var BlockCipher = C_lib.BlockCipher;
+	    var C_algo = C.algo;
+
+	    // Permuted Choice 1 constants
+	    var PC1 = [
+	        57, 49, 41, 33, 25, 17, 9,  1,
+	        58, 50, 42, 34, 26, 18, 10, 2,
+	        59, 51, 43, 35, 27, 19, 11, 3,
+	        60, 52, 44, 36, 63, 55, 47, 39,
+	        31, 23, 15, 7,  62, 54, 46, 38,
+	        30, 22, 14, 6,  61, 53, 45, 37,
+	        29, 21, 13, 5,  28, 20, 12, 4
+	    ];
+
+	    // Permuted Choice 2 constants
+	    var PC2 = [
+	        14, 17, 11, 24, 1,  5,
+	        3,  28, 15, 6,  21, 10,
+	        23, 19, 12, 4,  26, 8,
+	        16, 7,  27, 20, 13, 2,
+	        41, 52, 31, 37, 47, 55,
+	        30, 40, 51, 45, 33, 48,
+	        44, 49, 39, 56, 34, 53,
+	        46, 42, 50, 36, 29, 32
+	    ];
+
+	    // Cumulative bit shift constants
+	    var BIT_SHIFTS = [1,  2,  4,  6,  8,  10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28];
+
+	    // SBOXes and round permutation constants
+	    var SBOX_P = [
+	        {
+	            0x0: 0x808200,
+	            0x10000000: 0x8000,
+	            0x20000000: 0x808002,
+	            0x30000000: 0x2,
+	            0x40000000: 0x200,
+	            0x50000000: 0x808202,
+	            0x60000000: 0x800202,
+	            0x70000000: 0x800000,
+	            0x80000000: 0x202,
+	            0x90000000: 0x800200,
+	            0xa0000000: 0x8200,
+	            0xb0000000: 0x808000,
+	            0xc0000000: 0x8002,
+	            0xd0000000: 0x800002,
+	            0xe0000000: 0x0,
+	            0xf0000000: 0x8202,
+	            0x8000000: 0x0,
+	            0x18000000: 0x808202,
+	            0x28000000: 0x8202,
+	            0x38000000: 0x8000,
+	            0x48000000: 0x808200,
+	            0x58000000: 0x200,
+	            0x68000000: 0x808002,
+	            0x78000000: 0x2,
+	            0x88000000: 0x800200,
+	            0x98000000: 0x8200,
+	            0xa8000000: 0x808000,
+	            0xb8000000: 0x800202,
+	            0xc8000000: 0x800002,
+	            0xd8000000: 0x8002,
+	            0xe8000000: 0x202,
+	            0xf8000000: 0x800000,
+	            0x1: 0x8000,
+	            0x10000001: 0x2,
+	            0x20000001: 0x808200,
+	            0x30000001: 0x800000,
+	            0x40000001: 0x808002,
+	            0x50000001: 0x8200,
+	            0x60000001: 0x200,
+	            0x70000001: 0x800202,
+	            0x80000001: 0x808202,
+	            0x90000001: 0x808000,
+	            0xa0000001: 0x800002,
+	            0xb0000001: 0x8202,
+	            0xc0000001: 0x202,
+	            0xd0000001: 0x800200,
+	            0xe0000001: 0x8002,
+	            0xf0000001: 0x0,
+	            0x8000001: 0x808202,
+	            0x18000001: 0x808000,
+	            0x28000001: 0x800000,
+	            0x38000001: 0x200,
+	            0x48000001: 0x8000,
+	            0x58000001: 0x800002,
+	            0x68000001: 0x2,
+	            0x78000001: 0x8202,
+	            0x88000001: 0x8002,
+	            0x98000001: 0x800202,
+	            0xa8000001: 0x202,
+	            0xb8000001: 0x808200,
+	            0xc8000001: 0x800200,
+	            0xd8000001: 0x0,
+	            0xe8000001: 0x8200,
+	            0xf8000001: 0x808002
+	        },
+	        {
+	            0x0: 0x40084010,
+	            0x1000000: 0x4000,
+	            0x2000000: 0x80000,
+	            0x3000000: 0x40080010,
+	            0x4000000: 0x40000010,
+	            0x5000000: 0x40084000,
+	            0x6000000: 0x40004000,
+	            0x7000000: 0x10,
+	            0x8000000: 0x84000,
+	            0x9000000: 0x40004010,
+	            0xa000000: 0x40000000,
+	            0xb000000: 0x84010,
+	            0xc000000: 0x80010,
+	            0xd000000: 0x0,
+	            0xe000000: 0x4010,
+	            0xf000000: 0x40080000,
+	            0x800000: 0x40004000,
+	            0x1800000: 0x84010,
+	            0x2800000: 0x10,
+	            0x3800000: 0x40004010,
+	            0x4800000: 0x40084010,
+	            0x5800000: 0x40000000,
+	            0x6800000: 0x80000,
+	            0x7800000: 0x40080010,
+	            0x8800000: 0x80010,
+	            0x9800000: 0x0,
+	            0xa800000: 0x4000,
+	            0xb800000: 0x40080000,
+	            0xc800000: 0x40000010,
+	            0xd800000: 0x84000,
+	            0xe800000: 0x40084000,
+	            0xf800000: 0x4010,
+	            0x10000000: 0x0,
+	            0x11000000: 0x40080010,
+	            0x12000000: 0x40004010,
+	            0x13000000: 0x40084000,
+	            0x14000000: 0x40080000,
+	            0x15000000: 0x10,
+	            0x16000000: 0x84010,
+	            0x17000000: 0x4000,
+	            0x18000000: 0x4010,
+	            0x19000000: 0x80000,
+	            0x1a000000: 0x80010,
+	            0x1b000000: 0x40000010,
+	            0x1c000000: 0x84000,
+	            0x1d000000: 0x40004000,
+	            0x1e000000: 0x40000000,
+	            0x1f000000: 0x40084010,
+	            0x10800000: 0x84010,
+	            0x11800000: 0x80000,
+	            0x12800000: 0x40080000,
+	            0x13800000: 0x4000,
+	            0x14800000: 0x40004000,
+	            0x15800000: 0x40084010,
+	            0x16800000: 0x10,
+	            0x17800000: 0x40000000,
+	            0x18800000: 0x40084000,
+	            0x19800000: 0x40000010,
+	            0x1a800000: 0x40004010,
+	            0x1b800000: 0x80010,
+	            0x1c800000: 0x0,
+	            0x1d800000: 0x4010,
+	            0x1e800000: 0x40080010,
+	            0x1f800000: 0x84000
+	        },
+	        {
+	            0x0: 0x104,
+	            0x100000: 0x0,
+	            0x200000: 0x4000100,
+	            0x300000: 0x10104,
+	            0x400000: 0x10004,
+	            0x500000: 0x4000004,
+	            0x600000: 0x4010104,
+	            0x700000: 0x4010000,
+	            0x800000: 0x4000000,
+	            0x900000: 0x4010100,
+	            0xa00000: 0x10100,
+	            0xb00000: 0x4010004,
+	            0xc00000: 0x4000104,
+	            0xd00000: 0x10000,
+	            0xe00000: 0x4,
+	            0xf00000: 0x100,
+	            0x80000: 0x4010100,
+	            0x180000: 0x4010004,
+	            0x280000: 0x0,
+	            0x380000: 0x4000100,
+	            0x480000: 0x4000004,
+	            0x580000: 0x10000,
+	            0x680000: 0x10004,
+	            0x780000: 0x104,
+	            0x880000: 0x4,
+	            0x980000: 0x100,
+	            0xa80000: 0x4010000,
+	            0xb80000: 0x10104,
+	            0xc80000: 0x10100,
+	            0xd80000: 0x4000104,
+	            0xe80000: 0x4010104,
+	            0xf80000: 0x4000000,
+	            0x1000000: 0x4010100,
+	            0x1100000: 0x10004,
+	            0x1200000: 0x10000,
+	            0x1300000: 0x4000100,
+	            0x1400000: 0x100,
+	            0x1500000: 0x4010104,
+	            0x1600000: 0x4000004,
+	            0x1700000: 0x0,
+	            0x1800000: 0x4000104,
+	            0x1900000: 0x4000000,
+	            0x1a00000: 0x4,
+	            0x1b00000: 0x10100,
+	            0x1c00000: 0x4010000,
+	            0x1d00000: 0x104,
+	            0x1e00000: 0x10104,
+	            0x1f00000: 0x4010004,
+	            0x1080000: 0x4000000,
+	            0x1180000: 0x104,
+	            0x1280000: 0x4010100,
+	            0x1380000: 0x0,
+	            0x1480000: 0x10004,
+	            0x1580000: 0x4000100,
+	            0x1680000: 0x100,
+	            0x1780000: 0x4010004,
+	            0x1880000: 0x10000,
+	            0x1980000: 0x4010104,
+	            0x1a80000: 0x10104,
+	            0x1b80000: 0x4000004,
+	            0x1c80000: 0x4000104,
+	            0x1d80000: 0x4010000,
+	            0x1e80000: 0x4,
+	            0x1f80000: 0x10100
+	        },
+	        {
+	            0x0: 0x80401000,
+	            0x10000: 0x80001040,
+	            0x20000: 0x401040,
+	            0x30000: 0x80400000,
+	            0x40000: 0x0,
+	            0x50000: 0x401000,
+	            0x60000: 0x80000040,
+	            0x70000: 0x400040,
+	            0x80000: 0x80000000,
+	            0x90000: 0x400000,
+	            0xa0000: 0x40,
+	            0xb0000: 0x80001000,
+	            0xc0000: 0x80400040,
+	            0xd0000: 0x1040,
+	            0xe0000: 0x1000,
+	            0xf0000: 0x80401040,
+	            0x8000: 0x80001040,
+	            0x18000: 0x40,
+	            0x28000: 0x80400040,
+	            0x38000: 0x80001000,
+	            0x48000: 0x401000,
+	            0x58000: 0x80401040,
+	            0x68000: 0x0,
+	            0x78000: 0x80400000,
+	            0x88000: 0x1000,
+	            0x98000: 0x80401000,
+	            0xa8000: 0x400000,
+	            0xb8000: 0x1040,
+	            0xc8000: 0x80000000,
+	            0xd8000: 0x400040,
+	            0xe8000: 0x401040,
+	            0xf8000: 0x80000040,
+	            0x100000: 0x400040,
+	            0x110000: 0x401000,
+	            0x120000: 0x80000040,
+	            0x130000: 0x0,
+	            0x140000: 0x1040,
+	            0x150000: 0x80400040,
+	            0x160000: 0x80401000,
+	            0x170000: 0x80001040,
+	            0x180000: 0x80401040,
+	            0x190000: 0x80000000,
+	            0x1a0000: 0x80400000,
+	            0x1b0000: 0x401040,
+	            0x1c0000: 0x80001000,
+	            0x1d0000: 0x400000,
+	            0x1e0000: 0x40,
+	            0x1f0000: 0x1000,
+	            0x108000: 0x80400000,
+	            0x118000: 0x80401040,
+	            0x128000: 0x0,
+	            0x138000: 0x401000,
+	            0x148000: 0x400040,
+	            0x158000: 0x80000000,
+	            0x168000: 0x80001040,
+	            0x178000: 0x40,
+	            0x188000: 0x80000040,
+	            0x198000: 0x1000,
+	            0x1a8000: 0x80001000,
+	            0x1b8000: 0x80400040,
+	            0x1c8000: 0x1040,
+	            0x1d8000: 0x80401000,
+	            0x1e8000: 0x400000,
+	            0x1f8000: 0x401040
+	        },
+	        {
+	            0x0: 0x80,
+	            0x1000: 0x1040000,
+	            0x2000: 0x40000,
+	            0x3000: 0x20000000,
+	            0x4000: 0x20040080,
+	            0x5000: 0x1000080,
+	            0x6000: 0x21000080,
+	            0x7000: 0x40080,
+	            0x8000: 0x1000000,
+	            0x9000: 0x20040000,
+	            0xa000: 0x20000080,
+	            0xb000: 0x21040080,
+	            0xc000: 0x21040000,
+	            0xd000: 0x0,
+	            0xe000: 0x1040080,
+	            0xf000: 0x21000000,
+	            0x800: 0x1040080,
+	            0x1800: 0x21000080,
+	            0x2800: 0x80,
+	            0x3800: 0x1040000,
+	            0x4800: 0x40000,
+	            0x5800: 0x20040080,
+	            0x6800: 0x21040000,
+	            0x7800: 0x20000000,
+	            0x8800: 0x20040000,
+	            0x9800: 0x0,
+	            0xa800: 0x21040080,
+	            0xb800: 0x1000080,
+	            0xc800: 0x20000080,
+	            0xd800: 0x21000000,
+	            0xe800: 0x1000000,
+	            0xf800: 0x40080,
+	            0x10000: 0x40000,
+	            0x11000: 0x80,
+	            0x12000: 0x20000000,
+	            0x13000: 0x21000080,
+	            0x14000: 0x1000080,
+	            0x15000: 0x21040000,
+	            0x16000: 0x20040080,
+	            0x17000: 0x1000000,
+	            0x18000: 0x21040080,
+	            0x19000: 0x21000000,
+	            0x1a000: 0x1040000,
+	            0x1b000: 0x20040000,
+	            0x1c000: 0x40080,
+	            0x1d000: 0x20000080,
+	            0x1e000: 0x0,
+	            0x1f000: 0x1040080,
+	            0x10800: 0x21000080,
+	            0x11800: 0x1000000,
+	            0x12800: 0x1040000,
+	            0x13800: 0x20040080,
+	            0x14800: 0x20000000,
+	            0x15800: 0x1040080,
+	            0x16800: 0x80,
+	            0x17800: 0x21040000,
+	            0x18800: 0x40080,
+	            0x19800: 0x21040080,
+	            0x1a800: 0x0,
+	            0x1b800: 0x21000000,
+	            0x1c800: 0x1000080,
+	            0x1d800: 0x40000,
+	            0x1e800: 0x20040000,
+	            0x1f800: 0x20000080
+	        },
+	        {
+	            0x0: 0x10000008,
+	            0x100: 0x2000,
+	            0x200: 0x10200000,
+	            0x300: 0x10202008,
+	            0x400: 0x10002000,
+	            0x500: 0x200000,
+	            0x600: 0x200008,
+	            0x700: 0x10000000,
+	            0x800: 0x0,
+	            0x900: 0x10002008,
+	            0xa00: 0x202000,
+	            0xb00: 0x8,
+	            0xc00: 0x10200008,
+	            0xd00: 0x202008,
+	            0xe00: 0x2008,
+	            0xf00: 0x10202000,
+	            0x80: 0x10200000,
+	            0x180: 0x10202008,
+	            0x280: 0x8,
+	            0x380: 0x200000,
+	            0x480: 0x202008,
+	            0x580: 0x10000008,
+	            0x680: 0x10002000,
+	            0x780: 0x2008,
+	            0x880: 0x200008,
+	            0x980: 0x2000,
+	            0xa80: 0x10002008,
+	            0xb80: 0x10200008,
+	            0xc80: 0x0,
+	            0xd80: 0x10202000,
+	            0xe80: 0x202000,
+	            0xf80: 0x10000000,
+	            0x1000: 0x10002000,
+	            0x1100: 0x10200008,
+	            0x1200: 0x10202008,
+	            0x1300: 0x2008,
+	            0x1400: 0x200000,
+	            0x1500: 0x10000000,
+	            0x1600: 0x10000008,
+	            0x1700: 0x202000,
+	            0x1800: 0x202008,
+	            0x1900: 0x0,
+	            0x1a00: 0x8,
+	            0x1b00: 0x10200000,
+	            0x1c00: 0x2000,
+	            0x1d00: 0x10002008,
+	            0x1e00: 0x10202000,
+	            0x1f00: 0x200008,
+	            0x1080: 0x8,
+	            0x1180: 0x202000,
+	            0x1280: 0x200000,
+	            0x1380: 0x10000008,
+	            0x1480: 0x10002000,
+	            0x1580: 0x2008,
+	            0x1680: 0x10202008,
+	            0x1780: 0x10200000,
+	            0x1880: 0x10202000,
+	            0x1980: 0x10200008,
+	            0x1a80: 0x2000,
+	            0x1b80: 0x202008,
+	            0x1c80: 0x200008,
+	            0x1d80: 0x0,
+	            0x1e80: 0x10000000,
+	            0x1f80: 0x10002008
+	        },
+	        {
+	            0x0: 0x100000,
+	            0x10: 0x2000401,
+	            0x20: 0x400,
+	            0x30: 0x100401,
+	            0x40: 0x2100401,
+	            0x50: 0x0,
+	            0x60: 0x1,
+	            0x70: 0x2100001,
+	            0x80: 0x2000400,
+	            0x90: 0x100001,
+	            0xa0: 0x2000001,
+	            0xb0: 0x2100400,
+	            0xc0: 0x2100000,
+	            0xd0: 0x401,
+	            0xe0: 0x100400,
+	            0xf0: 0x2000000,
+	            0x8: 0x2100001,
+	            0x18: 0x0,
+	            0x28: 0x2000401,
+	            0x38: 0x2100400,
+	            0x48: 0x100000,
+	            0x58: 0x2000001,
+	            0x68: 0x2000000,
+	            0x78: 0x401,
+	            0x88: 0x100401,
+	            0x98: 0x2000400,
+	            0xa8: 0x2100000,
+	            0xb8: 0x100001,
+	            0xc8: 0x400,
+	            0xd8: 0x2100401,
+	            0xe8: 0x1,
+	            0xf8: 0x100400,
+	            0x100: 0x2000000,
+	            0x110: 0x100000,
+	            0x120: 0x2000401,
+	            0x130: 0x2100001,
+	            0x140: 0x100001,
+	            0x150: 0x2000400,
+	            0x160: 0x2100400,
+	            0x170: 0x100401,
+	            0x180: 0x401,
+	            0x190: 0x2100401,
+	            0x1a0: 0x100400,
+	            0x1b0: 0x1,
+	            0x1c0: 0x0,
+	            0x1d0: 0x2100000,
+	            0x1e0: 0x2000001,
+	            0x1f0: 0x400,
+	            0x108: 0x100400,
+	            0x118: 0x2000401,
+	            0x128: 0x2100001,
+	            0x138: 0x1,
+	            0x148: 0x2000000,
+	            0x158: 0x100000,
+	            0x168: 0x401,
+	            0x178: 0x2100400,
+	            0x188: 0x2000001,
+	            0x198: 0x2100000,
+	            0x1a8: 0x0,
+	            0x1b8: 0x2100401,
+	            0x1c8: 0x100401,
+	            0x1d8: 0x400,
+	            0x1e8: 0x2000400,
+	            0x1f8: 0x100001
+	        },
+	        {
+	            0x0: 0x8000820,
+	            0x1: 0x20000,
+	            0x2: 0x8000000,
+	            0x3: 0x20,
+	            0x4: 0x20020,
+	            0x5: 0x8020820,
+	            0x6: 0x8020800,
+	            0x7: 0x800,
+	            0x8: 0x8020000,
+	            0x9: 0x8000800,
+	            0xa: 0x20800,
+	            0xb: 0x8020020,
+	            0xc: 0x820,
+	            0xd: 0x0,
+	            0xe: 0x8000020,
+	            0xf: 0x20820,
+	            0x80000000: 0x800,
+	            0x80000001: 0x8020820,
+	            0x80000002: 0x8000820,
+	            0x80000003: 0x8000000,
+	            0x80000004: 0x8020000,
+	            0x80000005: 0x20800,
+	            0x80000006: 0x20820,
+	            0x80000007: 0x20,
+	            0x80000008: 0x8000020,
+	            0x80000009: 0x820,
+	            0x8000000a: 0x20020,
+	            0x8000000b: 0x8020800,
+	            0x8000000c: 0x0,
+	            0x8000000d: 0x8020020,
+	            0x8000000e: 0x8000800,
+	            0x8000000f: 0x20000,
+	            0x10: 0x20820,
+	            0x11: 0x8020800,
+	            0x12: 0x20,
+	            0x13: 0x800,
+	            0x14: 0x8000800,
+	            0x15: 0x8000020,
+	            0x16: 0x8020020,
+	            0x17: 0x20000,
+	            0x18: 0x0,
+	            0x19: 0x20020,
+	            0x1a: 0x8020000,
+	            0x1b: 0x8000820,
+	            0x1c: 0x8020820,
+	            0x1d: 0x20800,
+	            0x1e: 0x820,
+	            0x1f: 0x8000000,
+	            0x80000010: 0x20000,
+	            0x80000011: 0x800,
+	            0x80000012: 0x8020020,
+	            0x80000013: 0x20820,
+	            0x80000014: 0x20,
+	            0x80000015: 0x8020000,
+	            0x80000016: 0x8000000,
+	            0x80000017: 0x8000820,
+	            0x80000018: 0x8020820,
+	            0x80000019: 0x8000020,
+	            0x8000001a: 0x8000800,
+	            0x8000001b: 0x0,
+	            0x8000001c: 0x20800,
+	            0x8000001d: 0x820,
+	            0x8000001e: 0x20020,
+	            0x8000001f: 0x8020800
+	        }
+	    ];
+
+	    // Masks that select the SBOX input
+	    var SBOX_MASK = [
+	        0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000,
+	        0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f
+	    ];
+
+	    /**
+	     * DES block cipher algorithm.
+	     */
+	    var DES = C_algo.DES = BlockCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+
+	            // Select 56 bits according to PC1
+	            var keyBits = [];
+	            for (var i = 0; i < 56; i++) {
+	                var keyBitPos = PC1[i] - 1;
+	                keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1;
+	            }
+
+	            // Assemble 16 subkeys
+	            var subKeys = this._subKeys = [];
+	            for (var nSubKey = 0; nSubKey < 16; nSubKey++) {
+	                // Create subkey
+	                var subKey = subKeys[nSubKey] = [];
+
+	                // Shortcut
+	                var bitShift = BIT_SHIFTS[nSubKey];
+
+	                // Select 48 bits according to PC2
+	                for (var i = 0; i < 24; i++) {
+	                    // Select from the left 28 key bits
+	                    subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6);
+
+	                    // Select from the right 28 key bits
+	                    subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6);
+	                }
+
+	                // Since each subkey is applied to an expanded 32-bit input,
+	                // the subkey can be broken into 8 values scaled to 32-bits,
+	                // which allows the key to be used without expansion
+	                subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31);
+	                for (var i = 1; i < 7; i++) {
+	                    subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3);
+	                }
+	                subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27);
+	            }
+
+	            // Compute inverse subkeys
+	            var invSubKeys = this._invSubKeys = [];
+	            for (var i = 0; i < 16; i++) {
+	                invSubKeys[i] = subKeys[15 - i];
+	            }
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._subKeys);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._invSubKeys);
+	        },
+
+	        _doCryptBlock: function (M, offset, subKeys) {
+	            // Get input
+	            this._lBlock = M[offset];
+	            this._rBlock = M[offset + 1];
+
+	            // Initial permutation
+	            exchangeLR.call(this, 4,  0x0f0f0f0f);
+	            exchangeLR.call(this, 16, 0x0000ffff);
+	            exchangeRL.call(this, 2,  0x33333333);
+	            exchangeRL.call(this, 8,  0x00ff00ff);
+	            exchangeLR.call(this, 1,  0x55555555);
+
+	            // Rounds
+	            for (var round = 0; round < 16; round++) {
+	                // Shortcuts
+	                var subKey = subKeys[round];
+	                var lBlock = this._lBlock;
+	                var rBlock = this._rBlock;
+
+	                // Feistel function
+	                var f = 0;
+	                for (var i = 0; i < 8; i++) {
+	                    f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0];
+	                }
+	                this._lBlock = rBlock;
+	                this._rBlock = lBlock ^ f;
+	            }
+
+	            // Undo swap from last round
+	            var t = this._lBlock;
+	            this._lBlock = this._rBlock;
+	            this._rBlock = t;
+
+	            // Final permutation
+	            exchangeLR.call(this, 1,  0x55555555);
+	            exchangeRL.call(this, 8,  0x00ff00ff);
+	            exchangeRL.call(this, 2,  0x33333333);
+	            exchangeLR.call(this, 16, 0x0000ffff);
+	            exchangeLR.call(this, 4,  0x0f0f0f0f);
+
+	            // Set output
+	            M[offset] = this._lBlock;
+	            M[offset + 1] = this._rBlock;
+	        },
+
+	        keySize: 64/32,
+
+	        ivSize: 64/32,
+
+	        blockSize: 64/32
+	    });
+
+	    // Swap bits across the left and right words
+	    function exchangeLR(offset, mask) {
+	        var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask;
+	        this._rBlock ^= t;
+	        this._lBlock ^= t << offset;
+	    }
+
+	    function exchangeRL(offset, mask) {
+	        var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask;
+	        this._lBlock ^= t;
+	        this._rBlock ^= t << offset;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.DES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.DES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.DES = BlockCipher._createHelper(DES);
+
+	    /**
+	     * Triple-DES block cipher algorithm.
+	     */
+	    var TripleDES = C_algo.TripleDES = BlockCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+	            // Make sure the key length is valid (64, 128 or >= 192 bit)
+	            if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) {
+	                throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.');
+	            }
+
+	            // Extend the key according to the keying options defined in 3DES standard
+	            var key1 = keyWords.slice(0, 2);
+	            var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4);
+	            var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6);
+
+	            // Create DES instances
+	            this._des1 = DES.createEncryptor(WordArray.create(key1));
+	            this._des2 = DES.createEncryptor(WordArray.create(key2));
+	            this._des3 = DES.createEncryptor(WordArray.create(key3));
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._des1.encryptBlock(M, offset);
+	            this._des2.decryptBlock(M, offset);
+	            this._des3.encryptBlock(M, offset);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            this._des3.decryptBlock(M, offset);
+	            this._des2.encryptBlock(M, offset);
+	            this._des1.decryptBlock(M, offset);
+	        },
+
+	        keySize: 192/32,
+
+	        ivSize: 64/32,
+
+	        blockSize: 64/32
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.TripleDES = BlockCipher._createHelper(TripleDES);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    /**
+	     * RC4 stream cipher algorithm.
+	     */
+	    var RC4 = C_algo.RC4 = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+	            var keySigBytes = key.sigBytes;
+
+	            // Init sbox
+	            var S = this._S = [];
+	            for (var i = 0; i < 256; i++) {
+	                S[i] = i;
+	            }
+
+	            // Key setup
+	            for (var i = 0, j = 0; i < 256; i++) {
+	                var keyByteIndex = i % keySigBytes;
+	                var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff;
+
+	                j = (j + S[i] + keyByte) % 256;
+
+	                // Swap
+	                var t = S[i];
+	                S[i] = S[j];
+	                S[j] = t;
+	            }
+
+	            // Counters
+	            this._i = this._j = 0;
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            M[offset] ^= generateKeystreamWord.call(this);
+	        },
+
+	        keySize: 256/32,
+
+	        ivSize: 0
+	    });
+
+	    function generateKeystreamWord() {
+	        // Shortcuts
+	        var S = this._S;
+	        var i = this._i;
+	        var j = this._j;
+
+	        // Generate keystream word
+	        var keystreamWord = 0;
+	        for (var n = 0; n < 4; n++) {
+	            i = (i + 1) % 256;
+	            j = (j + S[i]) % 256;
+
+	            // Swap
+	            var t = S[i];
+	            S[i] = S[j];
+	            S[j] = t;
+
+	            keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8);
+	        }
+
+	        // Update counters
+	        this._i = i;
+	        this._j = j;
+
+	        return keystreamWord;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RC4.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RC4 = StreamCipher._createHelper(RC4);
+
+	    /**
+	     * Modified RC4 stream cipher algorithm.
+	     */
+	    var RC4Drop = C_algo.RC4Drop = RC4.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} drop The number of keystream words to drop. Default 192
+	         */
+	        cfg: RC4.cfg.extend({
+	            drop: 192
+	        }),
+
+	        _doReset: function () {
+	            RC4._doReset.call(this);
+
+	            // Drop
+	            for (var i = this.cfg.drop; i > 0; i--) {
+	                generateKeystreamWord.call(this);
+	            }
+	        }
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RC4Drop = StreamCipher._createHelper(RC4Drop);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    // Reusable objects
+	    var S  = [];
+	    var C_ = [];
+	    var G  = [];
+
+	    /**
+	     * Rabbit stream cipher algorithm
+	     */
+	    var Rabbit = C_algo.Rabbit = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var K = this._key.words;
+	            var iv = this.cfg.iv;
+
+	            // Swap endian
+	            for (var i = 0; i < 4; i++) {
+	                K[i] = (((K[i] << 8)  | (K[i] >>> 24)) & 0x00ff00ff) |
+	                       (((K[i] << 24) | (K[i] >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Generate initial state values
+	            var X = this._X = [
+	                K[0], (K[3] << 16) | (K[2] >>> 16),
+	                K[1], (K[0] << 16) | (K[3] >>> 16),
+	                K[2], (K[1] << 16) | (K[0] >>> 16),
+	                K[3], (K[2] << 16) | (K[1] >>> 16)
+	            ];
+
+	            // Generate initial counter values
+	            var C = this._C = [
+	                (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff),
+	                (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff),
+	                (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff),
+	                (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff)
+	            ];
+
+	            // Carry bit
+	            this._b = 0;
+
+	            // Iterate the system four times
+	            for (var i = 0; i < 4; i++) {
+	                nextState.call(this);
+	            }
+
+	            // Modify the counters
+	            for (var i = 0; i < 8; i++) {
+	                C[i] ^= X[(i + 4) & 7];
+	            }
+
+	            // IV setup
+	            if (iv) {
+	                // Shortcuts
+	                var IV = iv.words;
+	                var IV_0 = IV[0];
+	                var IV_1 = IV[1];
+
+	                // Generate four subvectors
+	                var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00);
+	                var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00);
+	                var i1 = (i0 >>> 16) | (i2 & 0xffff0000);
+	                var i3 = (i2 << 16)  | (i0 & 0x0000ffff);
+
+	                // Modify counter values
+	                C[0] ^= i0;
+	                C[1] ^= i1;
+	                C[2] ^= i2;
+	                C[3] ^= i3;
+	                C[4] ^= i0;
+	                C[5] ^= i1;
+	                C[6] ^= i2;
+	                C[7] ^= i3;
+
+	                // Iterate the system four times
+	                for (var i = 0; i < 4; i++) {
+	                    nextState.call(this);
+	                }
+	            }
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var X = this._X;
+
+	            // Iterate the system
+	            nextState.call(this);
+
+	            // Generate four keystream words
+	            S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16);
+	            S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16);
+	            S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16);
+	            S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16);
+
+	            for (var i = 0; i < 4; i++) {
+	                // Swap endian
+	                S[i] = (((S[i] << 8)  | (S[i] >>> 24)) & 0x00ff00ff) |
+	                       (((S[i] << 24) | (S[i] >>> 8))  & 0xff00ff00);
+
+	                // Encrypt
+	                M[offset + i] ^= S[i];
+	            }
+	        },
+
+	        blockSize: 128/32,
+
+	        ivSize: 64/32
+	    });
+
+	    function nextState() {
+	        // Shortcuts
+	        var X = this._X;
+	        var C = this._C;
+
+	        // Save old counter values
+	        for (var i = 0; i < 8; i++) {
+	            C_[i] = C[i];
+	        }
+
+	        // Calculate new counter values
+	        C[0] = (C[0] + 0x4d34d34d + this._b) | 0;
+	        C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0;
+	        C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0;
+	        C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0;
+	        C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0;
+	        C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0;
+	        C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0;
+	        C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0;
+	        this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0;
+
+	        // Calculate the g-values
+	        for (var i = 0; i < 8; i++) {
+	            var gx = X[i] + C[i];
+
+	            // Construct high and low argument for squaring
+	            var ga = gx & 0xffff;
+	            var gb = gx >>> 16;
+
+	            // Calculate high and low result of squaring
+	            var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb;
+	            var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0);
+
+	            // High XOR low
+	            G[i] = gh ^ gl;
+	        }
+
+	        // Calculate new state values
+	        X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0;
+	        X[1] = (G[1] + ((G[0] << 8)  | (G[0] >>> 24)) + G[7]) | 0;
+	        X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0;
+	        X[3] = (G[3] + ((G[2] << 8)  | (G[2] >>> 24)) + G[1]) | 0;
+	        X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0;
+	        X[5] = (G[5] + ((G[4] << 8)  | (G[4] >>> 24)) + G[3]) | 0;
+	        X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0;
+	        X[7] = (G[7] + ((G[6] << 8)  | (G[6] >>> 24)) + G[5]) | 0;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg);
+	     */
+	    C.Rabbit = StreamCipher._createHelper(Rabbit);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    // Reusable objects
+	    var S  = [];
+	    var C_ = [];
+	    var G  = [];
+
+	    /**
+	     * Rabbit stream cipher algorithm.
+	     *
+	     * This is a legacy version that neglected to convert the key to little-endian.
+	     * This error doesn't affect the cipher's security,
+	     * but it does affect its compatibility with other implementations.
+	     */
+	    var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var K = this._key.words;
+	            var iv = this.cfg.iv;
+
+	            // Generate initial state values
+	            var X = this._X = [
+	                K[0], (K[3] << 16) | (K[2] >>> 16),
+	                K[1], (K[0] << 16) | (K[3] >>> 16),
+	                K[2], (K[1] << 16) | (K[0] >>> 16),
+	                K[3], (K[2] << 16) | (K[1] >>> 16)
+	            ];
+
+	            // Generate initial counter values
+	            var C = this._C = [
+	                (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff),
+	                (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff),
+	                (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff),
+	                (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff)
+	            ];
+
+	            // Carry bit
+	            this._b = 0;
+
+	            // Iterate the system four times
+	            for (var i = 0; i < 4; i++) {
+	                nextState.call(this);
+	            }
+
+	            // Modify the counters
+	            for (var i = 0; i < 8; i++) {
+	                C[i] ^= X[(i + 4) & 7];
+	            }
+
+	            // IV setup
+	            if (iv) {
+	                // Shortcuts
+	                var IV = iv.words;
+	                var IV_0 = IV[0];
+	                var IV_1 = IV[1];
+
+	                // Generate four subvectors
+	                var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00);
+	                var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00);
+	                var i1 = (i0 >>> 16) | (i2 & 0xffff0000);
+	                var i3 = (i2 << 16)  | (i0 & 0x0000ffff);
+
+	                // Modify counter values
+	                C[0] ^= i0;
+	                C[1] ^= i1;
+	                C[2] ^= i2;
+	                C[3] ^= i3;
+	                C[4] ^= i0;
+	                C[5] ^= i1;
+	                C[6] ^= i2;
+	                C[7] ^= i3;
+
+	                // Iterate the system four times
+	                for (var i = 0; i < 4; i++) {
+	                    nextState.call(this);
+	                }
+	            }
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var X = this._X;
+
+	            // Iterate the system
+	            nextState.call(this);
+
+	            // Generate four keystream words
+	            S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16);
+	            S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16);
+	            S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16);
+	            S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16);
+
+	            for (var i = 0; i < 4; i++) {
+	                // Swap endian
+	                S[i] = (((S[i] << 8)  | (S[i] >>> 24)) & 0x00ff00ff) |
+	                       (((S[i] << 24) | (S[i] >>> 8))  & 0xff00ff00);
+
+	                // Encrypt
+	                M[offset + i] ^= S[i];
+	            }
+	        },
+
+	        blockSize: 128/32,
+
+	        ivSize: 64/32
+	    });
+
+	    function nextState() {
+	        // Shortcuts
+	        var X = this._X;
+	        var C = this._C;
+
+	        // Save old counter values
+	        for (var i = 0; i < 8; i++) {
+	            C_[i] = C[i];
+	        }
+
+	        // Calculate new counter values
+	        C[0] = (C[0] + 0x4d34d34d + this._b) | 0;
+	        C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0;
+	        C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0;
+	        C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0;
+	        C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0;
+	        C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0;
+	        C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0;
+	        C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0;
+	        this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0;
+
+	        // Calculate the g-values
+	        for (var i = 0; i < 8; i++) {
+	            var gx = X[i] + C[i];
+
+	            // Construct high and low argument for squaring
+	            var ga = gx & 0xffff;
+	            var gb = gx >>> 16;
+
+	            // Calculate high and low result of squaring
+	            var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb;
+	            var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0);
+
+	            // High XOR low
+	            G[i] = gh ^ gl;
+	        }
+
+	        // Calculate new state values
+	        X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0;
+	        X[1] = (G[1] + ((G[0] << 8)  | (G[0] >>> 24)) + G[7]) | 0;
+	        X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0;
+	        X[3] = (G[3] + ((G[2] << 8)  | (G[2] >>> 24)) + G[1]) | 0;
+	        X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0;
+	        X[5] = (G[5] + ((G[4] << 8)  | (G[4] >>> 24)) + G[3]) | 0;
+	        X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0;
+	        X[7] = (G[7] + ((G[6] << 8)  | (G[6] >>> 24)) + G[5]) | 0;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy);
+	}());
+
+
+	return CryptoJS;
+
+}));

+ 27 - 0
app/assets/js/plupload-2.3.7/bower.json

@@ -0,0 +1,27 @@
+{
+	"name": "plupload",
+	"license": "AGPLv3",
+	"authors": [
+		"Davit Barbakadze <davit.barbakadze@ephox.com>"
+	],
+	"homepage": "http://plupload.com",
+	"repository": {
+		"type": "git",
+		"url": "https://github.com/moxiecode/plupload.git"
+	},
+	"main": [
+		"./js/plupload.full.min.js"
+	],
+	"ignore": [
+		"tests/",
+		"src/",
+		"build/",
+		"examples/",
+		"Jakefile.js",
+		"package.json",
+		"bower.json",
+		"composer.json",
+		"README.md",
+		".*"
+	]
+}

+ 85 - 0
app/assets/js/plupload-2.3.7/examples/custom.html

@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+
+<title>Plupload - Custom example</title>
+
+<!-- production -->
+<script type="text/javascript" src="../js/plupload.full.min.js"></script>
+
+
+<!-- debug 
+<script type="text/javascript" src="../js/moxie.js"></script>
+<script type="text/javascript" src="../js/plupload.dev.js"></script>
+-->
+
+</head>
+<body style="font: 13px Verdana; background: #eee; color: #333">
+
+<h1>Custom example</h1>
+
+<p>Shows you how to use the core plupload API.</p>
+
+<div id="filelist">Your browser doesn't have Flash, Silverlight or HTML5 support.</div>
+<br />
+
+<div id="container">
+    <a id="pickfiles" href="javascript:;">[Select files]</a> 
+    <a id="uploadfiles" href="javascript:;">[Upload files]</a>
+</div>
+
+<br />
+<pre id="console"></pre>
+
+
+<script type="text/javascript">
+// Custom example logic
+
+var uploader = new plupload.Uploader({
+	runtimes : 'html5,flash,silverlight,html4',
+	browse_button : 'pickfiles', // you can pass an id...
+	container: document.getElementById('container'), // ... or DOM Element itself
+	url : 'upload.php',
+	flash_swf_url : '../js/Moxie.swf',
+	silverlight_xap_url : '../js/Moxie.xap',
+	
+	filters : {
+		max_file_size : '10mb',
+		mime_types: [
+			{title : "Image files", extensions : "jpg,gif,png"},
+			{title : "Zip files", extensions : "zip"}
+		]
+	},
+
+	init: {
+		PostInit: function() {
+			document.getElementById('filelist').innerHTML = '';
+
+			document.getElementById('uploadfiles').onclick = function() {
+				uploader.start();
+				return false;
+			};
+		},
+
+		FilesAdded: function(up, files) {
+			plupload.each(files, function(file) {
+				document.getElementById('filelist').innerHTML += '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ') <b></b></div>';
+			});
+		},
+
+		UploadProgress: function(up, file) {
+			document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
+		},
+
+		Error: function(up, err) {
+			document.getElementById('console').appendChild(document.createTextNode("\nError #" + err.code + ": " + err.message));
+		}
+	}
+});
+
+uploader.init();
+
+</script>
+</body>
+</html>

+ 34 - 0
app/assets/js/plupload-2.3.7/examples/dump.php

@@ -0,0 +1,34 @@
+<?php
+#!! IMPORTANT: 
+#!! this file is just an example, it doesn't incorporate any security checks and 
+#!! is not recommended to be used in production environment as it is. Be sure to 
+#!! revise it and customize to your needs.
+die("Make sure that you enable some form of authentication before removing this line.");
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+<title>Plupload - Form dump</title>
+</head>
+<body style="font: 13px Verdana; background: #eee; color: #333">
+	
+<h1>Post dump</h1>
+
+<p>Shows the form items posted.</p>
+
+<table>
+	<tr>
+		<th>Name</th>
+		<th>Value</th>
+	</tr>
+	<?php $count = 0; foreach ($_POST as $name => $value) { ?>
+	<tr class="<?php echo $count % 2 == 0 ? 'alt' : ''; ?>">
+		<td><?php echo htmlentities(stripslashes($name)) ?></td>
+		<td><?php echo nl2br(htmlentities(stripslashes($value))) ?></td>
+	</tr>
+	<?php } ?>
+</table>
+
+</body>
+</html>

+ 217 - 0
app/assets/js/plupload-2.3.7/examples/events.html

@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+
+<title>Plupload - Events example</title>
+
+<!-- production -->
+<script type="text/javascript" src="../js/plupload.full.min.js"></script>
+
+
+<!-- debug 
+<script type="text/javascript" src="../js/moxie.js"></script>
+<script type="text/javascript" src="../js/plupload.dev.js"></script>
+-->
+
+</head>
+<body style="font: 13px Verdana; background: #eee; color: #333">
+
+<h1>Events example</h1>
+
+<div id="container">
+    <a id="pickfiles" href="javascript:;">[Select files]</a> 
+    <a id="uploadfiles" href="javascript:;">[Upload files]</a>
+</div>
+
+<br />
+<pre id="console"></pre>
+ 
+<script type="text/javascript">
+	var uploader = new plupload.Uploader({
+        // General settings
+        runtimes : 'silverlight,html4',
+		browse_button : 'pickfiles', // you can pass in id...
+        url : 'upload.php',
+        chunk_size : '1mb',
+        unique_names : true,
+ 
+        // Resize images on client-side if we can
+        resize : { width : 320, height : 240, quality : 90 },
+        
+        filters : {
+            max_file_size : '10mb',
+
+			// Specify what files to browse for
+            mime_types: [
+                {title : "Image files", extensions : "jpg,gif,png"},
+                {title : "Zip files", extensions : "zip"}
+            ]
+        },
+ 
+		flash_swf_url : '../js/Moxie.swf',
+		silverlight_xap_url : '../js/Moxie.xap',
+         
+        // PreInit events, bound before the internal events
+        preinit : {
+            Init: function(up, info) {
+                log('[Init]', 'Info:', info, 'Features:', up.features);
+            },
+ 
+            UploadFile: function(up, file) {
+                log('[UploadFile]', file);
+ 
+                // You can override settings before the file is uploaded
+                // up.setOption('url', 'upload.php?id=' + file.id);
+                // up.setOption('multipart_params', {param1 : 'value1', param2 : 'value2'});
+            }
+        },
+ 
+        // Post init events, bound after the internal events
+        init : {
+			PostInit: function() {
+				// Called after initialization is finished and internal event handlers bound
+				log('[PostInit]');
+				
+				document.getElementById('uploadfiles').onclick = function() {
+					uploader.start();
+					return false;
+				};
+			},
+
+			Browse: function(up) {
+                // Called when file picker is clicked
+                log('[Browse]');
+            },
+
+            Refresh: function(up) {
+                // Called when the position or dimensions of the picker change
+                log('[Refresh]');
+            },
+ 
+            StateChanged: function(up) {
+                // Called when the state of the queue is changed
+                log('[StateChanged]', up.state == plupload.STARTED ? "STARTED" : "STOPPED");
+            },
+ 
+            QueueChanged: function(up) {
+                // Called when queue is changed by adding or removing files
+                log('[QueueChanged]');
+            },
+
+			OptionChanged: function(up, name, value, oldValue) {
+				// Called when one of the configuration options is changed
+				log('[OptionChanged]', 'Option Name: ', name, 'Value: ', value, 'Old Value: ', oldValue);
+			},
+
+			BeforeUpload: function(up, file) {
+				// Called right before the upload for a given file starts, can be used to cancel it if required
+				log('[BeforeUpload]', 'File: ', file);
+			},
+ 
+            UploadProgress: function(up, file) {
+                // Called while file is being uploaded
+                log('[UploadProgress]', 'File:', file, "Total:", up.total);
+            },
+
+			FileFiltered: function(up, file) {
+				// Called when file successfully files all the filters
+                log('[FileFiltered]', 'File:', file);
+			},
+ 
+            FilesAdded: function(up, files) {
+                // Called when files are added to queue
+                log('[FilesAdded]');
+ 
+                plupload.each(files, function(file) {
+                    log('  File:', file);
+                });
+            },
+ 
+            FilesRemoved: function(up, files) {
+                // Called when files are removed from queue
+                log('[FilesRemoved]');
+ 
+                plupload.each(files, function(file) {
+                    log('  File:', file);
+                });
+            },
+ 
+            FileUploaded: function(up, file, info) {
+                // Called when file has finished uploading
+                log('[FileUploaded] File:', file, "Info:", info);
+            },
+ 
+            ChunkUploaded: function(up, file, info) {
+                // Called when file chunk has finished uploading
+                log('[ChunkUploaded] File:', file, "Info:", info);
+            },
+
+			UploadComplete: function(up, files) {
+				// Called when all files are either uploaded or failed
+                log('[UploadComplete]');
+			},
+
+			Destroy: function(up) {
+				// Called when uploader is destroyed
+                log('[Destroy] ');
+			},
+ 
+            Error: function(up, args) {
+                // Called when error occurs
+                log('[Error] ', args);
+            }
+        }
+    });
+ 
+ 
+    function log() {
+        var str = "";
+ 
+        plupload.each(arguments, function(arg) {
+            var row = "";
+ 
+            if (typeof(arg) != "string") {
+                plupload.each(arg, function(value, key) {
+                    // Convert items in File objects to human readable form
+                    if (arg instanceof plupload.File) {
+                        // Convert status to human readable
+                        switch (value) {
+                            case plupload.QUEUED:
+                                value = 'QUEUED';
+                                break;
+ 
+                            case plupload.UPLOADING:
+                                value = 'UPLOADING';
+                                break;
+ 
+                            case plupload.FAILED:
+                                value = 'FAILED';
+                                break;
+ 
+                            case plupload.DONE:
+                                value = 'DONE';
+                                break;
+                        }
+                    }
+ 
+                    if (typeof(value) != "function") {
+                        row += (row ? ', ' : '') + key + '=' + value;
+                    }
+                });
+ 
+                str += row + " ";
+            } else {
+                str += arg + " ";
+            }
+        });
+ 
+        var log = document.getElementById('console');
+        log.innerHTML += str + "\n";
+    }
+
+	uploader.init();
+
+</script>
+</body>
+</html>

+ 139 - 0
app/assets/js/plupload-2.3.7/examples/jquery/all_runtimes.html

@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+
+<title>Plupload - Queue widget example</title>
+
+<link rel="stylesheet" href="../../js/jquery.plupload.queue/css/jquery.plupload.queue.css" type="text/css" media="screen" />
+
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
+
+<!-- production -->
+<script type="text/javascript" src="../../js/plupload.full.min.js"></script>
+<script type="text/javascript" src="../../js/jquery.plupload.queue/jquery.plupload.queue.js"></script>
+
+<!-- debug 
+<script type="text/javascript" src="../../js/moxie.js"></script>
+<script type="text/javascript" src="../../js/plupload.dev.js"></script>
+<script type="text/javascript" src="../../js/jquery.plupload.queue/jquery.plupload.queue.js"></script>
+-->
+
+</head>
+<body style="font: 13px Verdana; background: #eee; color: #333">
+
+<form method="post" action="dump.php">
+	<h1>Queue widget example</h1>
+
+	<p>Shows the jQuery Plupload Queue widget and under different runtimes.</p>
+
+	<div style="float: left; margin-right: 20px">
+		<h3>Flash runtime</h3>
+		<div id="flash_uploader" style="width: 500px; height: 330px;">Your browser doesn't have Flash installed.</div>
+
+		<h3>Silverlight runtime</h3>
+		<div id="silverlight_uploader" style="width: 500px; height: 330px;">Your browser doesn't have Silverlight installed.</div>
+	</div>
+
+	<div style="float: left; margin-right: 20px">
+		<h3>HTML 4 runtime</h3>
+		<div id="html4_uploader" style="width: 500px; height: 330px;">Your browser doesn't have HTML 4 support.</div>
+		
+		<h3>HTML 5 runtime</h3>
+		<div id="html5_uploader" style="width: 500px; height: 330px;">Your browser doesn't support native upload.</div>
+	</div>
+
+	<br style="clear: both" />
+
+	<input type="submit" value="Send" />
+</form>
+
+<script type="text/javascript">
+$(function() {
+	// Setup flash version
+	$("#flash_uploader").pluploadQueue({
+		// General settings
+		runtimes : 'flash',
+		url : '../upload.php',
+		chunk_size : '1mb',
+		unique_names : true,
+		
+		filters : {
+			max_file_size : '10mb',
+			mime_types: [
+				{title : "Image files", extensions : "jpg,gif,png"},
+				{title : "Zip files", extensions : "zip"}
+			]
+		},
+
+		// Resize images on clientside if we can
+		resize : {width : 320, height : 240, quality : 90},
+
+		// Flash settings
+		flash_swf_url : '../../js/Moxie.swf'
+	});
+
+
+	// Setup silverlight version
+	$("#silverlight_uploader").pluploadQueue({
+		// General settings
+		runtimes : 'silverlight',
+		url : '../upload.php',
+		chunk_size : '1mb',
+		unique_names : true,
+		
+		filters : {
+			max_file_size : '10mb',
+			mime_types: [
+				{title : "Image files", extensions : "jpg,gif,png"},
+				{title : "Zip files", extensions : "zip"}
+			]
+		},
+
+		// Resize images on clientside if we can
+		resize : {width : 320, height : 240, quality : 90},
+
+		// Silverlight settings
+		silverlight_xap_url : '../../js/Moxie.xap'
+	});
+
+	// Setup html5 version
+	$("#html5_uploader").pluploadQueue({
+		// General settings
+		runtimes : 'html5',
+		url : '../upload.php',
+		chunk_size : '1mb',
+		unique_names : true,
+		
+		filters : {
+			max_file_size : '10mb',
+			mime_types: [
+				{title : "Image files", extensions : "jpg,gif,png"},
+				{title : "Zip files", extensions : "zip"}
+			]
+		},
+
+		// Resize images on clientside if we can
+		resize : {width : 320, height : 240, quality : 90}
+	});
+
+
+	// Setup html4 version
+	$("#html4_uploader").pluploadQueue({
+		// General settings
+		runtimes : 'html4',
+		url : '../upload.php',
+		unique_names : true,
+		
+		filters : {
+			mime_types: [
+				{title : "Image files", extensions : "jpg,gif,png"},
+				{title : "Zip files", extensions : "zip"}
+			]
+		}
+	});
+});
+</script>
+
+</body>
+</html>

+ 113 - 0
app/assets/js/plupload-2.3.7/examples/jquery/jquery_ui_widget.html

@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+
+<title>Plupload - jQuery UI Widget</title>
+
+<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/base/jquery-ui.css" type="text/css" />
+<link rel="stylesheet" href="../../js/jquery.ui.plupload/css/jquery.ui.plupload.css" type="text/css" />
+
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
+<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
+
+<!-- production -->
+<script type="text/javascript" src="../../js/plupload.full.min.js"></script>
+<script type="text/javascript" src="../../js/jquery.ui.plupload/jquery.ui.plupload.js"></script>
+
+<!-- debug 
+<script type="text/javascript" src="../../js/moxie.js"></script>
+<script type="text/javascript" src="../../js/plupload.dev.js"></script>
+<script type="text/javascript" src="../../js/jquery.ui.plupload/jquery.ui.plupload.js"></script>
+-->
+
+</head>
+<body style="font: 13px Verdana; background: #eee; color: #333">
+
+<h1>jQuery UI Widget</h1>
+
+<p>You can see this example with different themes on the <a href="http://plupload.com/example_jquery_ui.php">www.plupload.com</a> website.</p>
+
+<form id="form" method="post" action="../dump.php">
+	<div id="uploader">
+		<p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
+	</div>
+	<br />
+	<input type="submit" value="Submit" />
+</form>
+
+<script type="text/javascript">
+// Initialize the widget when the DOM is ready
+$(function() {
+	$("#uploader").plupload({
+		// General settings
+		runtimes : 'html5,flash,silverlight,html4',
+		url : '../upload.php',
+
+		// User can upload no more then 20 files in one go (sets multiple_queues to false)
+		max_file_count: 20,
+		
+		chunk_size: '1mb',
+
+		// Resize images on clientside if we can
+		resize : {
+			width : 200, 
+			height : 200, 
+			quality : 90,
+			crop: true // crop to exact dimensions
+		},
+		
+		filters : {
+			// Maximum file size
+			max_file_size : '1000mb',
+			// Specify what files to browse for
+			mime_types: [
+				{title : "Image files", extensions : "jpg,gif,png"},
+				{title : "Zip files", extensions : "zip"}
+			]
+		},
+
+		// Rename files by clicking on their titles
+		rename: true,
+		
+		// Sort files
+		sortable: true,
+
+		// Enable ability to drag'n'drop files onto the widget (currently only HTML5 supports that)
+		dragdrop: true,
+
+		// Views to activate
+		views: {
+			list: true,
+			thumbs: true, // Show thumbs
+			active: 'thumbs'
+		},
+
+		// Flash settings
+		flash_swf_url : '../../js/Moxie.swf',
+
+		// Silverlight settings
+		silverlight_xap_url : '../../js/Moxie.xap'
+	});
+
+
+	// Handle the case when form was submitted before uploading has finished
+	$('#form').submit(function(e) {
+		// Files in queue upload them first
+		if ($('#uploader').plupload('getFiles').length > 0) {
+
+			// When all files are uploaded submit form
+			$('#uploader').on('complete', function() {
+				$('#form')[0].submit();
+			});
+
+			$('#uploader').plupload('start');
+		} else {
+			alert("You must have at least one file in the queue.");
+		}
+		return false; // Keep the form from submitting
+	});
+});
+</script>
+</body>
+</html>

+ 66 - 0
app/assets/js/plupload-2.3.7/examples/jquery/queue_widget.html

@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+
+<title>Plupload - Queue widget example</title>
+
+<link rel="stylesheet" href="../../js/jquery.plupload.queue/css/jquery.plupload.queue.css" type="text/css" media="screen" />
+
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
+
+<!-- production -->
+<script type="text/javascript" src="../../js/plupload.full.min.js"></script>
+<script type="text/javascript" src="../../js/jquery.plupload.queue/jquery.plupload.queue.js"></script>
+
+<!-- debug 
+<script type="text/javascript" src="../../js/moxie.js"></script>
+<script type="text/javascript" src="../../js/plupload.dev.js"></script>
+<script type="text/javascript" src="../../js/jquery.plupload.queue/jquery.plupload.queue.js"></script>
+-->
+
+
+</head>
+<body style="font: 13px Verdana; background: #eee; color: #333">
+
+<form method="post" action="dump.php">	
+	<div id="uploader">
+		<p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
+	</div>
+	<input type="submit" value="Send" />
+</form>
+
+<script type="text/javascript">
+$(function() {
+	
+	// Setup html5 version
+	$("#uploader").pluploadQueue({
+		// General settings
+		runtimes : 'html5,flash,silverlight,html4',
+		url : '../upload.php',
+		chunk_size: '1mb',
+		rename : true,
+		dragdrop: true,
+		
+		filters : {
+			// Maximum file size
+			max_file_size : '10mb',
+			// Specify what files to browse for
+			mime_types: [
+				{title : "Image files", extensions : "jpg,gif,png"},
+				{title : "Zip files", extensions : "zip"}
+			]
+		},
+
+		// Resize images on clientside if we can
+		resize : {width : 320, height : 240, quality : 90},
+
+		flash_swf_url : '../../js/Moxie.swf',
+		silverlight_xap_url : '../../js/Moxie.xap'
+	});
+
+});
+</script>
+
+</body>
+</html>

+ 131 - 0
app/assets/js/plupload-2.3.7/examples/jquery/s3.php

@@ -0,0 +1,131 @@
+<?php
+#!! IMPORTANT: 
+#!! this file is just an example, it doesn't incorporate any security checks and 
+#!! is not recommended to be used in production environment as it is. Be sure to 
+#!! revise it and customize to your needs.
+die("Make sure that you enable some form of authentication before removing this line.");
+
+/* 
+In order to upload files to S3 using Flash runtime, one should start by placing crossdomain.xml into the bucket.
+crossdomain.xml can be as simple as this:
+
+<?xml version="1.0"?>
+<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
+<cross-domain-policy>
+<allow-access-from domain="*" secure="false" />
+</cross-domain-policy>
+
+In our tests SilverLight didn't require anything special and worked with this configuration just fine. It may fail back
+to the same crossdomain.xml as last resort.
+
+!!!Important!!! Plupload UI Widget here, is used only for demo purposes and is not required for uploading to S3.
+*/
+
+// important variables that will be used throughout this example
+$bucket = 'BUCKET';
+
+// these can be found on your Account page, under Security Credentials > Access Keys
+$accessKeyId = 'ACCESS_KEY_ID';
+$secret = 'SECRET_ACCESS_KEY';
+
+// prepare policy
+$policy = base64_encode(json_encode(array(
+	// ISO 8601 - date('c'); generates uncompatible date, so better do it manually
+	'expiration' => date('Y-m-d\TH:i:s.000\Z', strtotime('+1 day')),  
+	'conditions' => array(
+		array('bucket' => $bucket),
+		array('acl' => 'public-read'),
+		array('starts-with', '$key', ''),
+		// for demo purposes we are accepting only images
+		array('starts-with', '$Content-Type', 'image/'),
+		// Plupload internally adds name field, so we need to mention it here
+		array('starts-with', '$name', ''), 	
+		// One more field to take into account: Filename - gets silently sent by FileReference.upload() in Flash
+		// http://docs.amazonwebservices.com/AmazonS3/latest/dev/HTTPPOSTFlash.html
+		array('starts-with', '$Filename', ''), 
+	)
+)));
+
+// sign policy
+$signature = base64_encode(hash_hmac('sha1', $policy, $secret, true));
+
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+
+<title>Plupload to Amazon S3 Example</title>
+
+<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/base/jquery-ui.css" type="text/css" />
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
+
+<!-- Load plupload and all it's runtimes and finally the UI widget -->
+<link rel="stylesheet" href="../../js/jquery.ui.plupload/css/jquery.ui.plupload.css" type="text/css" />
+
+
+<!-- production -->
+<script type="text/javascript" src="../../js/plupload.full.min.js"></script>
+<script type="text/javascript" src="../../js/jquery.ui.plupload/jquery.ui.plupload.js"></script>
+
+<!-- debug 
+<script type="text/javascript" src="../../js/moxie.js"></script>
+<script type="text/javascript" src="../../js/plupload.dev.js"></script>
+<script type="text/javascript" src="../../js/jquery.ui.plupload/jquery.ui.plupload.js"></script>
+-->
+
+</head>
+<body style="font: 13px Verdana; background: #eee; color: #333">
+
+<h1>Plupload to Amazon S3 Example</h1>
+
+<div id="uploader">
+    <p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
+</div>
+
+<script type="text/javascript">
+// Convert divs to queue widgets when the DOM is ready
+$(function() {
+	$("#uploader").plupload({
+		runtimes : 'html5,flash,silverlight',
+		url : 'http://<?php echo $bucket; ?>.s3.amazonaws.com/',
+		
+		multipart: true,
+		multipart_params: {
+			'key': '${filename}', // use filename as a key
+			'Filename': '${filename}', // adding this to keep consistency across the runtimes
+			'acl': 'public-read',
+			'Content-Type': 'image/jpeg',
+			'AWSAccessKeyId' : '<?php echo $accessKeyId; ?>',		
+			'policy': '<?php echo $policy; ?>',
+			'signature': '<?php echo $signature; ?>'
+		},
+		
+		// !!!Important!!! 
+		// this is not recommended with S3, since it will force Flash runtime into the mode, with no progress indication
+		//resize : {width : 800, height : 600, quality : 60},  // Resize images on clientside, if possible 
+		
+		// optional, but better be specified directly
+		file_data_name: 'file',
+
+		filters : {
+			// Maximum file size
+			max_file_size : '10mb',
+			// Specify what files to browse for
+			mime_types: [
+				{title : "Image files", extensions : "jpg,jpeg"}
+			]
+		},
+
+		// Flash settings
+		flash_swf_url : '../../js/Moxie.swf',
+
+		// Silverlight settings
+		silverlight_xap_url : '../../js/Moxie.xap'
+	});
+});
+</script>
+
+</body>
+</html>

+ 126 - 0
app/assets/js/plupload-2.3.7/examples/upload.php

@@ -0,0 +1,126 @@
+<?php
+/**
+ * upload.php
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+#!! IMPORTANT: 
+#!! this file is just an example, it doesn't incorporate any security checks and 
+#!! is not recommended to be used in production environment as it is. Be sure to 
+#!! revise it and customize to your needs.
+die("Make sure that you enable some form of authentication before removing this line.");
+
+
+// Make sure file is not cached (as it happens for example on iOS devices)
+header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+header("Cache-Control: no-store, no-cache, must-revalidate");
+header("Cache-Control: post-check=0, pre-check=0", false);
+header("Pragma: no-cache");
+
+/* 
+// Support CORS
+header("Access-Control-Allow-Origin: *");
+// other CORS headers if any...
+if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
+	exit; // finish preflight CORS requests here
+}
+*/
+
+// 5 minutes execution time
+@set_time_limit(5 * 60);
+
+// Uncomment this one to fake upload time
+// usleep(5000);
+
+// Settings
+$targetDir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload";
+//$targetDir = 'uploads';
+$cleanupTargetDir = true; // Remove old files
+$maxFileAge = 5 * 3600; // Temp file age in seconds
+
+
+// Create target dir
+if (!file_exists($targetDir)) {
+	@mkdir($targetDir);
+}
+
+// Get a file name
+if (isset($_REQUEST["name"])) {
+	$fileName = $_REQUEST["name"];
+} elseif (!empty($_FILES)) {
+	$fileName = $_FILES["file"]["name"];
+} else {
+	$fileName = uniqid("file_");
+}
+
+$filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
+
+// Chunking might be enabled
+$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
+$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0;
+
+
+// Remove old temp files	
+if ($cleanupTargetDir) {
+	if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
+		die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
+	}
+
+	while (($file = readdir($dir)) !== false) {
+		$tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
+
+		// If temp file is current file proceed to the next
+		if ($tmpfilePath == "{$filePath}.part") {
+			continue;
+		}
+
+		// Remove temp file if it is older than the max age and is not the current file
+		if (preg_match('/\.part$/', $file) && (filemtime($tmpfilePath) < time() - $maxFileAge)) {
+			@unlink($tmpfilePath);
+		}
+	}
+	closedir($dir);
+}	
+
+
+// Open temp file
+if (!$out = @fopen("{$filePath}.part", $chunks ? "ab" : "wb")) {
+	die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
+}
+
+if (!empty($_FILES)) {
+	if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
+		die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
+	}
+
+	// Read binary input stream and append it to temp file
+	if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
+		die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
+	}
+} else {	
+	if (!$in = @fopen("php://input", "rb")) {
+		die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
+	}
+}
+
+while ($buff = fread($in, 4096)) {
+	fwrite($out, $buff);
+}
+
+@fclose($out);
+@fclose($in);
+
+// Check if file has been uploaded
+if (!$chunks || $chunk == $chunks - 1) {
+	// Strip the temp .part suffix off 
+	rename("{$filePath}.part", $filePath);
+}
+
+// Return Success JSON-RPC response
+die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');

BIN
app/assets/js/plupload-2.3.7/js/Moxie.swf


BIN
app/assets/js/plupload-2.3.7/js/Moxie.xap


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/ar.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/az.js

@@ -0,0 +1,2 @@
+// Azerbaijani (az)
+plupload.addI18n({"Stop Upload":"Yükləməni saxla","Upload URL might be wrong or doesn't exist.":"Yükləmə ünvanı səhvdir və ya mövcud deyil","tb":"tb","Size":"Həcm","Close":"Bağla","You must specify either browse_button or drop_element.":"","Init error.":"Init error.","Add files to the upload queue and click the start button.":"Faylları əlavə edin və yüklə düyməsinə klikləyin.","List":"","Filename":"Faylın adı","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Şəklin formatı uyğun deyil və ya dəstəklənmir.","Status":"Status","HTTP Error.":"HTTP xətası.","Start Upload":"Yüklə","Error: File too large:":"Xəta:Fayl həcmi çox böyükdür.","kb":"kb","Duplicate file error.":"Bu fayl artıq növbədə var.","File size error.":"Fayl həcmi xətası.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Xəta: Yanlış fayl uzantısı:","Select files":"Faylları seçin","%s already present in the queue.":"%s artıq növbədə var.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Fayl: %s","b":"b","Uploaded %d/%d files":"%d/%d fayl yüklənib","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload element accepts only %d file(s) at a time. Extra files were stripped.","%d files queued":"Növbədə %d fayl var","File: %s, size: %d, max file size: %d":"Fayl: %s, həcm: %d, max fayl həcmi: %d","Thumbnails":"","Drag files here.":"Faylları bura çəkin.","Runtime ran out of available memory.":"Runtime ran out of available memory.","File count error.":"Fayl sayı çox böyükdür.","File extension error.":"Fayl uzantısı xətası.","mb":"mb","Add Files":"Fayl əlavə et"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/bg.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/bs.js

@@ -0,0 +1,2 @@
+// Bosnian (bs)
+plupload.addI18n({"Stop Upload":"Prekini dodavanje","Upload URL might be wrong or doesn't exist.":"URL za dodavanje je neispravan ili ne postoji.","tb":"tb","Size":"Veličina","Close":"Zatvori","You must specify either browse_button or drop_element.":"","Init error.":"Inicijalizacijska greška.","Add files to the upload queue and click the start button.":"Dodajte datoteke u red i kliknite na dugme za pokretanje.","List":"","Filename":"Naziv datoteke","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Format slike je neispravan ili nije podržan.","Status":"Status","HTTP Error.":"HTTP greška.","Start Upload":"Započni dodavanje","Error: File too large:":"Greška! Datoteka je prevelika:","kb":"kb","Duplicate file error.":"Dupla datoteka.","File size error.":"Greška u veličini datoteke.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Greška! Neispravan ekstenzija datoteke:","Select files":"Odaberite datoteke","%s already present in the queue.":"%s se već nalazi u redu.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Datoteka: %s","b":"b","Uploaded %d/%d files":"Dodano %d/%d datoteka","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Dodavanje trenutno dozvoljava samo %d datoteka istovremeno. Dodatne datoteke su uklonjene.","%d files queued":"%d datoteka čeka","File: %s, size: %d, max file size: %d":"Datoteka: %s, veličina: %d, maksimalna veličina: %d","Thumbnails":"","Drag files here.":"Dovucite datoteke ovdje.","Runtime ran out of available memory.":"Nema više dostupne memorije.","File count error.":"Greška u brojanju datoeka.","File extension error.":"Greška u ekstenziji datoteke.","mb":"mb","Add Files":"Dodaj datoteke"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/ca.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/cs.js

@@ -0,0 +1,2 @@
+// Czech (cs)
+plupload.addI18n({"Stop Upload":"Zastavit nahrávání","Upload URL might be wrong or doesn't exist.":"URL uploadu je možná špatně, nebo neexistuje.","tb":"tb","Size":"Velikost","Close":"Zavřít","You must specify either browse_button or drop_element.":"Musíte specifikovat browse_button či drop_element.","Init error.":"Chyba inicializace.","Add files to the upload queue and click the start button.":"Přidejte soubory do fronty a pak spusťte nahrávání.","List":"Seznam","Filename":"Název souboru","%s specified, but cannot be found.":"%s bylo specifikováno, ale nebylo nalezeno.","Image format either wrong or not supported.":"Špatný, nebo nepodporovaný formát obrázku.","Status":"Stav","HTTP Error.":"Chyba HTTP.","Start Upload":"Spustit nahrávání","Error: File too large:":"Chyba: Soubor je příliš veliký:","kb":"kb","Duplicate file error.":"Chyba - duplikovaný soubor.","File size error.":"Chyba velikosti souboru.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Chyba: Neplatná koncovka souboru:","Select files":"Vyberte soubory","%s already present in the queue.":"%s je již zařazen ve frontě.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"Rozlišení je mimo rozmezí! <b>%s</b> runtime podporuje obrázky pouze do %wx%hpx.","File: %s":"Soubor: %s","b":"b","Uploaded %d/%d files":"Nahráno %d/%d souborů","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload akceptuje pouze %d soubor(ů) najednou. Další soubory byly odstraněny.","%d files queued":"%d souborů ve frontě","File: %s, size: %d, max file size: %d":"Soubor: %s, velikost: %d, maximální velikost souboru: %d","Thumbnails":"Náhledy","Drag files here.":"Sem přetáhněte soubory.","Runtime ran out of available memory.":"Běh skriptu přesáhl dostupnou paměť.","File count error.":"Chyba v počtu souborů.","File extension error.":"Chyba přípony souboru.","mb":"mb","Add Files":"Přidat soubory"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/cy.js

@@ -0,0 +1,2 @@
+// Welsh (cy)
+plupload.addI18n({"Stop Upload":"Atal Lanlwytho","Upload URL might be wrong or doesn't exist.":"URL y lanlwythiad ynb anghywir neu ddim yn bodoli.","tb":"tb","Size":"Maint","Close":"Cau","You must specify either browse_button or drop_element.":"","Init error.":"Gwall cych.","Add files to the upload queue and click the start button.":"Ychwanegwch ffeiliau i'r ciw lanlwytho a chlicio'r botwm dechrau.","List":"","Filename":"Enw'r ffeil","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Fformat delwedd yn anghywir neu heb ei gynnal.","Status":"Statws","HTTP Error.":"Gwall HTTP.","Start Upload":"Dechrau Lanlwytho","Error: File too large:":"Gwall: Ffeil yn rhy fawr:","kb":"kb","Duplicate file error.":"Gwall ffeil ddyblyg.","File size error.":"Gwall maint ffeil.","N/A":"Dd/A","gb":"gb","Error: Invalid file extension:":"Gwall: estyniad ffeil annilys:","Select files":"Dewis ffeiliau","%s already present in the queue.":"%s yn y ciw yn barod.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Ffeil: %s","b":"b","Uploaded %d/%d files":"Lanlwythwyd  %d/%d ffeil","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Mae'r elfen lanlwytho yn derbyn %d ffeil ar y tro. Caiff ffeiliau ychwanegol eu tynnu.","%d files queued":"%d ffeil mewn ciw","File: %s, size: %d, max file size: %d":"Ffeil: %s, maint: %d, maint mwyaf ffeil: %d","Thumbnails":"","Drag files here.":"Llusgwch ffeiliau yma.","Runtime ran out of available memory.":"Allan o gof.","File count error.":"Gwall cyfri ffeiliau.","File extension error.":"Gwall estyniad ffeil.","mb":"mb","Add Files":"Ychwanegu Ffeiliau"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/da.js

@@ -0,0 +1,2 @@
+// Danish (da)
+plupload.addI18n({"Stop Upload":"Stop upload","Upload URL might be wrong or doesn't exist.":"Upload URL kan være forkert eller ikke eksisterende.","tb":"tb","Size":"Størrelse","Close":"Luk","You must specify either browse_button or drop_element.":"","Init error.":"Opstarts fejl.","Add files to the upload queue and click the start button.":"Tilføj filer til køen og klik Start upload knappen.","List":"","Filename":"Filnavn","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Billede format er enten forkert eller ikke understøttet.","Status":"Status","HTTP Error.":"HTTP fejl.","Start Upload":"Start upload","Error: File too large:":"Fejl: Filen er for stor:","kb":"kb","Duplicate file error.":"Filen findes allerede.","File size error.":"Filstørrelse fejl.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Fejl: Ugyldigt fil format:","Select files":"Vælg filer","%s already present in the queue.":"%s findes allerede i køen.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Fil: %s","b":"b","Uploaded %d/%d files":"Uploaded %d/%d filer","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload accepterer kun %d fil(er) af gangen. Ekstra filer blev skippet.","%d files queued":"%d filer i kø","File: %s, size: %d, max file size: %d":"Fil: %s, størrelse: %d, maks. filstørrelse: %d","Thumbnails":"","Drag files here.":"Træk filer her.","Runtime ran out of available memory.":"Runtime mangler tilgængelige hukommelse.","File count error.":"Fil antal fejl.","File extension error.":"Fil format fejl.","mb":"mb","Add Files":"Tilføj filer"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/de.js

@@ -0,0 +1,2 @@
+// German (de)
+plupload.addI18n({"Stop Upload":"Hochladen abbrechen","Upload URL might be wrong or doesn't exist.":"Upload-URL ist falsch oder existiert nicht.","tb":"TB","Size":"Größe","Close":"Schließen","You must specify either browse_button or drop_element.":"","Init error.":"Initialisierungsfehler","Add files to the upload queue and click the start button.":"Dateien hinzufügen und auf 'Hochladen' klicken.","List":"Liste","Filename":"Dateiname","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Bildformat falsch oder nicht unterstützt.","Status":"Status","HTTP Error.":"HTTP-Fehler","Start Upload":"Hochladen beginnen","Error: File too large:":"Fehler: Datei zu groß:","kb":"KB","Duplicate file error.":"Datei bereits hochgeladen","File size error.":"Fehler bei Dateigröße","N/A":"Nicht verfügbar","gb":"GB","Error: Invalid file extension:":"Fehler: Ungültige Dateiendung:","Select files":"Dateien auswählen","%s already present in the queue.":"%s ist bereits in der Warteschlange","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Datei: %s","b":"B","Uploaded %d/%d files":"%d/%d Dateien wurden hochgeladen","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Pro Durchgang können nur %d Datei(en) akzeptiert werden. Überzählige Dateien wurden ignoriert.","%d files queued":"%d Dateien in der Warteschlange","File: %s, size: %d, max file size: %d":"Datei: %s, Größe: %d, maximale Dateigröße: %d","Thumbnails":"Vorschaubilder","Drag files here.":"Dateien auf diese Fläche bewegen.","Runtime ran out of available memory.":"Nicht genügend Speicher verfügbar.","File count error.":"Fehlerhafte Dateianzahl.","File extension error.":"Fehler bei Dateiendung","mb":"MB","Add Files":"Dateien hinzufügen"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/el.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/en.js

@@ -0,0 +1,2 @@
+// English (en)
+plupload.addI18n({"Stop Upload":"Stop Upload","Upload URL might be wrong or doesn't exist.":"Upload URL might be wrong or doesn't exist.","tb":"tb","Size":"Size","Close":"Close","You must specify either browse_button or drop_element.":"You must specify either browse_button or drop_element.","Init error.":"Init error.","Add files to the upload queue and click the start button.":"Add files to the upload queue and click the start button.","List":"List","Filename":"Filename","%s specified, but cannot be found.":"%s specified, but cannot be found.","Image format either wrong or not supported.":"Image format either wrong or not supported.","Status":"Status","HTTP Error.":"HTTP Error.","Start Upload":"Start Upload","Error: File too large:":"Error: File too large:","kb":"kb","Duplicate file error.":"Duplicate file error.","File size error.":"File size error.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Error: Invalid file extension:","Select files":"Select files","%s already present in the queue.":"%s already present in the queue.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.","File: %s":"File: %s","b":"b","Uploaded %d/%d files":"Uploaded %d/%d files","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload element accepts only %d file(s) at a time. Extra files were stripped.","%d files queued":"%d files queued","File: %s, size: %d, max file size: %d":"File: %s, size: %d, max file size: %d","Thumbnails":"Thumbnails","Drag files here.":"Drag files here.","Runtime ran out of available memory.":"Runtime ran out of available memory.","File count error.":"File count error.","File extension error.":"File extension error.","mb":"mb","Add Files":"Add Files"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/es.js

@@ -0,0 +1,2 @@
+// Spanish (es)
+plupload.addI18n({"Stop Upload":"Detener Subida.","Upload URL might be wrong or doesn't exist.":"URL de carga inexistente.","tb":"TB","Size":"Tamaño","Close":"Cerrar","You must specify either browse_button or drop_element.":"Debe especificar el browse_button o el drop_element","Init error.":"Error de inicialización.","Add files to the upload queue and click the start button.":"Agregue archivos a la lista de subida y pulse clic en el botón de Iniciar carga","List":"Lista","Filename":"Nombre de archivo","%s specified, but cannot be found.":"%s especificado, pero no se puede encontrar","Image format either wrong or not supported.":"Formato de imagen no soportada.","Status":"Estado","HTTP Error.":"Error de HTTP.","Start Upload":"Iniciar carga","Error: File too large:":"Error: archivo demasiado grande:","kb":"KB","Duplicate file error.":"Error, archivo duplicado","File size error.":"Error de tamaño de archivo.","N/A":"No disponible","gb":"GB","Error: Invalid file extension:":"Error: Extensión de archivo inválida:","Select files":"Elija archivos","%s already present in the queue.":"%s ya se encuentra en la lista.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"Resolución fuera de límites! El tiempo de ejecución <b>%s</b> sólo admite imágenes hasta %wx%hpx","File: %s":"Archivo: %s","b":"B","Uploaded %d/%d files":"Subidos %d/%d archivos","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Se aceptan sólo %d archivo(s) al tiempo. Más, no se tienen en cuenta.","%d files queued":"%d archivos en cola.","File: %s, size: %d, max file size: %d":"Archivo: %s, tamaño: %d, tamaño máximo de archivo: %d","Thumbnails":"Miniaturas","Drag files here.":"Arrastre archivos aquí","Runtime ran out of available memory.":"No hay memoria disponible.","File count error.":"Error en contador de archivos.","File extension error.":"Error de extensión de archivo.","mb":"MB","Add Files":"Agregar archivos"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/et.js

@@ -0,0 +1,2 @@
+// Estonian (et)
+plupload.addI18n({"Stop Upload":"Stop Upload","Upload URL might be wrong or doesn't exist.":"Üleslaadimise URL võib olla vale või seda pole.","tb":"","Size":"Suurus","Close":"Sulge","You must specify either browse_button or drop_element.":"","Init error.":"Lähtestamise viga.","Add files to the upload queue and click the start button.":"Lisa failid üleslaadimise järjekorda ja klõpsa alustamise nupule.","List":"","Filename":"Failinimi","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Image format either wrong or not supported.","Status":"Olek","HTTP Error.":"HTTP ühenduse viga.","Start Upload":"Start Upload","Error: File too large:":"Error: File too large:","kb":"","Duplicate file error.":"","File size error.":"Failisuuruse viga.","N/A":"N/A","gb":"","Error: Invalid file extension:":"Error: Invalid file extension:","Select files":"Vali faile","%s already present in the queue.":"","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Fail: %s","b":"","Uploaded %d/%d files":"Üles laaditud %d/%d","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Üleslaadimise element saab vastu võtta ainult %d faili ühe korraga. Ülejäänud failid jäetakse laadimata.","%d files queued":"Järjekorras on %d faili","File: %s, size: %d, max file size: %d":"","Thumbnails":"","Drag files here.":"Lohista failid siia.","Runtime ran out of available memory.":"Runtime ran out of available memory.","File count error.":"Failide arvu viga.","File extension error.":"Faililaiendi viga.","mb":"","Add Files":"Add Files"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/fa.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/fi.js

@@ -0,0 +1,2 @@
+// Finnish (fi)
+plupload.addI18n({"Stop Upload":"Pysäytä lähetys","Upload URL might be wrong or doesn't exist.":"Lähetyksen URL-osoite saattaa olla väärä tai sitä ei ole olemassa.","tb":"TB","Size":"Koko","Close":"Sulje","You must specify either browse_button or drop_element.":"","Init error.":"Init virhe.","Add files to the upload queue and click the start button.":"Lisää tiedostoja lähetysjonoon ja klikkaa aloita-nappia.","List":"","Filename":"Tiedostonimi","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Kuvaformaatti on joko väärä tai ei tuettu.","Status":"Tila","HTTP Error.":"HTTP-virhe.","Start Upload":"Aloita lähetys","Error: File too large:":"Virhe: Liian suuri tiedosto:","kb":"kB","Duplicate file error.":"Tuplatiedostovirhe.","File size error.":"Tiedostokokovirhe.","N/A":"N/A","gb":"GB","Error: Invalid file extension:":"Virhe: Virheellinen tiedostopääte:","Select files":"Valitse tiedostoja","%s already present in the queue.":"%s on jo jonossa.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Tiedosto: %s","b":"B","Uploaded %d/%d files":"Lähetetty %d/%d tiedostoa","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Vain %d tiedosto(a) voidaan lähettää kerralla. Ylimääräiset tiedostot ohitettiin.","%d files queued":"%d tiedostoa jonossa","File: %s, size: %d, max file size: %d":"Tiedosto: %s, koko: %d, suurin sallittu tiedostokoko: %d","Thumbnails":"","Drag files here.":"Raahaa tiedostot tähän.","Runtime ran out of available memory.":"Toiminnon käytettävissä oleva muisti loppui kesken.","File count error.":"Tiedostolaskentavirhe.","File extension error.":"Tiedostopäätevirhe.","mb":"MB","Add Files":"Lisää tiedostoja"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/fr.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/he.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/hr.js

@@ -0,0 +1,2 @@
+// Croatian (hr)
+plupload.addI18n({"Stop Upload":"Zaustavi upload.","Upload URL might be wrong or doesn't exist.":"Upload URL might be wrong or doesn't exist.","tb":"tb","Size":"Veličina","Close":"Zatvori","You must specify either browse_button or drop_element.":"","Init error.":"Greška inicijalizacije.","Add files to the upload queue and click the start button.":"Dodajte datoteke u listu i kliknite Upload.","List":"","Filename":"Ime datoteke","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Image format either wrong or not supported.","Status":"Status","HTTP Error.":"HTTP greška.","Start Upload":"Pokreni upload.","Error: File too large:":"Pogreška: Datoteka je prevelika:","kb":"kb","Duplicate file error.":"Pogreška dvostruke datoteke.","File size error.":"Greška veličine datoteke.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Pogreška: Nevažeći nastavak datoteke:","Select files":"Odaberite datoteke:","%s already present in the queue.":"%s  je već prisutan  u listi čekanja.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Datoteka: %s","b":"b","Uploaded %d/%d files":"Uploadano %d/%d datoteka","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload element accepts only %d file(s) at a time. Extra files were stripped.","%d files queued":"%d datoteka na čekanju.","File: %s, size: %d, max file size: %d":"Datoteka: %s, veličina: %d, maksimalna veličina: %d","Thumbnails":"","Drag files here.":"Dovucite datoteke ovdje","Runtime ran out of available memory.":"Runtime aplikaciji  je ponestalo memorije.","File count error.":"Pogreška u broju datoteka.","File extension error.":"Pogreška u nastavku datoteke.","mb":"mb","Add Files":"Dodaj datoteke"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/hu.js

@@ -0,0 +1,2 @@
+// Hungarian (hu)
+plupload.addI18n({"Stop Upload":"Feltöltés leállítása","Upload URL might be wrong or doesn't exist.":"A feltöltő URL hibás vagy nem létezik.","tb":"TB","Size":"Méret","Close":"Bezárás","You must specify either browse_button or drop_element.":"","Init error.":"Init hiba.","Add files to the upload queue and click the start button.":"A fájlok feltöltési sorhoz való hozzáadása után az Indítás gombra kell kattintani.","List":"","Filename":"Fájlnév","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Rossz vagy nem támogatott képformátum.","Status":"Állapot","HTTP Error.":"HTTP-hiba.","Start Upload":"Feltöltés indítása","Error: File too large:":"Hiba: a fájl túl nagy:","kb":"kB","Duplicate file error.":"Duplikáltfájl-hiba.","File size error.":"Hibás fájlméret.","N/A":"Nem elérhető","gb":"GB","Error: Invalid file extension:":"Hiba: érvénytelen fájlkiterjesztés:","Select files":"Fájlok kiválasztása","%s already present in the queue.":"%s már szerepel a listában.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Fájl: %s","b":"b","Uploaded %d/%d files":"Feltöltött fájlok: %d/%d","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"A feltöltés egyszerre csak %d fájlt fogad el, a többi fájl nem lesz feltöltve.","%d files queued":"%d fájl sorbaállítva","File: %s, size: %d, max file size: %d":"Fájl: %s, méret: %d, legnagyobb fájlméret: %d","Thumbnails":"","Drag files here.":"Ide lehet húzni a fájlokat.","Runtime ran out of available memory.":"Futásidőben elfogyott a rendelkezésre álló memória.","File count error.":"A fájlok számával kapcsolatos hiba.","File extension error.":"Hibás fájlkiterjesztés.","mb":"MB","Add Files":"Fájlok hozzáadása"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/hy.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/id.js

@@ -0,0 +1,2 @@
+// Indonesian (id)
+plupload.addI18n({"Stop Upload":"Hentikan Upload","Upload URL might be wrong or doesn't exist.":"Alamat URL untuk upload tidak benar atau tidak ada","tb":"tb","Size":"Ukuran","Close":"Tutup","You must specify either browse_button or drop_element.":"","Init error.":"Kesalahan pada Init","Add files to the upload queue and click the start button.":"Tambahkan file kedalam antrian upload dan klik tombol Mulai","List":"","Filename":"Nama File","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Kesalahan pada jenis gambar atau jenis file tidak didukung","Status":"Status","HTTP Error.":"HTTP Bermasalah","Start Upload":"Mulai Upload","Error: File too large:":"Kesalahan: File terlalu besar","kb":"kb","Duplicate file error.":"Terjadi duplikasi file","File size error.":"Kesalahan pada ukuran file","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Kesalahan: Ekstensi file tidak dikenal","Select files":"Pilih file","%s already present in the queue.":"%s sudah ada dalam daftar antrian","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"File: %s","b":"b","Uploaded %d/%d files":"File terupload %d/%d","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Tempat untuk upload hanya menerima %d file(s) dalam setiap upload. File lainnya tidak akan disertakan","%d files queued":"%d file dalam antrian","File: %s, size: %d, max file size: %d":"File: %s, ukuran: %d, maksimum ukuran file: %d","Thumbnails":"","Drag files here.":"Tarik file kesini","Runtime ran out of available memory.":"Tidak cukup memori","File count error.":"Kesalahan pada jumlah file","File extension error.":"Kesalahan pada ekstensi file","mb":"mb","Add Files":"Tambah File"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/it.js

@@ -0,0 +1,2 @@
+// Italian (it)
+plupload.addI18n({"Stop Upload":"Ferma Upload","Upload URL might be wrong or doesn't exist.":"URL di Upload errata o non esistente","tb":"tb","Size":"Dimensione","Close":"Chiudi","You must specify either browse_button or drop_element.":"Devi indicare almeno uno tra browse_button o drop_element.","Init error.":"Errore inizializzazione.","Add files to the upload queue and click the start button.":"Aggiungi i file alla coda di caricamento e clicca il pulsante di avvio.","List":"Lista","Filename":"Nome file","%s specified, but cannot be found.":"%s specificato, ma non è stato possibile trovarlo.","Image format either wrong or not supported.":"Formato immagine errato o non supportato.","Status":"Stato","HTTP Error.":"Errore HTTP.","Start Upload":"Inizia Upload","Error: File too large:":"Errore: File troppo grande:","kb":"kb","Duplicate file error.":"Errore file duplicato.","File size error.":"Errore dimensione file.","N/A":"N/D","gb":"gb","Error: Invalid file extension:":"Errore: Estensione file non valida:","Select files":"Seleziona i files","%s already present in the queue.":"%s già presente nella coda.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"Risoluzione oltre i limiti! <b>%s</b> runtime supporta immagini fino a %wx%hpx.","File: %s":"File: %s","b":"byte","Uploaded %d/%d files":"Caricati %d/%d file","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload element accepts only %d file(s) at a time. Extra files were stripped.","%d files queued":"%d file in coda","File: %s, size: %d, max file size: %d":"File: %s, dimensione: %d, dimensione max file: %d","Thumbnails":"Anteprime","Drag files here.":"Trascina i files qui.","Runtime ran out of available memory.":"Runtime ha esaurito la memoria disponibile.","File count error.":"File count error.","File extension error.":"Errore estensione file.","mb":"mb","Add Files":"Aggiungi file"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/ja.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/ka.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/kk.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/km.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/ko.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/ku_IQ.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/lt.js

@@ -0,0 +1,2 @@
+// Lithuanian (lt)
+plupload.addI18n({"Stop Upload":"Stabdyti įkėlimą","Upload URL might be wrong or doesn't exist.":"Klaidinga arba neegzistuojanti įkėlimo nuoroda.","tb":"tb","Size":"Dydis","Close":"Uždaryti","You must specify either browse_button or drop_element.":"","Init error.":"Įkrovimo klaida.","Add files to the upload queue and click the start button.":"Pridėkite bylas į įkėlimo eilę ir paspauskite starto mygtuką.","List":"","Filename":"Bylos pavadinimas","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Paveiksliuko formatas klaidingas arba nebepalaikomas.","Status":"Statusas","HTTP Error.":"HTTP klaida.","Start Upload":"Pradėti įkėlimą","Error: File too large:":"Klaida: Byla per didelė:","kb":"kb","Duplicate file error.":"Pasikartojanti byla.","File size error.":"Netinkamas bylos dydis.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Klaida: Netinkamas bylos plėtinys:","Select files":"Žymėti bylas","%s already present in the queue.":"%s jau yra eilėje.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Byla: %s","b":"b","Uploaded %d/%d files":"Įkelta bylų: %d/%d","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Vienu metu galima įkelti tik %d bylas(ų). Papildomos bylos buvo pašalintos.","%d files queued":"%d bylų eilėje","File: %s, size: %d, max file size: %d":"Byla: %s, dydis: %d, galimas dydis: %d","Thumbnails":"","Drag files here.":"Padėti bylas čia.","Runtime ran out of available memory.":"Išeikvota darbinė atmintis.","File count error.":"Netinkamas bylų kiekis.","File extension error.":"Netinkamas pletinys.","mb":"mb","Add Files":"Pridėti bylas"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/lv.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/ms.js

@@ -0,0 +1,2 @@
+// Malay (ms)
+plupload.addI18n({"Stop Upload":"Berhenti Muat naik","Upload URL might be wrong or doesn't exist.":"URL muat naik mungkin salah atau tidak wujud.","tb":"tb","Size":"saiz","Close":"Tutup","You must specify either browse_button or drop_element.":"","Init error.":"Ralat perlaksanaan.","Add files to the upload queue and click the start button.":"Tambah fail ke dalam giliran muat naik dan klik butang Muat Naik.","List":"","Filename":"Nama fail","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Format imej sama ada salah atau tidak disokong.","Status":"Status","HTTP Error.":"Ralat HTTP.","Start Upload":"Muat Naik","Error: File too large:":"Ralat: Fail terlalu bersar:","kb":"kb","Duplicate file error.":"Ralat menggandakan fail.","File size error.":"Ralat saiz fail.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Ralat: Sambungan fail tidak sah:","Select files":"Pilih fail","%s already present in the queue.":"%s telah ada dalam barisan.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Fail: %s","b":"b","Uploaded %d/%d files":"%d/%d telah dimuat naik","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Element muat naik hanya menerima %d fail(-fail) pada satu masa. Fail tambahan telah digugurkan.","%d files queued":"%d fail dalam barisan","File: %s, size: %d, max file size: %d":"Fail: %s, saiz: %d, saiz maks fail: %d","Thumbnails":"","Drag files here.":"Seret fail ke sini.","Runtime ran out of available memory.":"Ruang ingatan masa larian tidak mencukupi.","File count error.":"Ralat bilangan fail.","File extension error.":"Ralat sambungan fail.","mb":"mb","Add Files":"Tambah Fail"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/nl.js

@@ -0,0 +1,2 @@
+// Dutch (nl)
+plupload.addI18n({"Stop Upload":"Stop Upload","Upload URL might be wrong or doesn't exist.":"Upload URL is verkeerd of bestaat niet.","tb":"tb","Size":"Grootte","Close":"Sluiten","You must specify either browse_button or drop_element.":"","Init error.":"Initialisatie error.","Add files to the upload queue and click the start button.":"Voeg bestanden toe aan de wachtrij en druk op 'Start'.","List":"","Filename":"Bestandsnaam","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"bestandsextensie is verkeerd of niet ondersteund.","Status":"Status","HTTP Error.":"HTTP Error.","Start Upload":"Start Upload","Error: File too large:":"Error: Bestand te groot:","kb":"kb","Duplicate file error.":"Bestand bestaat al.","File size error.":"Bestandsgrootte error.","N/A":"Niet beschikbaar","gb":"gb","Error: Invalid file extension:":"Error: Ongeldige bestandsextensie:","Select files":"Selecteer bestand(en):","%s already present in the queue.":"%s is al aan de wachtrij toegevoegd.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Bestand: %s","b":"b","Uploaded %d/%d files":"%d/%d bestanden ge-upload","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload accepteert alleen %d bestand(en) tegelijk. Extra bestanden zijn verwijderd.","%d files queued":"%d bestand(en) in de wachtrij","File: %s, size: %d, max file size: %d":"Bestand: %s, grootte: %d, maximale bestandsgrootte: %d","Thumbnails":"","Drag files here.":"Sleep bestanden hierheen.","Runtime ran out of available memory.":"Het maximum bruikbare geheugen is overschreden.","File count error.":"Teveel bestand(en) error.","File extension error.":"Ongeldig bestandsextensie.","mb":"mb","Add Files":"Bestand(en) toevoegen"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/pl.js

@@ -0,0 +1,2 @@
+// Polish (pl)
+plupload.addI18n({"Stop Upload":"Przerwij transfer.","Upload URL might be wrong or doesn't exist.":"Adres URL może być nieprawidłowy lub może nie istnieć","tb":"tb","Size":"Rozmiar","Close":"Zamknij","You must specify either browse_button or drop_element.":"Musisz określić browse_button albo drop_element.","Init error.":"Błąd inicjalizacji.","Add files to the upload queue and click the start button.":"Dodaj pliki i kliknij 'Rozpocznij transfer'.","List":"Lista","Filename":"Nazwa pliku","%s specified, but cannot be found.":"%s określony ale nie można znaleźć.","Image format either wrong or not supported.":"Format zdjęcia jest zły lub nieobsługiwany","Status":"Status","HTTP Error.":"Błąd HTTP.","Start Upload":"Wyślij","Error: File too large:":"Błąd: Plik za duży:","kb":"kb","Duplicate file error.":"Błąd: duplikacja pliku.","File size error.":"Plik jest zbyt duży.","N/A":"Nie dostępne","gb":"gb","Error: Invalid file extension:":"Błąd: Nieprawidłowe rozszerzenie pliku:","Select files":"Wybierz pliki:","%s already present in the queue.":"%s już występuje w kolejce.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"Za duża rozdzielczość! <b>%s</b> maksymalna rozdzielczość to: %wx%hpx.","File: %s":"Plik: %s","b":"b","Uploaded %d/%d files":"Wysłano %d/%d plików","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Można jednocześnie dodać %d plików. Dodatkowe pliki zostały usunięte.","%d files queued":"%d plików w kolejce.","File: %s, size: %d, max file size: %d":"Plik: %s, rozmiar: %d, maksymalny rozmiar pliku: %d","Thumbnails":"Miniatury","Drag files here.":"Przeciągnij tu pliki","Runtime ran out of available memory.":"Wyczerpano pamięć RAM.","File count error.":"Błąd liczenia pliku.","File extension error.":"Nie obsługiwany format pliku.","mb":"mb","Add Files":"Dodaj pliki"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/pt.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/pt_BR.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/ro.js

@@ -0,0 +1,2 @@
+// Romanian (ro)
+plupload.addI18n({"Stop Upload":"Oprește încărcarea","Upload URL might be wrong or doesn't exist.":"Upload URL might be wrong or doesn't exist.","tb":"tb","Size":"Mărime","Close":"Închide","You must specify either browse_button or drop_element.":"","Init error.":"Eroare inițializare.","Add files to the upload queue and click the start button.":"Adaugă fișiere în lista apoi apasă butonul \"Începe încărcarea\".","List":"","Filename":"Nume fișier","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Formatul de imagine ori este greșit ori nu este suportat.","Status":"Stare","HTTP Error.":"Eroare HTTP","Start Upload":"Începe încărcarea","Error: File too large:":"Eroare: Fișierul este prea mare:","kb":"kb","Duplicate file error.":"Eroare duplicat fișier.","File size error.":"Eroare dimensiune fișier.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Eroare: Extensia fișierului este invalidă:","Select files":"Selectează fișierele","%s already present in the queue.":"%s există deja în lista de așteptare.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Fișier: %s","b":"b","Uploaded %d/%d files":"Fișiere încărcate %d/%d","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload element accepts only %d file(s) at a time. Extra files were stripped.","%d files queued":"%d fișiere listate","File: %s, size: %d, max file size: %d":"Fișier: %s, mărime: %d, mărime maximă: %d","Thumbnails":"","Drag files here.":"Trage aici fișierele.","Runtime ran out of available memory.":"Runtime ran out of available memory.","File count error.":"Eroare numărare fișiere.","File extension error.":"Eroare extensie fișier.","mb":"mb","Add Files":"Adaugă fișiere"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/ru.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/sk.js

@@ -0,0 +1,2 @@
+// Slovak (sk)
+plupload.addI18n({"Stop Upload":"Zastaviť nahrávanie","Upload URL might be wrong or doesn't exist.":"URL pre nahratie nie je správna alebo neexistuje.","tb":"tb","Size":"Veľkosť","Close":"Zatvoriť","You must specify either browse_button or drop_element.":"","Init error.":"Chyba inicializácie.","Add files to the upload queue and click the start button.":"Pridajte súbory do zoznamu a potom spustite nahrávanie.","List":"","Filename":"Názov súboru","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Formát obrázku je nesprávny alebo nie je podporovaný.","Status":"Stav","HTTP Error.":"HTTP Chyba.","Start Upload":"Spustiť nahrávanie","Error: File too large:":"Chyba: Súbor je príliš veľký:","kb":"kb","Duplicate file error.":"Duplicitný súbor.","File size error.":"Súbor je príliš veľký.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Error: Nesprávny typ súboru:","Select files":"Vyberte súbory","%s already present in the queue.":"%s sa už nachádza v zozname.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Súbor: %s","b":"b","Uploaded %d/%d files":"Nahraných %d/%d súborov","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload element accepts only %d file(s) at a time. Extra files were stripped.","%d files queued":"%d súborov pridaných do zoznamu","File: %s, size: %d, max file size: %d":"Súbor: %s, veľkosť: %d, max. veľkosť súboru: %d","Thumbnails":"","Drag files here.":"Sem pretiahnite súbory.","Runtime ran out of available memory.":"Runtime ran out of available memory.","File count error.":"Nesprávny počet súborov.","File extension error.":"Chybný typ súboru.","mb":"mb","Add Files":"Pridať súbory"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/sl.js

@@ -0,0 +1,2 @@
+// Slovenian (sl)
+plupload.addI18n({"Stop Upload":"Ustavi prenos","Upload URL might be wrong or doesn't exist.":"URL za nalaganje je napačen ali ne obstaja.","tb":"tb","Size":"Velikost","Close":"Zapri","You must specify either browse_button or drop_element.":"","Init error.":"Napaka pri inicializaciji.","Add files to the upload queue and click the start button.":"Dodaj datoteke na seznam in klikni na gumb začni","List":"Seznam","Filename":"Ime datoteke","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Format slike je napačen ali ni podrpt.","Status":"Status","HTTP Error.":"Neznana HTTP napaka.","Start Upload":"Začni prenos","Error: File too large:":"Napaka: datoteka je prevelika:","kb":"kb","Duplicate file error.":"Datoteka je že na seznamu.","File size error.":"Datoteka je prevelika.","N/A":"Ni na voljo","gb":"gb","Error: Invalid file extension:":"Napaka: napačen tip datoteke:","Select files":"Izberi datoteke","%s already present in the queue.":"%s je že na seznamu.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Datoteka: %s","b":"b","Uploaded %d/%d files":"Naloženo %d/%d datotek","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Nalagalnik sprejme samo %d datotek na enkrat. Višek datotek je odstranjen iz seznama.","%d files queued":"%d datotek na seznamu","File: %s, size: %d, max file size: %d":"Datoteka: %s, velikost: %d, največja dovoljena velikost: %d","Thumbnails":"Sličice","Drag files here.":"Potegni datoteke sem.","Runtime ran out of available memory.":"Zmanjkalo je pomnilnika.","File count error.":"Napačno število datotek.","File extension error.":"Napačen tip datoteke.","mb":"mb","Add Files":"Dodaj datoteke"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/sq.js

@@ -0,0 +1,2 @@
+// Albanian (sq)
+plupload.addI18n({"Stop Upload":"Ndalimi i ngarkimit","Upload URL might be wrong or doesn't exist.":"Ngarkimi i URL-s është i gabuar ose nuk ekziston.","tb":"TB","Size":"Madhësia","Close":"Mbyll","You must specify either browse_button or drop_element.":"","Init error.":"Init gabim.","Add files to the upload queue and click the start button.":"Mbas ngarkimit të dosjeve sipas rradhës duhet të klikoni butonin Start.","List":"","Filename":"Emri i dosjes","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Formati i fotove është i keq ose nuk është i pranueshëm.","Status":"Statusi","HTTP Error.":"HTTP Gabim.","Start Upload":"Nisja e ngarkimit","Error: File too large:":"Gabim: dosja është shumë e madhe:","kb":"KB","Duplicate file error.":"Gabim i dublikimit të dosjes.","File size error.":"Gabim i madhësisë së dosjes.","N/A":"Nuk është në dispozicion","gb":"GB","Error: Invalid file extension:":"Gabim: përhapja e llojit të dosjes është e pavlefshme:","Select files":"Zhgjidhni dosjet","%s already present in the queue.":"%s tashmë ekziston në list.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"Dosje: %s","b":"B","Uploaded %d/%d files":"Dosjet e ngarkuara: %d/%d","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Ngarkimi pranon njëherësh vetëm %d dosje, dosjet e tjera nuk do të jenë të ngarkuara.","%d files queued":"Dosja %d e vendosur në rradhë","File: %s, size: %d, max file size: %d":"Dosje: %s, madhësia: %d, madhësia maximale e dosjes: %d","Thumbnails":"","Drag files here.":"Këtu mund të tërhiqni dosjet","Runtime ran out of available memory.":"Memoria që ishte në dispozicion ka mbaruar.","File count error.":"Gabim në lidhje me numrin e dosjeve.","File extension error.":"Gabim i zgjerimit të dosjes.","mb":"MB","Add Files":"Shtoni dosjet"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/sr.js

@@ -0,0 +1,2 @@
+// Serbian (sr)
+plupload.addI18n({"Stop Upload":"Stop Upload","Upload URL might be wrong or doesn't exist.":"Upload URL might be wrong or doesn't exist.","tb":"","Size":"Veličina","Close":"Close","You must specify either browse_button or drop_element.":"","Init error.":"Init error.","Add files to the upload queue and click the start button.":"Dodajte fajlove u listu i kliknite na dugme Start.","List":"","Filename":"Naziv fajla","%s specified, but cannot be found.":"","Image format either wrong or not supported.":"Image format either wrong or not supported.","Status":"Status","HTTP Error.":"HTTP Error.","Start Upload":"Počni upload","Error: File too large:":"Error: File too large:","kb":"","Duplicate file error.":"","File size error.":"File size error.","N/A":"N/A","gb":"","Error: Invalid file extension:":"Error: Invalid file extension:","Select files":"Izaberite fajlove","%s already present in the queue.":"","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"","File: %s":"File: %s","b":"","Uploaded %d/%d files":"Snimljeno %d/%d fajlova","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Upload element accepts only %d file(s) at a time. Extra files were stripped.","%d files queued":"%d files queued","File: %s, size: %d, max file size: %d":"","Thumbnails":"","Drag files here.":"Prevucite fajlove ovde.","Runtime ran out of available memory.":"Runtime ran out of available memory.","File count error.":"File count error.","File extension error.":"File extension error.","mb":"","Add Files":"Dodaj fajlove"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/sv.js

@@ -0,0 +1,2 @@
+// Swedish (sv)
+plupload.addI18n({"Stop Upload":"Avbryt","Upload URL might be wrong or doesn't exist.":"URL:en va fel eller existerar inte.","tb":"tb","Size":"Storlek","Close":"Stäng","You must specify either browse_button or drop_element.":"Du behöver specificera browse_button eller drop_element.","Init error.":"Problem vid initialisering.","Add files to the upload queue and click the start button.":"Lägg till filer till kön och tryck på start.","List":"Lista","Filename":"Filnamn","%s specified, but cannot be found.":"%s specificerad, men hittades inte.","Image format either wrong or not supported.":"Bildformatet är fel eller så finns inte stöd för det.","Status":"Status","HTTP Error.":"HTTP problem.","Start Upload":"Starta","Error: File too large:":"Fel: Filen är för stor:","kb":"kb","Duplicate file error.":"Problem med dubbla filer.","File size error.":"Problem med filstorlek.","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"Fel: Ej godkänd filändelse.","Select files":"Välj filer","%s already present in the queue.":"%s är redan tillagd.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"Upplösning utanför gränserna! <b>%s</b> bara bilder upp till %wx%hpx stöds.","File: %s":"Fil: %s","b":"b","Uploaded %d/%d files":"Laddade upp %d/%d filer","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Det går bara lägga till %d filer åt gången, allt utöver detta togs bort.","%d files queued":"%d filer i kö","File: %s, size: %d, max file size: %d":"Fil: %s, storlek: %d, max storlek: %d","Thumbnails":"Miniatyrer","Drag files here.":"Dra filer hit","Runtime ran out of available memory.":"Slut på minne.","File count error.":"Räknefel.","File extension error.":"Problem med filändelse.","mb":"mb","Add Files":"Lägg till"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/th_TH.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/tr.js

@@ -0,0 +1,2 @@
+// Turkish (tr)
+plupload.addI18n({"Stop Upload":"Yüklemeyi durdur","Upload URL might be wrong or doesn't exist.":"URL yok ya da hatalı olabilir.","tb":"tb","Size":"Boyut","Close":"Kapat","You must specify either browse_button or drop_element.":"browse_button veya drop_element değişkenlerini belirlemelisiniz.","Init error.":"Başlangıç hatası.","Add files to the upload queue and click the start button.":"Dosyaları kuyruğa ekleyin ve başlatma butonuna tıklayın.","List":"Liste","Filename":"Dosya adı","%s specified, but cannot be found.":"%s tanımlandı fakat bulunamadı.","Image format either wrong or not supported.":"Resim formatı yanlış ya da desteklenmiyor.","Status":"Durum","HTTP Error.":"HTTP hatası.","Start Upload":"Yüklemeyi başlat","Error: File too large:":"Hata: Dosya çok büyük:","kb":"kb","Duplicate file error.":"Yinelenen dosya hatası.","File size error.":"Dosya boyutu hatası.","N/A":"-","gb":"gb","Error: Invalid file extension:":"Hata: Geçersiz dosya uzantısı:","Select files":"Dosyaları seç","%s already present in the queue.":"%s kuyrukta zaten mevcut.","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"Çözünürlük sınırların dışındadır! <b>%s</b> modu en fazla %wx%hpx desteklemektedir.","File: %s":"Dosya: %s","b":"bayt","Uploaded %d/%d files":"%d/%d dosya yüklendi","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"Yükleme elemanı aynı anda %d dosya kabul eder. Ekstra dosyalar işleme konulmaz.","%d files queued":"Kuyrukta %d dosya var.","File: %s, size: %d, max file size: %d":"Dosya: %s, boyut: %d, maksimum dosya boyutu: %d","Thumbnails":"Önizlemeler","Drag files here.":"Dosyaları buraya bırakın.","Runtime ran out of available memory.":"İşlem için yeterli bellek yok.","File count error.":"Dosya sayım hatası.","File extension error.":"Dosya uzantısı hatası.","mb":"mb","Add Files":"Dosya ekle"});

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/uk_UA.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
app/assets/js/plupload-2.3.7/js/i18n/vi.js


+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/zh_CN.js

@@ -0,0 +1,2 @@
+// Chinese (China) (zh_CN)
+plupload.addI18n({"Stop Upload":"停止上传","Upload URL might be wrong or doesn't exist.":"上传的URL可能是错误的或不存在。","tb":"tb","Size":"大小","Close":"关闭","You must specify either browse_button or drop_element.":"您必须指定 browse_button 或者 drop_element。","Init error.":"初始化错误。","Add files to the upload queue and click the start button.":"将文件添加到上传队列,然后点击”开始上传“按钮。","List":"列表","Filename":"文件名","%s specified, but cannot be found.":"%s 已指定,但是没有找到。","Image format either wrong or not supported.":"图片格式错误或者不支持。","Status":"状态","HTTP Error.":"HTTP 错误。","Start Upload":"开始上传","Error: File too large:":"错误: 文件太大:","kb":"kb","Duplicate file error.":"重复文件错误。","File size error.":"文件大小错误。","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"错误:无效的文件扩展名:","Select files":"选择文件","%s already present in the queue.":"%s 已经在当前队列里。","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"超限。<b>%s</b> 支持最大 %wx%hpx 的图片。","File: %s":"文件: %s","b":"b","Uploaded %d/%d files":"已上传 %d/%d 个文件","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"每次只接受同时上传 %d 个文件,多余的文件将会被删除。","%d files queued":"%d 个文件加入到队列","File: %s, size: %d, max file size: %d":"文件: %s, 大小: %d, 最大文件大小: %d","Thumbnails":"缩略图","Drag files here.":"把文件拖到这里。","Runtime ran out of available memory.":"运行时已消耗所有可用内存。","File count error.":"文件数量错误。","File extension error.":"文件扩展名错误。","mb":"mb","Add Files":"增加文件"});

+ 2 - 0
app/assets/js/plupload-2.3.7/js/i18n/zh_TW.js

@@ -0,0 +1,2 @@
+// Chinese (Taiwan) (zh_TW)
+plupload.addI18n({"Stop Upload":"停止上傳","Upload URL might be wrong or doesn't exist.":"檔案URL可能有誤或者不存在。","tb":"tb","Size":"大小","Close":"關閉","You must specify either browse_button or drop_element.":"您必須指定 browse_button 或 drop_element。","Init error.":"初始化錯誤。","Add files to the upload queue and click the start button.":"將檔案加入上傳序列,然後點選”開始上傳“按鈕。","List":"清單","Filename":"檔案名稱","%s specified, but cannot be found.":"找不到已選擇的 %s。","Image format either wrong or not supported.":"圖片格式錯誤或者不支援。","Status":"狀態","HTTP Error.":"HTTP 錯誤。","Start Upload":"開始上傳","Error: File too large:":"錯誤: 檔案大小太大:","kb":"kb","Duplicate file error.":"錯誤:檔案重複。","File size error.":"錯誤:檔案大小超過限制。","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"錯誤:不接受的檔案格式:","Select files":"選擇檔案","%s already present in the queue.":"%s 已經存在目前的檔案序列。","Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.":"圖片解析度超出範圍! <b>%s</b> 最高只支援到 %wx%hpx。","File: %s":"檔案: %s","b":"b","Uploaded %d/%d files":"已上傳 %d/%d 個文件","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"每次只能上傳 %d 個檔案,超過限制數量的檔案將被忽略。","%d files queued":"%d 個檔案加入到序列","File: %s, size: %d, max file size: %d":"檔案: %s, 大小: %d, 檔案大小上限: %d","Thumbnails":"縮圖","Drag files here.":"把檔案拖曳到這裡。","Runtime ran out of available memory.":"執行時耗盡了所有可用的記憶體。","File count error.":"檔案數量錯誤。","File extension error.":"檔案副檔名錯誤。","mb":"mb","Add Files":"增加檔案"});

+ 185 - 0
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/css/jquery.plupload.queue.css

@@ -0,0 +1,185 @@
+/* 
+   Plupload
+------------------------------------------------------------------- */
+
+.plupload_wrapper * {
+	box-sizing: content-box;
+}
+
+.plupload_button {
+	display: -moz-inline-box; /* FF < 3*/
+	display: inline-block;
+	font: normal 12px sans-serif;
+	text-decoration: none;
+    color: #42454a;
+    border: 1px solid #bababa;
+    padding: 2px 8px 3px 20px;
+	margin-right: 4px;
+    background: #f3f3f3 url('../img/buttons.png') no-repeat 0 center;
+	outline: 0;
+
+    /* Optional rounded corners for browsers that support it */
+    -moz-border-radius: 3px;
+    -khtml-border-radius: 3px;
+    -webkit-border-radius: 3px;
+    border-radius: 3px;
+}
+
+.plupload_button:hover {
+	color: #000;
+	text-decoration: none;
+}
+
+.plupload_disabled, a.plupload_disabled:hover {
+    color: #737373;
+    border-color: #c5c5c5;
+    background: #ededed url('../img/buttons-disabled.png') no-repeat 0 center;
+	cursor: default;
+}
+
+.plupload_add {
+	background-position: -181px center;
+}
+
+.plupload_wrapper {
+	font: normal 11px Verdana,sans-serif;
+	width: 100%;
+}
+
+.plupload_container {
+	padding: 8px;
+	background: url('../img/transp50.png');
+	/*-moz-border-radius: 5px;*/
+}
+
+.plupload_container input {
+	border: 1px solid #DDD;
+	font: normal 11px Verdana,sans-serif;
+	width: 98%;
+}
+
+.plupload_header {background: #2A2C2E url('../img/backgrounds.gif') repeat-x;}
+.plupload_header_content {
+	background: url('../img/backgrounds.gif') no-repeat 0 -317px;
+	min-height: 56px;
+	padding-left: 60px;
+	color: #FFF;
+}
+.plupload_header_title {
+	font: normal 18px sans-serif;
+	padding: 6px 0 3px;
+}
+.plupload_header_text {
+	font: normal 12px sans-serif;
+}
+
+.plupload_filelist {
+	margin: 0;
+	padding: 0;
+	list-style: none;
+}
+
+.plupload_scroll .plupload_filelist {
+	height: 185px;
+	background: #F5F5F5;
+	overflow-y: scroll;
+}
+
+.plupload_filelist li {
+	padding: 10px 8px;
+	background: #F5F5F5 url('../img/backgrounds.gif') repeat-x 0 -156px;
+	border-bottom: 1px solid #DDD;
+}
+
+.plupload_filelist_header, .plupload_filelist_footer {
+	background: #DFDFDF;
+	padding: 8px 8px;
+	color: #42454A;
+}
+.plupload_filelist_header {	
+	border-top: 1px solid #EEE;
+	border-bottom: 1px solid #CDCDCD;
+}
+
+.plupload_filelist_footer {border-top: 1px solid #FFF; height: 22px; line-height: 20px; vertical-align: middle;}
+.plupload_file_name {float: left; overflow: hidden}
+.plupload_file_status {color: #777;}
+.plupload_file_status span {color: #42454A;}
+.plupload_file_size, .plupload_file_status, .plupload_progress {
+	float: right;
+	width: 80px;
+}
+.plupload_file_size, .plupload_file_status, .plupload_file_action {text-align: right;}
+
+.plupload_filelist .plupload_file_name {
+	width: 205px;
+	white-space: nowrap;
+	text-overflow: ellipsis;
+}
+
+.plupload_file_action {
+	float: right;
+	width: 16px;
+	height: 16px;
+	margin-left: 15px;
+}
+
+.plupload_file_action * {
+	display: none;
+	width: 16px;
+	height: 16px;
+}
+
+li.plupload_uploading {background: #ECF3DC url('../img/backgrounds.gif') repeat-x 0 -238px;}
+li.plupload_done {color:#AAA}
+
+li.plupload_delete a {
+	background: url('../img/delete.gif');
+}
+
+li.plupload_failed a {
+	background: url('../img/error.gif');
+	cursor: default;
+}
+
+li.plupload_done a {
+	background: url('../img/done.gif');
+	cursor: default;
+}
+
+.plupload_progress, .plupload_upload_status {
+	display: none;
+}
+
+.plupload_progress_container {
+	margin-top: 3px;
+	border: 1px solid #CCC;
+	background: #FFF;
+	padding: 1px;
+}
+.plupload_progress_bar {
+	width: 0px;
+	height: 7px;
+	background: #CDEB8B;
+}
+
+.plupload_scroll .plupload_filelist_header .plupload_file_action, .plupload_scroll .plupload_filelist_footer .plupload_file_action {
+	margin-right: 17px;
+}
+
+/* Floats */
+
+.plupload_clear,.plupload_clearer {clear: both;}
+.plupload_clearer, .plupload_progress_bar {
+	display: block;
+	font-size: 0;
+	line-height: 0;	
+}
+
+li.plupload_droptext {
+	background: transparent;
+	text-align: center;
+	vertical-align: middle;
+	border: 0;
+	line-height: 165px;
+}

BIN
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/backgrounds.gif


BIN
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/buttons-disabled.png


BIN
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/buttons.png


BIN
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/delete.gif


BIN
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/done.gif


BIN
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/error.gif


BIN
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/throbber.gif


BIN
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/img/transp50.png


+ 433 - 0
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/jquery.plupload.queue.js

@@ -0,0 +1,433 @@
+/**
+ * jquery.plupload.queue.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/* global jQuery:true, alert:true */
+
+/**
+jQuery based implementation of the Plupload API - multi-runtime file uploading API.
+
+To use the widget you must include _jQuery_. It is not meant to be extended in any way and is provided to be
+used as it is.
+
+@example
+	<!-- Instantiating: -->
+	<div id="uploader">
+		<p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
+	</div>
+
+	<script>
+		$('#uploader').pluploadQueue({
+			url : '../upload.php',
+			filters : [
+				{title : "Image files", extensions : "jpg,gif,png"}
+			],
+			rename: true,
+			flash_swf_url : '../../js/Moxie.swf',
+			silverlight_xap_url : '../../js/Moxie.xap',
+		});
+	</script>
+
+@example
+	// Retrieving a reference to plupload.Uploader object
+	var uploader = $('#uploader').pluploadQueue();
+
+	uploader.bind('FilesAdded', function() {
+
+		// Autostart
+		setTimeout(uploader.start, 1); // "detach" from the main thread
+	});
+
+@class pluploadQueue
+@constructor
+@param {Object} settings For detailed information about each option check documentation.
+	@param {String} settings.url URL of the server-side upload handler.
+	@param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled.
+	@param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.
+	@param {Array} [settings.filters=[]] Set of file type filters, each one defined by hash of title and extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`
+	@param {String} [settings.flash_swf_url] URL of the Flash swf.
+	@param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.
+	@param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
+	@param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.
+	@param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.
+	@param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.
+	@param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.
+	@param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
+	@param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.
+	@param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}`
+		@param {Number} [settings.resize.width] If image is bigger, it will be resized.
+		@param {Number} [settings.resize.height] If image is bigger, it will be resized.
+		@param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).
+		@param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.
+	@param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.
+	@param {String} [settings.silverlight_xap_url] URL of the Silverlight xap.
+	@param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.
+
+	@param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop.
+	@param {Boolean} [settings.rename=false] Enable ability to rename files in the queue.
+	@param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure.
+*/
+;(function($, plupload) {
+	var uploaders = {};
+
+	function _(str) {
+		return plupload.translate(str) || str;
+	}
+
+	function renderUI(id, target) {
+		// Remove all existing non plupload items
+		target.contents().each(function(i, node) {
+			node = $(node);
+
+			if (!node.is('.plupload')) {
+				node.remove();
+			}
+		});
+
+		target.prepend(
+			'<div class="plupload_wrapper plupload_scroll">' +
+				'<div id="' + id + '_container" class="plupload_container">' +
+					'<div class="plupload">' +
+						'<div class="plupload_header">' +
+							'<div class="plupload_header_content">' +
+								'<div class="plupload_header_title">' + _('Select files') + '</div>' +
+								'<div class="plupload_header_text">' + _('Add files to the upload queue and click the start button.') + '</div>' +
+							'</div>' +
+						'</div>' +
+
+						'<div class="plupload_content">' +
+							'<div class="plupload_filelist_header">' +
+								'<div class="plupload_file_name">' + _('Filename') + '</div>' +
+								'<div class="plupload_file_action">&nbsp;</div>' +
+								'<div class="plupload_file_status"><span>' + _('Status') + '</span></div>' +
+								'<div class="plupload_file_size">' + _('Size') + '</div>' +
+								'<div class="plupload_clearer">&nbsp;</div>' +
+							'</div>' +
+
+							'<ul id="' + id + '_filelist" class="plupload_filelist"></ul>' +
+
+							'<div class="plupload_filelist_footer">' +
+								'<div class="plupload_file_name">' +
+									'<div class="plupload_buttons">' +
+										'<a href="#" class="plupload_button plupload_add" id="' + id + '_browse">' + _('Add Files') + '</a>' +
+										'<a href="#" class="plupload_button plupload_start">' + _('Start Upload') + '</a>' +
+									'</div>' +
+									'<span class="plupload_upload_status"></span>' +
+								'</div>' +
+								'<div class="plupload_file_action"></div>' +
+								'<div class="plupload_file_status"><span class="plupload_total_status">0%</span></div>' +
+								'<div class="plupload_file_size"><span class="plupload_total_file_size">0 b</span></div>' +
+								'<div class="plupload_progress">' +
+									'<div class="plupload_progress_container">' +
+										'<div class="plupload_progress_bar"></div>' +
+									'</div>' +
+								'</div>' +
+								'<div class="plupload_clearer">&nbsp;</div>' +
+							'</div>' +
+						'</div>' +
+					'</div>' +
+				'</div>' +
+				'<input type="hidden" id="' + id + '_count" name="' + id + '_count" value="0" />' +
+			'</div>'
+		);
+	}
+
+	$.fn.pluploadQueue = function(settings) {
+		if (settings) {
+			this.each(function() {
+				var uploader, target, id, contents_bak;
+
+				target = $(this);
+				id = target.attr('id');
+
+				if (!id) {
+					id = plupload.guid();
+					target.attr('id', id);
+				}
+
+				contents_bak = target.html();
+				renderUI(id, target);
+
+				settings = $.extend({
+					dragdrop : true,
+					browse_button : id + '_browse',
+					container : id
+				}, settings);
+
+				// Enable drag/drop (see PostInit handler as well)
+				if (settings.dragdrop) {
+					settings.drop_element = id + '_filelist';
+				}
+
+				uploader = new plupload.Uploader(settings);
+
+				uploaders[id] = uploader;
+
+				function handleStatus(file) {
+					var actionClass;
+
+					if (file.status == plupload.DONE) {
+						actionClass = 'plupload_done';
+					}
+
+					if (file.status == plupload.FAILED) {
+						actionClass = 'plupload_failed';
+					}
+
+					if (file.status == plupload.QUEUED) {
+						actionClass = 'plupload_delete';
+					}
+
+					if (file.status == plupload.UPLOADING) {
+						actionClass = 'plupload_uploading';
+					}
+
+					var icon = $('#' + file.id).attr('class', actionClass).find('a').css('display', 'block');
+					if (file.hint) {
+						icon.attr('title', file.hint);
+					}
+				}
+
+				function updateTotalProgress() {
+					$('span.plupload_total_status', target).html(uploader.total.percent + '%');
+					$('div.plupload_progress_bar', target).css('width', uploader.total.percent + '%');
+					$('span.plupload_upload_status', target).html(
+						plupload.sprintf(_('Uploaded %d/%d files'), uploader.total.uploaded, uploader.files.length)
+					);
+				}
+
+				function updateList() {
+					var fileList = $('ul.plupload_filelist', target).html(''), inputCount = 0, inputHTML;
+
+					$.each(uploader.files, function(i, file) {
+						inputHTML = '';
+
+						if (file.status == plupload.DONE) {
+							if (file.target_name) {
+								inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_tmpname" value="' + plupload.xmlEncode(file.target_name) + '" />';
+							}
+
+							inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_name" value="' + plupload.xmlEncode(file.name) + '" />';
+							inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_status" value="' + (file.status == plupload.DONE ? 'done' : 'failed') + '" />';
+
+							inputCount++;
+
+							$('#' + id + '_count').val(inputCount);
+						}
+
+						fileList.append(
+							'<li id="' + file.id + '">' +
+								'<div class="plupload_file_name"><span>' + file.name + '</span></div>' +
+								'<div class="plupload_file_action"><a href="#"></a></div>' +
+								'<div class="plupload_file_status">' + file.percent + '%</div>' +
+								'<div class="plupload_file_size">' + plupload.formatSize(file.size) + '</div>' +
+								'<div class="plupload_clearer">&nbsp;</div>' +
+								inputHTML +
+							'</li>'
+						);
+
+						handleStatus(file);
+
+						$('#' + file.id + '.plupload_delete a').click(function(e) {
+							$('#' + file.id).remove();
+							uploader.removeFile(file);
+
+							e.preventDefault();
+						});
+					});
+
+					$('span.plupload_total_file_size', target).html(plupload.formatSize(uploader.total.size));
+
+					if (uploader.total.queued === 0) {
+						$('span.plupload_add_text', target).html(_('Add Files'));
+					} else {
+						$('span.plupload_add_text', target).html(plupload.sprintf(_('%d files queued'), uploader.total.queued));
+					}
+
+					$('a.plupload_start', target).toggleClass('plupload_disabled', uploader.files.length == (uploader.total.uploaded + uploader.total.failed));
+
+					// Scroll to end of file list
+					fileList[0].scrollTop = fileList[0].scrollHeight;
+
+					updateTotalProgress();
+
+					// Re-add drag message if there is no files
+					if (!uploader.files.length && uploader.features.dragdrop && uploader.settings.dragdrop) {
+						$('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');
+					}
+				}
+
+				function destroy() {
+					delete uploaders[id];
+					uploader.destroy();
+					target.html(contents_bak);
+					uploader = target = contents_bak = null;
+				}
+
+				uploader.bind("UploadFile", function(up, file) {
+					$('#' + file.id).addClass('plupload_current_file');
+				});
+
+				uploader.bind('Init', function(up, res) {
+					// Enable rename support
+					if (!settings.unique_names && settings.rename) {
+						target.on('click', '#' + id + '_filelist div.plupload_file_name span', function(e) {
+							var targetSpan = $(e.target), file, parts, name, ext = "";
+							var fileContainer = targetSpan.closest('li');
+
+							if (!fileContainer.hasClass('plupload_delete')) {
+								return;
+							}
+
+							// Get file name and split out name and extension
+							file = up.getFile(targetSpan.parents('li')[0].id);
+							name = file.name;
+							parts = /^(.+)(\.[^.]+)$/.exec(name);
+							if (parts) {
+								name = parts[1];
+								ext = parts[2];
+							}
+
+							// Display input element
+							targetSpan.hide().after('<input type="text" />');
+							targetSpan.next().val(name).focus().blur(function() {
+								targetSpan.show().next().remove();
+							}).keydown(function(e) {
+								var targetInput = $(this);
+
+								if (e.keyCode == 13) {
+									e.preventDefault();
+
+									// Rename file and glue extension back on
+									file.name = targetInput.val() + ext;
+									targetSpan.html(file.name);
+									targetInput.blur();
+								}
+							});
+						});
+					}
+
+					$('#' + id + '_container').attr('title', 'Using runtime: ' + res.runtime);
+
+					$('a.plupload_start', target).click(function(e) {
+						if (!$(this).hasClass('plupload_disabled')) {
+							uploader.start();
+						}
+
+						e.preventDefault();
+					});
+
+					$('a.plupload_stop', target).click(function(e) {
+						e.preventDefault();
+						uploader.stop();
+					});
+
+					$('a.plupload_start', target).addClass('plupload_disabled');
+				});
+
+				uploader.bind("Error", function(up, err) {
+					var file = err.file, message;
+
+					if (file) {
+						message = err.message;
+
+						if (err.details) {
+							message += " (" + err.details + ")";
+						}
+
+						if (err.code == plupload.FILE_SIZE_ERROR) {
+							alert(_("Error: File too large:") + " " + file.name);
+						}
+
+						if (err.code == plupload.FILE_EXTENSION_ERROR) {
+							alert(_("Error: Invalid file extension:") + " " + file.name);
+						}
+
+						file.hint = message;
+						$('#' + file.id).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message);
+					}
+
+					if (err.code === plupload.INIT_ERROR) {
+						setTimeout(function() {
+							destroy();
+						}, 1);
+					}
+				});
+
+				uploader.bind("PostInit", function(up) {
+					// features are populated only after input components are fully instantiated
+					if (up.settings.dragdrop && up.features.dragdrop) {
+						$('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');
+					}
+				});
+
+				uploader.init();
+
+				uploader.bind('StateChanged', function() {
+					if (uploader.state === plupload.STARTED) {
+						$('li.plupload_delete a,div.plupload_buttons', target).hide();
+						uploader.disableBrowse(true);
+
+						$('span.plupload_upload_status,div.plupload_progress,a.plupload_stop', target).css('display', 'block');
+						$('span.plupload_upload_status', target).html('Uploaded ' + uploader.total.uploaded + '/' + uploader.files.length + ' files');
+
+						if (settings.multiple_queues) {
+							$('span.plupload_total_status,span.plupload_total_file_size', target).show();
+						}
+					} else {
+						updateList();
+						$('a.plupload_stop,div.plupload_progress', target).hide();
+						$('a.plupload_delete', target).css('display', 'block');
+
+						if (settings.multiple_queues && uploader.total.uploaded + uploader.total.failed == uploader.files.length) {
+							$(".plupload_buttons,.plupload_upload_status", target).css("display", "inline");
+							uploader.disableBrowse(false);
+
+							$(".plupload_start", target).addClass("plupload_disabled");
+							$('span.plupload_total_status,span.plupload_total_file_size', target).hide();
+						}
+					}
+				});
+
+				uploader.bind('FilesAdded', updateList);
+
+				uploader.bind('FilesRemoved', function() {
+					// since the whole file list is redrawn for every change in the queue
+					// we need to scroll back to the file removal point to avoid annoying
+					// scrolling to the bottom bug (see #926)
+					var scrollTop = $('#' + id + '_filelist').scrollTop();
+					updateList();
+					$('#' + id + '_filelist').scrollTop(scrollTop);
+				});
+
+				uploader.bind('FileUploaded', function(up, file) {
+					handleStatus(file);
+				});
+
+				uploader.bind("UploadProgress", function(up, file) {
+					// Set file specific progress
+					$('#' + file.id + ' div.plupload_file_status', target).html(file.percent + '%');
+
+					handleStatus(file);
+					updateTotalProgress();
+				});
+
+				// Call setup function
+				if (settings.setup) {
+					settings.setup(uploader);
+				}
+			});
+
+			return this;
+		} else {
+			// Get uploader instance for specified element
+			return uploaders[$(this[0]).attr('id')];
+		}
+	};
+})(jQuery, plupload);

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
app/assets/js/plupload-2.3.7/js/jquery.plupload.queue/jquery.plupload.queue.min.js


+ 379 - 0
app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/css/jquery.ui.plupload.css

@@ -0,0 +1,379 @@
+/*
+   Plupload
+------------------------------------------------------------------- */
+
+.plupload_wrapper * {
+	box-sizing: content-box;
+}
+
+.plupload_button {
+	cursor: pointer;
+	outline: none;
+}
+
+.plupload_wrapper {
+	font: normal 11px Verdana,sans-serif;
+	width: 100%;
+	min-width: 520px;
+	line-height: 12px;
+}
+
+.plupload_container {
+	_height: 300px;
+	min-height: 300px;
+	position: relative;
+}
+
+.plupload_filelist_footer {border-width: 1px 0 0 0}
+.plupload_file {border-width: 0 0 1px 0}
+.plupload_container .plupload_header {border-width: 0 0 1px 0; position: relative;}
+
+.plupload_delete .ui-icon,
+.plupload_done .ui-icon,
+.plupload_failed .ui-icon {
+	cursor:pointer;
+}
+
+.plupload_header_content {
+	height: 56px;
+	padding: 0 160px 0 60px;
+	position: relative;
+}
+
+.plupload_logo {
+	width: 40px;
+	height: 40px;
+	background: url('../img/plupload.png') no-repeat 0 0;
+	position: absolute;
+	top: 8px;
+	left: 8px;
+}
+
+.plupload_header_content_bw .plupload_logo {
+	background-position: -40px 0;
+}
+
+.plupload_header_title {
+	font: normal 18px sans-serif;
+	line-height: 19px;
+	padding: 6px 0 3px;
+}
+
+.plupload_header_text {
+	font: normal 12px sans-serif;
+}
+
+.plupload_view_switch {
+	position: absolute;
+	right: 16px;
+	bottom: 8px;
+	margin: 0;
+	display: none;
+}
+
+.plupload_view_switch .ui-button {
+	margin-right: -0.31em;
+}
+
+.plupload_content {
+	position: absolute;
+	top: 86px;
+	bottom: 44px;
+	left: 0;
+	right: 0;
+	overflow-y: auto;
+	width: 100%;
+}
+
+.plupload_filelist {
+	border-collapse: collapse;
+	border-left: none;
+	border-right: none;
+	margin: 0;
+	padding: 0;
+	width: 100%;
+	-moz-user-select: none;
+	-webkit-user-select: none;
+	user-select: none;
+}
+
+.plupload_filelist_content {
+	padding: 0;
+	margin: 0;
+}
+
+.plupload_cell {padding: 8px 6px;}
+
+.plupload_file {
+	list-style: none;
+	display: block;
+	position: relative;
+	overflow: hidden;
+	line-height: 12px;
+}
+
+.plupload_file_thumb {
+	position: relative;
+	background-image: none;
+	background-color: #eee;
+}
+
+.plupload_thumb_loading {
+	background: #eee url(../img/loading.gif) center no-repeat;
+}
+
+.plupload_thumb_loading .plupload_file_dummy,
+.plupload_thumb_embedded .plupload_file_dummy {
+	display: none;
+}
+
+.plupload_file_name {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
+
+.plupload_filelist_header {
+	border-top: none;
+}
+
+.plupload_filelist_footer {
+	position: absolute;
+	bottom: 0;
+	left: 0;
+	right: 0;
+}
+
+.plupload_buttons {
+	position: relative;
+}
+
+/* list view */
+.plupload_view_list .plupload_file {
+	border-left: none;
+	border-right: none;
+	border-top: none;
+	height: 29px;
+	width: 100% !important;
+	/* fix IE6 vertical white-space bug */
+	_float: left;
+	_clear: left;
+}
+
+.plupload_view_list div.plupload_file_size,
+.plupload_view_list div.plupload_file_status,
+.plupload_view_list div.plupload_file_action {
+	padding: 8px 6px;
+	position: absolute;
+	top: 0;
+	right: 0;
+}
+
+.plupload_view_list div.plupload_file_name {
+	margin-right: 156px;
+	padding: 8px 6px;
+	_width: 75%;
+}
+
+.plupload_view_list div.plupload_file_size {
+	right: 28px;
+}
+
+.plupload_view_list div.plupload_file_status {
+	right: 82px;
+}
+
+.plupload_view_list .plupload_file_rename {
+	margin-left: -2px;
+}
+
+.plupload_view_list .plupload_file_size,
+.plupload_view_list .plupload_file_status,
+.plupload_filelist_footer .plupload_file_size,
+.plupload_filelist_footer .plupload_file_status {
+	text-align: right;
+	width: 52px;
+}
+
+.plupload_view_list .plupload_file_thumb {
+	position: absolute;
+	top: -999px;
+}
+
+.plupload_view_list .plupload_file_progress {
+	display: none;
+}
+
+
+/* thumbs view */
+.plupload_view_thumbs .plupload_content {
+	top: 57px;
+}
+
+.plupload_view_thumbs .plupload_filelist_header {
+	display: none;
+}
+
+.plupload_view_thumbs .plupload_file {
+	padding: 6px;
+	margin: 10px;
+	border: 1px solid #fff;
+	float: left;
+}
+
+.plupload_view_thumbs .plupload_file_thumb,
+.plupload_view_thumbs .plupload_file_dummy {
+	text-align: center;
+	overflow: hidden;
+}
+
+.plupload_view_thumbs .plupload_file_dummy {
+	font-size: 21px;
+	font-weight: bold;
+	text-transform: lowercase;
+	overflow: hidden;
+	border: none;
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+}
+
+.plupload_view_thumbs div.plupload_file_action {
+	position: absolute;
+	top: 0;
+	right: 0;
+}
+
+.plupload_view_thumbs div.plupload_file_name {
+	padding: 0;
+	font-weight: bold;
+}
+
+.plupload_view_thumbs .plupload_file_rename {
+	padding: 1px 0;
+	width: 100% !important;
+}
+
+.plupload_view_thumbs div.plupload_file_size {
+	font-size: 0.8em;
+	font-weight: normal;
+}
+
+.plupload_view_thumbs div.plupload_file_status {
+	position: relative;
+	height: 3px;
+	overflow: hidden;
+	text-indent: -999px;
+	margin-bottom: 3px;
+}
+
+.plupload_view_thumbs div.plupload_file_progress {
+	border: none;
+	height: 100%;
+}
+
+.plupload .ui-sortable-helper,
+.plupload .ui-sortable .plupload_file {
+	cursor:move;
+}
+
+.plupload_file_action {width: 16px;}
+.plupload_file_name {
+	overflow: hidden;
+	padding-left: 10px;
+}
+
+.plupload_file_rename {
+	border: none;
+	font: normal 11px Verdana, sans-serif;
+	padding: 1px 2px;
+	line-height: 11px;
+	height: 11px;
+}
+
+.plupload_progress {width: 60px;}
+.plupload_progress_container {padding: 1px;}
+
+
+/* Floats */
+
+.plupload_right {float: right;}
+.plupload_left {float: left;}
+.plupload_clear,.plupload_clearer {clear: both;}
+.plupload_clearer, .plupload_progress_bar {
+	display: block;
+	font-size: 0;
+	line-height: 0;
+}
+.plupload_clearer {height: 0;}
+
+/* Misc */
+.plupload_hidden {display: none !important;}
+
+.plupload_droptext {
+	position: absolute;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	background: transparent;
+	text-align: center;
+	vertical-align: middle;
+	border: 0;
+	line-height: 160px;
+	display: none;
+}
+
+.plupload_dropbox .plupload_droptext {
+	display: block;
+}
+
+.plupload_files_queued .plupload_droptext {
+	display: none;
+}
+
+.plupload_buttons, .plupload_upload_status {float: left}
+
+.plupload_message {
+	position: absolute;
+	top: -1px;
+	left: -1px;
+	height: 100%;
+	width: 100%;
+}
+
+.plupload_message p {
+	padding:0.7em;
+	margin:0;
+}
+
+.plupload_message strong {
+	font-weight: bold;
+}
+
+.plupload_message i {
+	font-style: italic;
+}
+
+.plupload_message p span.ui-icon {
+	float: left;
+	margin-right: 0.3em;
+}
+
+.plupload_header_content .ui-state-error,
+.plupload_header_content .ui-state-highlight {
+	border:none;
+}
+
+.plupload_message_close {
+	position:absolute;
+	top:5px;
+	right:5px;
+	cursor:pointer;
+}
+
+.plupload .ui-sortable-placeholder {
+	height:35px;
+}

BIN
app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/img/loading.gif


BIN
app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/img/plupload.png


+ 1358 - 0
app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/jquery.ui.plupload.js

@@ -0,0 +1,1358 @@
+/**
+ * jquery.ui.plupload.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ *
+ * Depends:
+ *	jquery.ui.core.js
+ *	jquery.ui.widget.js
+ *	jquery.ui.button.js
+ *	jquery.ui.progressbar.js
+ *
+ * Optionally:
+ *	jquery.ui.sortable.js
+ */
+
+ /* global jQuery:true */
+
+/**
+jQuery UI based implementation of the Plupload API - multi-runtime file uploading API.
+
+To use the widget you must include _jQuery_ and _jQuery UI_ bundle (including `ui.core`, `ui.widget`, `ui.button`,
+`ui.progressbar` and `ui.sortable`).
+
+In general the widget is designed the way that you do not usually need to do anything to it after you instantiate it.
+But! You still can intervenue, to some extent, in case you need to. Although, due to the fact that widget is based on
+_jQuery UI_ widget factory, there are some specifics. See examples below for more details.
+
+@example
+	<!-- Instantiating: -->
+	<div id="uploader">
+		<p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
+	</div>
+
+	<script>
+		$('#uploader').plupload({
+			url : '../upload.php',
+			filters : [
+				{title : "Image files", extensions : "jpg,gif,png"}
+			],
+			rename: true,
+			sortable: true,
+			flash_swf_url : '../../js/Moxie.swf',
+			silverlight_xap_url : '../../js/Moxie.xap',
+		});
+	</script>
+
+@example
+	// Invoking methods:
+	$('#uploader').plupload(options);
+
+	// Display welcome message in the notification area
+	$('#uploader').plupload('notify', 'info', "This might be obvious, but you need to click 'Add Files' to add some files.");
+
+@example
+	// Subscribing to the events...
+	// ... on initialization:
+	$('#uploader').plupload({
+		...
+		viewchanged: function(event, args) {
+			// stuff ...
+		}
+	});
+	// ... or after initialization
+	$('#uploader').on("viewchanged", function(event, args) {
+		// stuff ...
+	});
+
+@class UI.Plupload
+@constructor
+@param {Object} settings For detailed information about each option check documentation.
+	@param {String} settings.url URL of the server-side upload handler.
+	@param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled.
+	@param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.
+	@param {Object} [settings.filters={}] Set of file type filters.
+		@param {Array} [settings.filters.mime_types=[]] List of file types to accept, each one defined by title and list of extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`
+		@param {String|Number} [settings.filters.max_file_size=0] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
+		@param {Boolean} [settings.filters.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
+		@param {Number} [settings.filters.max_file_count=0] Limit the number of files that can reside in the queue at the same time (default is 0 - no limit).
+	@param {String} [settings.flash_swf_url] URL of the Flash swf.
+	@param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.
+	@param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
+	@param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.
+	@param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.
+	@param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.
+	@param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.
+	@param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
+	@param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.
+	@param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}`
+		@param {Number} [settings.resize.width] If image is bigger, it will be resized.
+		@param {Number} [settings.resize.height] If image is bigger, it will be resized.
+		@param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).
+		@param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.
+	@param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.
+	@param {String} [settings.silverlight_xap_url] URL of the Silverlight xap.
+	@param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.
+
+	@param {Boolean} [settings.autostart=false] Whether to auto start uploading right after file selection.
+	@param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop.
+	@param {Boolean} [settings.rename=false] Enable ability to rename files in the queue.
+	@param {Boolean} [settings.sortable=false] Enable ability to sort files in the queue, changing their uploading priority.
+	@param {Object} [settings.buttons] Control the visibility of functional buttons.
+		@param {Boolean} [settings.buttons.browse=true] Display browse button.
+		@param {Boolean} [settings.buttons.start=true] Display start button.
+		@param {Boolean} [settings.buttons.stop=true] Display stop button.
+	@param {Object} [settings.views] Control various views of the file queue.
+		@param {Boolean} [settings.views.list=true] Enable list view.
+		@param {Boolean} [settings.views.thumbs=false] Enable thumbs view.
+		@param {String} [settings.views.default='list'] Default view.
+		@param {Boolean} [settings.views.remember=true] Whether to remember the current view (requires jQuery Cookie plugin).
+	@param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure.
+*/
+;(function(window, document, plupload, o, $) {
+
+/**
+Dispatched when the widget is initialized and ready.
+
+@event ready
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+*/
+
+/**
+Dispatched when file dialog is closed.
+
+@event selected
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+@param {Array} files Array of selected files represented by plupload.File objects
+*/
+
+/**
+Dispatched when file dialog is closed.
+
+@event removed
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+@param {Array} files Array of removed files represented by plupload.File objects
+*/
+
+/**
+Dispatched when upload is started.
+
+@event started
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+*/
+
+/**
+Dispatched when upload is stopped.
+
+@event stopped
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+*/
+
+/**
+Dispatched during the upload process.
+
+@event progress
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+@param {plupload.File} file File that is being uploaded (includes loaded and percent properties among others).
+	@param {Number} size Total file size in bytes.
+	@param {Number} loaded Number of bytes uploaded of the files total size.
+	@param {Number} percent Number of percentage uploaded of the file.
+*/
+
+/**
+Dispatched when file is uploaded.
+
+@event uploaded
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+@param {plupload.File} file File that was uploaded.
+	@param {Enum} status Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
+*/
+
+/**
+Dispatched when upload of the whole queue is complete.
+
+@event complete
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+@param {Array} files Array of uploaded files represented by plupload.File objects
+*/
+
+/**
+Dispatched when the view is changed, e.g. from `list` to `thumbs` or vice versa.
+
+@event viewchanged
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+@param {String} type Current view type.
+*/
+
+/**
+Dispatched when error of some kind is detected.
+
+@event error
+@param {plupload.Uploader} uploader Uploader instance sending the event.
+@param {String} error Error message.
+@param {plupload.File} file File that was uploaded.
+	@param {Enum} status Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
+*/
+
+var uploaders = {};
+
+function _(str) {
+	return plupload.translate(str) || str;
+}
+
+function renderUI(obj) {
+	obj.id = obj.attr('id');
+
+	obj.html(
+		'<div class="plupload_wrapper">' +
+			'<div class="ui-widget-content plupload_container">' +
+				'<div class="ui-state-default ui-widget-header plupload_header">' +
+					'<div class="plupload_header_content">' +
+						'<div class="plupload_logo"> </div>' +
+						'<div class="plupload_header_title">' + _("Select files") + '</div>' +
+						'<div class="plupload_header_text">' + _("Add files to the upload queue and click the start button.") + '</div>' +
+						'<div class="plupload_view_switch">' +
+							'<input type="radio" id="'+obj.id+'_view_list" name="view_mode_'+obj.id+'" checked="checked" /><label class="plupload_button" for="'+obj.id+'_view_list" data-view="list">' + _('List') + '</label>' +
+							'<input type="radio" id="'+obj.id+'_view_thumbs" name="view_mode_'+obj.id+'" /><label class="plupload_button"  for="'+obj.id+'_view_thumbs" data-view="thumbs">' + _('Thumbnails') + '</label>' +
+						'</div>' +
+					'</div>' +
+				'</div>' +
+
+				'<table class="plupload_filelist plupload_filelist_header ui-widget-header">' +
+				'<tr>' +
+					'<td class="plupload_cell plupload_file_name">' + _('Filename') + '</td>' +
+					'<td class="plupload_cell plupload_file_status">' + _('Status') + '</td>' +
+					'<td class="plupload_cell plupload_file_size">' + _('Size') + '</td>' +
+					'<td class="plupload_cell plupload_file_action">&nbsp;</td>' +
+				'</tr>' +
+				'</table>' +
+
+				'<div class="plupload_content">' +
+					'<div class="plupload_droptext">' + _("Drag files here.") + '</div>' +
+					'<ul class="plupload_filelist_content"> </ul>' +
+					'<div class="plupload_clearer">&nbsp;</div>' +
+				'</div>' +
+
+				'<table class="plupload_filelist plupload_filelist_footer ui-widget-header">' +
+				'<tr>' +
+					'<td class="plupload_cell plupload_file_name">' +
+						'<div class="plupload_buttons"><!-- Visible -->' +
+							'<a class="plupload_button plupload_add">' + _("Add Files") + '</a>&nbsp;' +
+							'<a class="plupload_button plupload_start">' + _("Start Upload") + '</a>&nbsp;' +
+							'<a class="plupload_button plupload_stop plupload_hidden">'+_("Stop Upload") + '</a>&nbsp;' +
+						'</div>' +
+
+						'<div class="plupload_started plupload_hidden"><!-- Hidden -->' +
+							'<div class="plupload_progress plupload_right">' +
+								'<div class="plupload_progress_container"></div>' +
+							'</div>' +
+
+							'<div class="plupload_cell plupload_upload_status"></div>' +
+
+							'<div class="plupload_clearer">&nbsp;</div>' +
+						'</div>' +
+					'</td>' +
+					'<td class="plupload_file_status"><span class="plupload_total_status">0%</span></td>' +
+					'<td class="plupload_file_size"><span class="plupload_total_file_size">0 kb</span></td>' +
+					'<td class="plupload_file_action"></td>' +
+				'</tr>' +
+				'</table>' +
+
+			'</div>' +
+			'<input class="plupload_count" value="0" type="hidden">' +
+		'</div>'
+	);
+}
+
+
+$.widget("ui.plupload", {
+
+	widgetEventPrefix: '',
+
+	contents_bak: '',
+
+	options: {
+		browse_button_hover: 'ui-state-hover',
+		browse_button_active: 'ui-state-active',
+
+		filters: {},
+
+		// widget specific
+		buttons: {
+			browse: true,
+			start: true,
+			stop: true
+		},
+
+		views: {
+			list: true,
+			thumbs: false,
+			active: 'list',
+			remember: true // requires: https://github.com/carhartl/jquery-cookie, otherwise disabled even if set to true
+		},
+
+		thumb_width: 100,
+		thumb_height: 60,
+
+		multiple_queues: true, // re-use widget by default
+		dragdrop : true,
+		autostart: false,
+		sortable: false,
+		rename: false
+	},
+
+	FILE_COUNT_ERROR: -9001,
+
+	_create: function() {
+		var id = this.element.attr('id');
+		if (!id) {
+			id = plupload.guid();
+			this.element.attr('id', id);
+		}
+		this.id = id;
+
+		// backup the elements initial state
+		this.contents_bak = this.element.html();
+		renderUI(this.element);
+
+		// container, just in case
+		this.container = $('.plupload_container', this.element).attr('id', id + '_container');
+
+		this.content = $('.plupload_content', this.element);
+
+		if ($.fn.resizable) {
+			this.container.resizable({
+				handles: 's',
+				minHeight: 300
+			});
+		}
+
+		// list of files, may become sortable
+		this.filelist = $('.plupload_filelist_content', this.container)
+			.attr({
+				id: id + '_filelist',
+				unselectable: 'on'
+			});
+
+
+		// buttons
+		this.browse_button = $('.plupload_add', this.container).attr('id', id + '_browse');
+		this.start_button = $('.plupload_start', this.container).attr('id', id + '_start');
+		this.stop_button = $('.plupload_stop', this.container).attr('id', id + '_stop');
+		this.thumbs_switcher = $('#' + id + '_view_thumbs');
+		this.list_switcher = $('#' + id + '_view_list');
+
+		if ($.ui.button) {
+			this.browse_button.button({
+				icons: { primary: 'ui-icon-circle-plus' },
+				disabled: true
+			});
+
+			this.start_button.button({
+				icons: { primary: 'ui-icon-circle-arrow-e' },
+				disabled: true
+			});
+
+			this.stop_button.button({
+				icons: { primary: 'ui-icon-circle-close' }
+			});
+
+			this.list_switcher.button({
+				text: false,
+				icons: { secondary: "ui-icon-grip-dotted-horizontal" }
+			});
+
+			this.thumbs_switcher.button({
+				text: false,
+				icons: { secondary: "ui-icon-image" }
+			});
+		}
+
+		// progressbar
+		this.progressbar = $('.plupload_progress_container', this.container);
+
+		if ($.ui.progressbar) {
+			this.progressbar.progressbar();
+		}
+
+		// counter
+		this.counter = $('.plupload_count', this.element)
+			.attr({
+				id: id + '_count',
+				name: id + '_count'
+			});
+
+		// initialize uploader instance
+		this._initUploader();
+	},
+
+	_initUploader: function() {
+		var self = this
+		, id = this.id
+		, uploader
+		, options = {
+			container: id + '_buttons',
+			browse_button: id + '_browse'
+		}
+		;
+
+		$('.plupload_buttons', this.element).attr('id', id + '_buttons');
+
+		if (self.options.dragdrop) {
+			this.filelist.parent().attr('id', this.id + '_dropbox');
+			options.drop_element = this.id + '_dropbox';
+		}
+
+		this.filelist.on('click', function(e) {
+			var me = $(e.target), fileContainer;
+			if (me.hasClass('plupload_action_icon')) {
+				fileContainer = me.closest('.plupload_file');
+				if (fileContainer.hasClass('plupload_delete')) {
+					self.removeFile(fileContainer.attr('id'));
+					e.preventDefault();
+				}
+			}
+		});
+
+		uploader = this.uploader = uploaders[id] = new plupload.Uploader($.extend(this.options, options));
+
+		// retrieve full normalized set of options
+		this.options = uploader.getOption();
+
+		if (self.options.views.thumbs) {
+			uploader.settings.required_features.display_media = true;
+		}
+
+		// for backward compatibility
+		if (self.options.max_file_count) {
+			plupload.extend(uploader.getOption('filters'), {
+				max_file_count: self.options.max_file_count
+			});
+		}
+
+		plupload.addFileFilter('max_file_count', function(maxCount, file, cb) {
+			if (maxCount <= this.files.length - (this.total.uploaded + this.total.failed)) {
+				self.browse_button.button('disable');
+				this.disableBrowse();
+
+				this.trigger('Error', {
+					code : self.FILE_COUNT_ERROR,
+					message : _("File count error."),
+					file : file
+				});
+				cb(false);
+			} else {
+				cb(true);
+			}
+		});
+
+
+		uploader.bind('Error', function(up, err) {
+			var message, details = "";
+
+			message = '<strong>' + err.message + '</strong>';
+
+			switch (err.code) {
+				case plupload.FILE_EXTENSION_ERROR:
+					details = plupload.sprintf(_("File: %s"), err.file.name);
+					break;
+
+				case plupload.FILE_SIZE_ERROR:
+					details = plupload.sprintf(_("File: %s, size: %d, max file size: %d"), err.file.name,  plupload.formatSize(err.file.size), plupload.formatSize(plupload.parseSize(up.getOption('filters').max_file_size)));
+					break;
+
+				case plupload.FILE_DUPLICATE_ERROR:
+					details = plupload.sprintf(_("%s already present in the queue."), err.file.name);
+					break;
+
+				case self.FILE_COUNT_ERROR:
+					details = plupload.sprintf(_("Upload element accepts only %d file(s) at a time. Extra files were stripped."), up.getOption('filters').max_file_count || 0);
+					break;
+
+				case plupload.IMAGE_FORMAT_ERROR :
+					details = _("Image format either wrong or not supported.");
+					break;
+
+				case plupload.IMAGE_MEMORY_ERROR :
+					details = _("Runtime ran out of available memory.");
+					break;
+
+				/* // This needs a review
+				case plupload.IMAGE_DIMENSIONS_ERROR :
+					details = plupload.sprintf(_('Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.'), up.runtime, up.features.maxWidth, up.features.maxHeight);
+					break;	*/
+
+				case plupload.HTTP_ERROR:
+					details = _("Upload URL might be wrong or doesn't exist.");
+					break;
+			}
+
+			message += " <br /><i>" + details + "</i>";
+
+			self._trigger('error', null, { up: up, error: err } );
+
+			// do not show UI if no runtime can be initialized
+			if (err.code === plupload.INIT_ERROR) {
+				setTimeout(function() {
+					self.destroy();
+				}, 1);
+			} else {
+				self.notify('error', message);
+			}
+		});
+
+
+		uploader.bind('PostInit', function(up) {
+			// all buttons are optional, so they can be disabled and hidden
+			if (!self.options.buttons.browse) {
+				self.browse_button.button('disable').hide();
+				up.disableBrowse(true);
+			} else {
+				self.browse_button.button('enable');
+			}
+
+			if (!self.options.buttons.start) {
+				self.start_button.button('disable').hide();
+			}
+
+			if (!self.options.buttons.stop) {
+				self.stop_button.button('disable').hide();
+			}
+
+			if (!self.options.unique_names && self.options.rename) {
+				self._enableRenaming();
+			}
+
+			if (self.options.dragdrop && up.features.dragdrop) {
+				self.filelist.parent().addClass('plupload_dropbox');
+			}
+
+			self._enableViewSwitcher();
+
+			self.start_button.click(function(e) {
+				if (!$(this).button('option', 'disabled')) {
+					self.start();
+				}
+				e.preventDefault();
+			});
+
+			self.stop_button.click(function(e) {
+				self.stop();
+				e.preventDefault();
+			});
+
+			self._trigger('ready', null, { up: up });
+		});
+
+		// uploader internal events must run first
+		uploader.init();
+
+		uploader.bind('FileFiltered', function(up, file) {
+			self._addFiles(file);
+		});
+
+		uploader.bind('FilesAdded', function(up, files) {
+			self._trigger('selected', null, { up: up, files: files } );
+
+			// re-enable sortable
+			if (self.options.sortable && $.ui.sortable) {
+				self._enableSortingList();
+			}
+
+			self._trigger('updatelist', null, { filelist: self.filelist });
+
+			if (self.options.autostart) {
+				// set a little delay to make sure that QueueChanged triggered by the core has time to complete
+				setTimeout(function() {
+					self.start();
+				}, 10);
+			}
+		});
+
+		uploader.bind('FilesRemoved', function(up, files) {
+			// destroy sortable if enabled
+			if ($.ui.sortable && self.options.sortable) {
+				$('tbody', self.filelist).sortable('destroy');
+			}
+
+			$.each(files, function(i, file) {
+				$('#' + file.id).toggle("highlight", function() {
+					$(this).remove();
+				});
+			});
+
+			if (up.files.length) {
+				// re-initialize sortable
+				if (self.options.sortable && $.ui.sortable) {
+					self._enableSortingList();
+				}
+			}
+
+			self._trigger('updatelist', null, { filelist: self.filelist });
+			self._trigger('removed', null, { up: up, files: files } );
+		});
+
+		uploader.bind('QueueChanged', function() {
+			self._handleState();
+		});
+
+		uploader.bind('StateChanged', function(up) {
+			self._handleState();
+			if (plupload.STARTED === up.state) {
+				self._trigger('started', null, { up: this.uploader });
+			} else if (plupload.STOPPED === up.state) {
+				self._trigger('stopped', null, { up: this.uploader });
+			}
+		});
+
+		uploader.bind('UploadFile', function(up, file) {
+			self._handleFileStatus(file);
+		});
+
+		uploader.bind('FileUploaded', function(up, file, result) {
+			self._handleFileStatus(file);
+			self._trigger('uploaded', null, { up: up, file: file, result: result } );
+		});
+
+		uploader.bind('UploadProgress', function(up, file) {
+			self._handleFileStatus(file);
+			self._updateTotalProgress();
+			self._trigger('progress', null, { up: up, file: file } );
+		});
+
+		uploader.bind('UploadComplete', function(up, files) {
+			self._addFormFields();
+			self._trigger('complete', null, { up: up, files: files } );
+		});
+	},
+
+
+	_setOption: function(key, value) {
+		var self = this;
+
+		if (key == 'buttons' && typeof(value) == 'object') {
+			value = $.extend(self.options.buttons, value);
+
+			if (!value.browse) {
+				self.browse_button.button('disable').hide();
+				self.uploader.disableBrowse(true);
+			} else {
+				self.browse_button.button('enable').show();
+				self.uploader.disableBrowse(false);
+			}
+
+			if (!value.start) {
+				self.start_button.button('disable').hide();
+			} else {
+				self.start_button.button('enable').show();
+			}
+
+			if (!value.stop) {
+				self.stop_button.button('disable').hide();
+			} else {
+				self.start_button.button('enable').show();
+			}
+		}
+
+		self.uploader.setOption(key, value);
+	},
+
+
+	/**
+	Start upload. Triggers `start` event.
+
+	@method start
+	*/
+	start: function() {
+		this.uploader.start();
+	},
+
+
+	/**
+	Stop upload. Triggers `stop` event.
+
+	@method stop
+	*/
+	stop: function() {
+		this.uploader.stop();
+	},
+
+
+	/**
+	Enable browse button.
+
+	@method enable
+	*/
+	enable: function() {
+		this.browse_button.button('enable');
+		this.uploader.disableBrowse(false);
+	},
+
+
+	/**
+	Disable browse button.
+
+	@method disable
+	*/
+	disable: function() {
+		this.browse_button.button('disable');
+		this.uploader.disableBrowse(true);
+	},
+
+
+	/**
+	Retrieve file by its unique id.
+
+	@method getFile
+	@param {String} id Unique id of the file
+	@return {plupload.File}
+	*/
+	getFile: function(id) {
+		var file;
+
+		if (typeof id === 'number') {
+			file = this.uploader.files[id];
+		} else {
+			file = this.uploader.getFile(id);
+		}
+		return file;
+	},
+
+	/**
+	Return array of files currently in the queue.
+
+	@method getFiles
+	@return {Array} Array of files in the queue represented by plupload.File objects
+	*/
+	getFiles: function() {
+		return this.uploader.files;
+	},
+
+
+	/**
+	Remove the file from the queue.
+
+	@method removeFile
+	@param {plupload.File|String} file File to remove, might be specified directly or by its unique id
+	*/
+	removeFile: function(file) {
+		if (plupload.typeOf(file) === 'string') {
+			file = this.getFile(file);
+		}
+		this.uploader.removeFile(file);
+	},
+
+
+	/**
+	Clear the file queue.
+
+	@method clearQueue
+	*/
+	clearQueue: function() {
+		this.uploader.splice();
+	},
+
+
+	/**
+	Retrieve internal plupload.Uploader object (usually not required).
+
+	@method getUploader
+	@return {plupload.Uploader}
+	*/
+	getUploader: function() {
+		return this.uploader;
+	},
+
+
+	/**
+	Trigger refresh procedure, specifically browse_button re-measure and re-position operations.
+	Might get handy, when UI Widget is placed within the popup, that is constantly hidden and shown
+	again - without calling this method after each show operation, dialog trigger might get displaced
+	and disfunctional.
+
+	@method refresh
+	*/
+	refresh: function() {
+		this.uploader.refresh();
+	},
+
+
+	/**
+	Display a message in notification area.
+
+	@method notify
+	@param {Enum} type Type of the message, either `error` or `info`
+	@param {String} message The text message to display.
+	*/
+	notify: function(type, message) {
+		var popup = $(
+			'<div class="plupload_message">' +
+				'<span class="plupload_message_close ui-icon ui-icon-circle-close" title="'+_('Close')+'"></span>' +
+				'<p><span class="ui-icon"></span>' + message + '</p>' +
+			'</div>'
+		);
+
+		popup
+			.addClass('ui-state-' + (type === 'error' ? 'error' : 'highlight'))
+			.find('p .ui-icon')
+				.addClass('ui-icon-' + (type === 'error' ? 'alert' : 'info'))
+				.end()
+			.find('.plupload_message_close')
+				.click(function() {
+					popup.remove();
+				})
+				.end();
+
+		$('.plupload_header', this.container).append(popup);
+	},
+
+
+	/**
+	Destroy the widget, the uploader, free associated resources and bring back original html.
+
+	@method destroy
+	*/
+	destroy: function() {
+		// destroy uploader instance
+		this.uploader.destroy();
+
+		// unbind all button events
+		$('.plupload_button', this.element).unbind();
+
+		// destroy buttons
+		if ($.ui.button) {
+			$('.plupload_add, .plupload_start, .plupload_stop', this.container)
+				.button('destroy');
+		}
+
+		// destroy progressbar
+		if ($.ui.progressbar) {
+			this.progressbar.progressbar('destroy');
+		}
+
+		// destroy sortable behavior
+		if ($.ui.sortable && this.options.sortable) {
+			$('tbody', this.filelist).sortable('destroy');
+		}
+
+		// restore the elements initial state
+		this.element
+			.empty()
+			.html(this.contents_bak);
+		this.contents_bak = '';
+
+		$.Widget.prototype.destroy.apply(this);
+	},
+
+
+	_handleState: function() {
+		var up = this.uploader
+		, filesPending = up.files.length - (up.total.uploaded + up.total.failed)
+		, maxCount = up.getOption('filters').max_file_count || 0
+		;
+
+		if (plupload.STARTED === up.state) {
+			$([])
+				.add(this.stop_button)
+				.add('.plupload_started')
+					.removeClass('plupload_hidden');
+
+			this.start_button.button('disable');
+
+			if (!this.options.multiple_queues) {
+				this.browse_button.button('disable');
+				up.disableBrowse();
+			}
+
+			$('.plupload_upload_status', this.element).html(plupload.sprintf(_('Uploaded %d/%d files'), up.total.uploaded, up.files.length));
+			$('.plupload_header_content', this.element).addClass('plupload_header_content_bw');
+		}
+		else if (plupload.STOPPED === up.state) {
+			$([])
+				.add(this.stop_button)
+				.add('.plupload_started')
+					.addClass('plupload_hidden');
+
+			if (filesPending) {
+				this.start_button.button('enable');
+			} else {
+				this.start_button.button('disable');
+			}
+
+			if (this.options.multiple_queues) {
+				$('.plupload_header_content', this.element).removeClass('plupload_header_content_bw');
+			}
+
+			// if max_file_count defined, only that many files can be queued at once
+			if (this.options.multiple_queues && maxCount && maxCount > filesPending) {
+				this.browse_button.button('enable');
+				up.disableBrowse(false);
+			}
+
+			this._updateTotalProgress();
+		}
+
+		if (up.total.queued === 0) {
+			$('.ui-button-text', this.browse_button).html(_('Add Files'));
+		} else {
+			$('.ui-button-text', this.browse_button).html(plupload.sprintf(_('%d files queued'), up.total.queued));
+		}
+
+		// have a helper class on a container expressing whether it has files queued or not
+		this.container.toggleClass('plupload_files_queued', up.files.length);
+
+		up.refresh();
+	},
+
+
+	_handleFileStatus: function(file) {
+		var $file = $('#' + file.id), actionClass, iconClass;
+
+		// since this method might be called asynchronously, file row might not yet be rendered
+		if (!$file.length) {
+			return;
+		}
+
+		switch (file.status) {
+			case plupload.DONE:
+				actionClass = 'plupload_done';
+				iconClass = 'plupload_action_icon ui-icon ui-icon-circle-check';
+				break;
+
+			case plupload.FAILED:
+				actionClass = 'ui-state-error plupload_failed';
+				iconClass = 'plupload_action_icon ui-icon ui-icon-alert';
+				break;
+
+			case plupload.QUEUED:
+				actionClass = 'plupload_delete';
+				iconClass = 'plupload_action_icon ui-icon ui-icon-circle-minus';
+				break;
+
+			case plupload.UPLOADING:
+				actionClass = 'ui-state-highlight plupload_uploading';
+				iconClass = 'plupload_action_icon ui-icon ui-icon-circle-arrow-w';
+
+				// scroll uploading file into the view if its bottom boundary is out of it
+				var scroller = $('.plupload_scroll', this.container)
+				, scrollTop = scroller.scrollTop()
+				, scrollerHeight = scroller.height()
+				, rowOffset = $file.position().top + $file.height()
+				;
+
+				if (scrollerHeight < rowOffset) {
+					scroller.scrollTop(scrollTop + rowOffset - scrollerHeight);
+				}
+
+				// Set file specific progress
+				$file
+					.find('.plupload_file_percent')
+						.html(file.percent + '%')
+						.end()
+					.find('.plupload_file_progress')
+						.css('width', file.percent + '%')
+						.end()
+					.find('.plupload_file_size')
+						.html(plupload.formatSize(file.size));
+				break;
+		}
+		actionClass += ' ui-state-default plupload_file';
+
+		$file
+			.attr('class', actionClass)
+			.find('.plupload_action_icon')
+				.attr('class', iconClass);
+	},
+
+
+	_updateTotalProgress: function() {
+		var up = this.uploader;
+
+		// Scroll to end of file list
+		this.filelist[0].scrollTop = this.filelist[0].scrollHeight;
+
+		this.progressbar.progressbar('value', up.total.percent);
+
+		this.element
+			.find('.plupload_total_status')
+				.html(up.total.percent + '%')
+				.end()
+			.find('.plupload_total_file_size')
+				.html(plupload.formatSize(up.total.size))
+				.end()
+			.find('.plupload_upload_status')
+				.html(plupload.sprintf(_('Uploaded %d/%d files'), up.total.uploaded, up.files.length));
+	},
+
+
+	_displayThumbs: function() {
+		var self = this
+		, tw, th // thumb width/height
+		, cols
+		, num = 0 // number of simultaneously visible thumbs
+		, thumbs = [] // array of thumbs to preload at any given moment
+		, loading = false
+		;
+
+		if (!this.options.views.thumbs) {
+			return;
+		}
+
+
+		function onLast(el, eventName, cb) {
+			var timer;
+
+			el.on(eventName, function() {
+				clearTimeout(timer);
+				timer = setTimeout(function() {
+					clearTimeout(timer);
+					cb();
+				}, 300);
+			});
+		}
+
+
+		// calculate number of simultaneously visible thumbs
+		function measure() {
+			if (!tw || !th) {
+				var wrapper = $('.plupload_file:eq(0)', self.filelist);
+				tw = wrapper.outerWidth(true);
+				th = wrapper.outerHeight(true);
+			}
+
+			var aw = self.content.width(), ah = self.content.height();
+			cols = Math.floor(aw / tw);
+			num =  cols * (Math.ceil(ah / th) + 1);
+		}
+
+
+		function pickThumbsToLoad() {
+			// calculate index of virst visible thumb
+			var startIdx = Math.floor(self.content.scrollTop() / th) * cols;
+			// get potentially visible thumbs that are not yet visible
+			thumbs = $('.plupload_file .plupload_file_thumb', self.filelist)
+				.slice(startIdx, startIdx + num)
+				.filter('.plupload_thumb_toload')
+				.get();
+		}
+
+
+		function init() {
+			function mpl() { // measure, pick, load
+				if (self.view_mode !== 'thumbs') {
+					return;
+				}
+				measure();
+				pickThumbsToLoad();
+				lazyLoad();
+			}
+
+			if ($.fn.resizable) {
+				onLast(self.container, 'resize', mpl);
+			}
+
+			onLast(self.window, 'resize', mpl);
+			onLast(self.content, 'scroll',  mpl);
+
+			self.element.on('viewchanged selected', mpl);
+
+			mpl();
+		}
+
+
+		function preloadThumb(file, cb) {
+			var img = new o.image.Image();
+			var resolveUrl = o.core.utils.Url.resolveUrl;
+
+			img.onload = function() {
+				var thumb = $('#' + file.id + ' .plupload_file_thumb', self.filelist);
+				this.embed(thumb[0], {
+					width: self.options.thumb_width,
+					height: self.options.thumb_height,
+					crop: true,
+					fit: true,
+					preserveHeaders: false,
+					swf_url: resolveUrl(self.options.flash_swf_url),
+					xap_url: resolveUrl(self.options.silverlight_xap_url)
+				});
+			};
+
+			img.bind("embedded error", function(e) {
+				$('#' + file.id, self.filelist)
+					.find('.plupload_file_thumb')
+						.removeClass('plupload_thumb_loading')
+						.addClass('plupload_thumb_' + e.type)
+					;
+				this.destroy();
+				setTimeout(cb, 1); // detach, otherwise ui might hang (in SilverLight for example)
+			});
+
+			$('#' + file.id, self.filelist)
+				.find('.plupload_file_thumb')
+					.removeClass('plupload_thumb_toload')
+					.addClass('plupload_thumb_loading')
+				;
+			img.load(file.getSource());
+		}
+
+
+		function lazyLoad() {
+			if (self.view_mode !== 'thumbs' || loading) {
+				return;
+			}
+
+			pickThumbsToLoad();
+			if (!thumbs.length) {
+				return;
+			}
+
+			loading = true;
+
+			preloadThumb(self.getFile($(thumbs.shift()).closest('.plupload_file').attr('id')), function() {
+				loading = false;
+				lazyLoad();
+			});
+		}
+
+		// this has to run only once to measure structures and bind listeners
+		this.element.on('selected', function onselected() {
+			self.element.off('selected', onselected);
+			init();
+		});
+	},
+
+
+	_addFiles: function(files) {
+		var self = this, file_html, html = '';
+
+		file_html = '<li class="plupload_file ui-state-default plupload_delete" id="{id}" style="width:{thumb_width}px;">' +
+			'<div class="plupload_file_thumb plupload_thumb_toload" style="width: {thumb_width}px; height: {thumb_height}px;">' +
+				'<div class="plupload_file_dummy ui-widget-content" style="line-height: {thumb_height}px;"><span class="ui-state-disabled">{ext} </span></div>' +
+			'</div>' +
+			'<div class="plupload_file_status">' +
+				'<div class="plupload_file_progress ui-widget-header" style="width: 0%"> </div>' +
+				'<span class="plupload_file_percent">{percent} </span>' +
+			'</div>' +
+			'<div class="plupload_file_name" title="{name}">' +
+				'<span class="plupload_file_name_wrapper">{name} </span>' +
+			'</div>' +
+			'<div class="plupload_file_action">' +
+				'<div class="plupload_action_icon ui-icon ui-icon-circle-minus"> </div>' +
+			'</div>' +
+			'<div class="plupload_file_size">{size} </div>' +
+			'<div class="plupload_file_fields"> </div>' +
+		'</li>';
+
+		if (plupload.typeOf(files) !== 'array') {
+			files = [files];
+		}
+
+		$.each(files, function(i, file) {
+			var ext = o.core.utils.Mime.getFileExtension(file.name) || 'none';
+
+			html += file_html.replace(/\{(\w+)\}/g, function($0, $1) {
+				switch ($1) {
+					case 'thumb_width':
+					case 'thumb_height':
+						return self.options[$1];
+
+					case 'size':
+						return plupload.formatSize(file.size);
+
+					case 'ext':
+						return ext;
+
+					default:
+						return file[$1] || '';
+				}
+			});
+		});
+
+		self.filelist.append(html);
+	},
+
+
+	_addFormFields: function() {
+		var self = this;
+
+		// re-add from fresh
+		$('.plupload_file_fields', this.filelist).html('');
+
+		plupload.each(this.uploader.files, function(file, count) {
+			var fields = ''
+			, id = self.id + '_' + count
+			;
+
+			if (file.target_name) {
+				fields += '<input type="hidden" name="' + id + '_tmpname" value="'+plupload.xmlEncode(file.target_name)+'" />';
+			}
+			fields += '<input type="hidden" name="' + id + '_name" value="'+plupload.xmlEncode(file.name)+'" />';
+			fields += '<input type="hidden" name="' + id + '_status" value="' + (file.status === plupload.DONE ? 'done' : 'failed') + '" />';
+
+			$('#' + file.id).find('.plupload_file_fields').html(fields);
+		});
+
+		this.counter.val(this.uploader.files.length);
+	},
+
+
+	_viewChanged: function(view) {
+		// update or write a new cookie
+		if (this.options.views.remember && $.cookie) {
+			$.cookie('plupload_ui_view', view, { expires: 7, path: '/' });
+		}
+
+		// ugly fix for IE6 - make content area stretchable
+		if (plupload.ua.browser === 'IE' && plupload.ua.version < 7) {
+			this.content.attr('style', 'height:expression(document.getElementById("' + this.id + '_container' + '").clientHeight - ' + (view === 'list' ? 132 : 102) + ')');
+		}
+
+		this.container.removeClass('plupload_view_list plupload_view_thumbs').addClass('plupload_view_' + view);
+		this.view_mode = view;
+		this._trigger('viewchanged', null, { view: view });
+	},
+
+
+	_enableViewSwitcher: function() {
+		var self = this
+		, view
+		, switcher = $('.plupload_view_switch', this.container)
+		, buttons
+		, button
+		;
+
+		plupload.each(['list', 'thumbs'], function(view) {
+			if (!self.options.views[view]) {
+				switcher.find('[for="' + self.id + '_view_' + view + '"], #'+ self.id +'_view_' + view).remove();
+			}
+		});
+
+		// check if any visible left
+		buttons = switcher.find('.plupload_button');
+
+		if (buttons.length === 1) {
+			switcher.hide();
+			view = buttons.eq(0).data('view');
+			this._viewChanged(view);
+		} else if ($.ui.button && buttons.length > 1) {
+			if (this.options.views.remember && $.cookie) {
+				view = $.cookie('plupload_ui_view');
+			}
+
+			// if wierd case, bail out to default
+			if (!~plupload.inArray(view, ['list', 'thumbs'])) {
+				view = this.options.views.active;
+			}
+
+			switcher
+				.show()
+				.buttonset()
+				.find('.ui-button')
+					.click(function(e) {
+						view = $(this).data('view');
+						self._viewChanged(view);
+						e.preventDefault(); // avoid auto scrolling to widget in IE and FF (see #850)
+					});
+
+			// if view not active - happens when switcher wasn't clicked manually
+			button = switcher.find('[for="' + self.id + '_view_'+view+'"]');
+			if (button.length) {
+				button.trigger('click');
+			}
+		} else {
+			switcher.show();
+			this._viewChanged(this.options.views.active);
+		}
+
+		// initialize thumb viewer if requested
+		if (this.options.views.thumbs) {
+			this._displayThumbs();
+		}
+	},
+
+
+	_enableRenaming: function() {
+		var self = this;
+
+		this.filelist.dblclick(function(e) {
+			var nameInput, fileContainer, file, parts, name, ext = "";
+			var nameSpan = $(e.target);
+
+			if (!nameSpan.hasClass('plupload_file_name_wrapper')) {
+				return;
+			}
+
+			fileContainer = nameSpan.closest('.plupload_file');
+			if (!fileContainer.hasClass('plupload_delete')) {
+				return;
+			}
+
+			// Get file name and split out name and extension
+			file = self.uploader.getFile(fileContainer[0].id);
+			name = file.name;
+			parts = /^(.+)(\.[^.]+)$/.exec(name);
+			if (parts) {
+				name = parts[1];
+				ext = parts[2];
+			}
+
+			// Display input element
+			nameInput = $('<input class="plupload_file_rename" type="text" />').width(nameSpan.width()).insertAfter(nameSpan.hide());
+			nameInput.val(name).blur(function() {
+				nameSpan.show().parent().scrollLeft(0).end().next().remove();
+			}).keydown(function(e) {
+				var nameInput = $(this);
+
+				if ($.inArray(e.keyCode, [13, 27]) !== -1) {
+					e.preventDefault();
+
+					// Rename file and glue extension back on
+					if (e.keyCode === 13) {
+						file.name = nameInput.val() + ext;
+						nameSpan.html(file.name);
+					}
+					nameInput.blur();
+				}
+			})[0].focus();
+		});
+	},
+
+
+	_enableSortingList: function() {
+		var self = this;
+
+		if ($('.plupload_file', this.filelist).length < 2) {
+			return;
+		}
+
+		// destroy sortable if enabled
+		$('tbody', this.filelist).sortable('destroy');
+
+		// enable
+		this.filelist.sortable({
+			items: '.plupload_delete',
+
+			cancel: 'object, .plupload_clearer',
+
+			stop: function() {
+				var files = [];
+
+				$.each($(this).sortable('toArray'), function(i, id) {
+					files[files.length] = self.uploader.getFile(id);
+				});
+
+				files.unshift(files.length);
+				files.unshift(0);
+
+				// re-populate files array
+				Array.prototype.splice.apply(self.uploader.files, files);
+			}
+		});
+	}
+});
+
+} (window, document, plupload, moxie, jQuery));

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
app/assets/js/plupload-2.3.7/js/jquery.ui.plupload/jquery.ui.plupload.min.js


+ 11714 - 0
app/assets/js/plupload-2.3.7/js/moxie.js

@@ -0,0 +1,11714 @@
+;var MXI_DEBUG = true;
+/**
+ * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
+ * v1.5.7
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ *
+ * Date: 2017-11-03
+ */
+;(function (global, factory) {
+	var extract = function() {
+		var ctx = {};
+		factory.apply(ctx, arguments);
+		return ctx.moxie;
+	};
+	
+	if (typeof define === "function" && define.amd) {
+		define("moxie", [], extract);
+	} else if (typeof module === "object" && module.exports) {
+		module.exports = extract();
+	} else {
+		global.moxie = extract();
+	}
+}(this || window, function() {
+/**
+ * Compiled inline version. (Library mode)
+ */
+
+/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
+/*globals $code */
+
+(function(exports, undefined) {
+	"use strict";
+
+	var modules = {};
+
+	function require(ids, callback) {
+		var module, defs = [];
+
+		for (var i = 0; i < ids.length; ++i) {
+			module = modules[ids[i]] || resolve(ids[i]);
+			if (!module) {
+				throw 'module definition dependecy not found: ' + ids[i];
+			}
+
+			defs.push(module);
+		}
+
+		callback.apply(null, defs);
+	}
+
+	function define(id, dependencies, definition) {
+		if (typeof id !== 'string') {
+			throw 'invalid module definition, module id must be defined and be a string';
+		}
+
+		if (dependencies === undefined) {
+			throw 'invalid module definition, dependencies must be specified';
+		}
+
+		if (definition === undefined) {
+			throw 'invalid module definition, definition function must be specified';
+		}
+
+		require(dependencies, function() {
+			modules[id] = definition.apply(null, arguments);
+		});
+	}
+
+	function defined(id) {
+		return !!modules[id];
+	}
+
+	function resolve(id) {
+		var target = exports;
+		var fragments = id.split(/[.\/]/);
+
+		for (var fi = 0; fi < fragments.length; ++fi) {
+			if (!target[fragments[fi]]) {
+				return;
+			}
+
+			target = target[fragments[fi]];
+		}
+
+		return target;
+	}
+
+	function expose(ids) {
+		for (var i = 0; i < ids.length; i++) {
+			var target = exports;
+			var id = ids[i];
+			var fragments = id.split(/[.\/]/);
+
+			for (var fi = 0; fi < fragments.length - 1; ++fi) {
+				if (target[fragments[fi]] === undefined) {
+					target[fragments[fi]] = {};
+				}
+
+				target = target[fragments[fi]];
+			}
+
+			target[fragments[fragments.length - 1]] = modules[id];
+		}
+	}
+
+// Included from: src/javascript/core/utils/Basic.js
+
+/**
+ * Basic.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Basic
+@public
+@static
+*/
+
+define('moxie/core/utils/Basic', [], function() {
+	/**
+	Gets the true type of the built-in object (better version of typeof).
+	@author Angus Croll (http://javascriptweblog.wordpress.com/)
+
+	@method typeOf
+	@static
+	@param {Object} o Object to check.
+	@return {String} Object [[Class]]
+	*/
+	function typeOf(o) {
+		var undef;
+
+		if (o === undef) {
+			return 'undefined';
+		} else if (o === null) {
+			return 'null';
+		} else if (o.nodeType) {
+			return 'node';
+		}
+
+		// the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8
+		return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
+	}
+
+	/**
+	Extends the specified object with another object(s).
+
+	@method extend
+	@static
+	@param {Object} target Object to extend.
+	@param {Object} [obj]* Multiple objects to extend with.
+	@return {Object} Same as target, the extended object.
+	*/
+	function extend() {
+		return merge(false, false, arguments);
+	}
+
+
+	/**
+	Extends the specified object with another object(s), but only if the property exists in the target.
+
+	@method extendIf
+	@static
+	@param {Object} target Object to extend.
+	@param {Object} [obj]* Multiple objects to extend with.
+	@return {Object} Same as target, the extended object.
+	*/
+	function extendIf() {
+		return merge(true, false, arguments);
+	}
+
+
+	function extendImmutable() {
+		return merge(false, true, arguments);
+	}
+
+
+	function extendImmutableIf() {
+		return merge(true, true, arguments);
+	}
+
+
+	function clone(value) {
+		switch (typeOf(value)) {
+			case 'array':
+				return merge(false, true, [[], value]);
+
+			case 'object':
+				return merge(false, true, [{}, value]);
+
+			default:
+				return value;
+		}
+	}
+
+
+	function shallowCopy(obj) {
+		switch (typeOf(obj)) {
+			case 'array':
+				return Array.prototype.slice.call(obj);
+
+			case 'object':
+				return extend({}, obj);
+		}
+		return obj;
+	}
+
+
+	function merge(strict, immutable, args) {
+		var undef;
+		var target = args[0];
+
+		each(args, function(arg, i) {
+			if (i > 0) {
+				each(arg, function(value, key) {
+					var isComplex = inArray(typeOf(value), ['array', 'object']) !== -1;
+
+					if (value === undef || strict && target[key] === undef) {
+						return true;
+					}
+
+					if (isComplex && immutable) {
+						value = shallowCopy(value);
+					}
+
+					if (typeOf(target[key]) === typeOf(value) && isComplex) {
+						merge(strict, immutable, [target[key], value]);
+					} else {
+						target[key] = value;
+					}
+				});
+			}
+		});
+
+		return target;
+	}
+
+
+	/**
+	A way to inherit one `class` from another in a consisstent way (more or less)
+
+	@method inherit
+	@static
+	@since >1.4.1
+	@param {Function} child
+	@param {Function} parent
+	@return {Function} Prepared constructor
+	*/
+	function inherit(child, parent) {
+		// copy over all parent properties
+		for (var key in parent) {
+			if ({}.hasOwnProperty.call(parent, key)) {
+				child[key] = parent[key];
+			}
+		}
+
+		// give child `class` a place to define its own methods
+		function ctor() {
+			this.constructor = child;
+
+			if (MXI_DEBUG) {
+				var getCtorName = function(fn) {
+					var m = fn.toString().match(/^function\s([^\(\s]+)/);
+					return m ? m[1] : false;
+				};
+
+				this.ctorName = getCtorName(child);
+			}
+		}
+		ctor.prototype = parent.prototype;
+		child.prototype = new ctor();
+
+		// keep a way to reference parent methods
+		child.parent = parent.prototype;
+		return child;
+	}
+
+
+	/**
+	Executes the callback function for each item in array/object. If you return false in the
+	callback it will break the loop.
+
+	@method each
+	@static
+	@param {Object} obj Object to iterate.
+	@param {function} callback Callback function to execute for each item.
+	*/
+	function each(obj, callback) {
+		var length, key, i, undef;
+
+		if (obj) {
+			try {
+				length = obj.length;
+			} catch(ex) {
+				length = undef;
+			}
+
+			if (length === undef || typeof(length) !== 'number') {
+				// Loop object items
+				for (key in obj) {
+					if (obj.hasOwnProperty(key)) {
+						if (callback(obj[key], key) === false) {
+							return;
+						}
+					}
+				}
+			} else {
+				// Loop array items
+				for (i = 0; i < length; i++) {
+					if (callback(obj[i], i) === false) {
+						return;
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	Checks if object is empty.
+
+	@method isEmptyObj
+	@static
+	@param {Object} o Object to check.
+	@return {Boolean}
+	*/
+	function isEmptyObj(obj) {
+		var prop;
+
+		if (!obj || typeOf(obj) !== 'object') {
+			return true;
+		}
+
+		for (prop in obj) {
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	Recieve an array of functions (usually async) to call in sequence, each  function
+	receives a callback as first argument that it should call, when it completes. Finally,
+	after everything is complete, main callback is called. Passing truthy value to the
+	callback as a first argument will interrupt the sequence and invoke main callback
+	immediately.
+
+	@method inSeries
+	@static
+	@param {Array} queue Array of functions to call in sequence
+	@param {Function} cb Main callback that is called in the end, or in case of error
+	*/
+	function inSeries(queue, cb) {
+		var i = 0, length = queue.length;
+
+		if (typeOf(cb) !== 'function') {
+			cb = function() {};
+		}
+
+		if (!queue || !queue.length) {
+			cb();
+		}
+
+		function callNext(i) {
+			if (typeOf(queue[i]) === 'function') {
+				queue[i](function(error) {
+					/*jshint expr:true */
+					++i < length && !error ? callNext(i) : cb(error);
+				});
+			}
+		}
+		callNext(i);
+	}
+
+
+	/**
+	Recieve an array of functions (usually async) to call in parallel, each  function
+	receives a callback as first argument that it should call, when it completes. After
+	everything is complete, main callback is called. Passing truthy value to the
+	callback as a first argument will interrupt the process and invoke main callback
+	immediately.
+
+	@method inParallel
+	@static
+	@param {Array} queue Array of functions to call in sequence
+	@param {Function} cb Main callback that is called in the end, or in case of erro
+	*/
+	function inParallel(queue, cb) {
+		var count = 0, num = queue.length, cbArgs = new Array(num);
+
+		each(queue, function(fn, i) {
+			fn(function(error) {
+				if (error) {
+					return cb(error);
+				}
+
+				var args = [].slice.call(arguments);
+				args.shift(); // strip error - undefined or not
+
+				cbArgs[i] = args;
+				count++;
+
+				if (count === num) {
+					cbArgs.unshift(null);
+					cb.apply(this, cbArgs);
+				}
+			});
+		});
+	}
+
+
+	/**
+	Find an element in array and return it's index if present, otherwise return -1.
+
+	@method inArray
+	@static
+	@param {Mixed} needle Element to find
+	@param {Array} array
+	@return {Int} Index of the element, or -1 if not found
+	*/
+	function inArray(needle, array) {
+		if (array) {
+			if (Array.prototype.indexOf) {
+				return Array.prototype.indexOf.call(array, needle);
+			}
+
+			for (var i = 0, length = array.length; i < length; i++) {
+				if (array[i] === needle) {
+					return i;
+				}
+			}
+		}
+		return -1;
+	}
+
+
+	/**
+	Returns elements of first array if they are not present in second. And false - otherwise.
+
+	@private
+	@method arrayDiff
+	@param {Array} needles
+	@param {Array} array
+	@return {Array|Boolean}
+	*/
+	function arrayDiff(needles, array) {
+		var diff = [];
+
+		if (typeOf(needles) !== 'array') {
+			needles = [needles];
+		}
+
+		if (typeOf(array) !== 'array') {
+			array = [array];
+		}
+
+		for (var i in needles) {
+			if (inArray(needles[i], array) === -1) {
+				diff.push(needles[i]);
+			}
+		}
+		return diff.length ? diff : false;
+	}
+
+
+	/**
+	Find intersection of two arrays.
+
+	@private
+	@method arrayIntersect
+	@param {Array} array1
+	@param {Array} array2
+	@return {Array} Intersection of two arrays or null if there is none
+	*/
+	function arrayIntersect(array1, array2) {
+		var result = [];
+		each(array1, function(item) {
+			if (inArray(item, array2) !== -1) {
+				result.push(item);
+			}
+		});
+		return result.length ? result : null;
+	}
+
+
+	/**
+	Forces anything into an array.
+
+	@method toArray
+	@static
+	@param {Object} obj Object with length field.
+	@return {Array} Array object containing all items.
+	*/
+	function toArray(obj) {
+		var i, arr = [];
+
+		for (i = 0; i < obj.length; i++) {
+			arr[i] = obj[i];
+		}
+
+		return arr;
+	}
+
+
+	/**
+	Generates an unique ID. The only way a user would be able to get the same ID is if the two persons
+	at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses
+	a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth
+	to be hit with an asteroid.
+
+	@method guid
+	@static
+	@param {String} prefix to prepend (by default 'o' will be prepended).
+	@method guid
+	@return {String} Virtually unique id.
+	*/
+	var guid = (function() {
+		var counter = 0;
+
+		return function(prefix) {
+			var guid = new Date().getTime().toString(32), i;
+
+			for (i = 0; i < 5; i++) {
+				guid += Math.floor(Math.random() * 65535).toString(32);
+			}
+
+			return (prefix || 'o_') + guid + (counter++).toString(32);
+		};
+	}());
+
+
+	/**
+	Trims white spaces around the string
+
+	@method trim
+	@static
+	@param {String} str
+	@return {String}
+	*/
+	function trim(str) {
+		if (!str) {
+			return str;
+		}
+		return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, '');
+	}
+
+
+	/**
+	Parses the specified size string into a byte value. For example 10kb becomes 10240.
+
+	@method parseSizeStr
+	@static
+	@param {String/Number} size String to parse or number to just pass through.
+	@return {Number} Size in bytes.
+	*/
+	function parseSizeStr(size) {
+		if (typeof(size) !== 'string') {
+			return size;
+		}
+
+		var muls = {
+				t: 1099511627776,
+				g: 1073741824,
+				m: 1048576,
+				k: 1024
+			},
+			mul;
+
+		size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, ''));
+		mul = size[2];
+		size = +size[1];
+
+		if (muls.hasOwnProperty(mul)) {
+			size *= muls[mul];
+		}
+		return Math.floor(size);
+	}
+
+
+	/**
+	 * Pseudo sprintf implementation - simple way to replace tokens with specified values.
+	 *
+	 * @param {String} str String with tokens
+	 * @return {String} String with replaced tokens
+	 */
+	function sprintf(str) {
+		var args = [].slice.call(arguments, 1);
+
+		return str.replace(/%([a-z])/g, function($0, $1) {
+			var value = args.shift();
+
+			switch ($1) {
+				case 's':
+					return value + '';
+
+				case 'd':
+					return parseInt(value, 10);
+
+				case 'f':
+					return parseFloat(value);
+
+				case 'c':
+					return '';
+
+				default:
+					return value;
+			}
+		});
+	}
+
+
+
+	function delay(cb, timeout) {
+		var self = this;
+		setTimeout(function() {
+			cb.call(self);
+		}, timeout || 1);
+	}
+
+
+	return {
+		guid: guid,
+		typeOf: typeOf,
+		extend: extend,
+		extendIf: extendIf,
+		extendImmutable: extendImmutable,
+		extendImmutableIf: extendImmutableIf,
+		clone: clone,
+		inherit: inherit,
+		each: each,
+		isEmptyObj: isEmptyObj,
+		inSeries: inSeries,
+		inParallel: inParallel,
+		inArray: inArray,
+		arrayDiff: arrayDiff,
+		arrayIntersect: arrayIntersect,
+		toArray: toArray,
+		trim: trim,
+		sprintf: sprintf,
+		parseSizeStr: parseSizeStr,
+		delay: delay
+	};
+});
+
+// Included from: src/javascript/core/utils/Encode.js
+
+/**
+ * Encode.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Encode
+@public
+@static
+*/
+
+define('moxie/core/utils/Encode', [], function() {
+
+	/**
+	Encode string with UTF-8
+
+	@method utf8_encode
+	@static
+	@param {String} str String to encode
+	@return {String} UTF-8 encoded string
+	*/
+	var utf8_encode = function(str) {
+		return unescape(encodeURIComponent(str));
+	};
+	
+	/**
+	Decode UTF-8 encoded string
+
+	@method utf8_decode
+	@static
+	@param {String} str String to decode
+	@return {String} Decoded string
+	*/
+	var utf8_decode = function(str_data) {
+		return decodeURIComponent(escape(str_data));
+	};
+	
+	/**
+	Decode Base64 encoded string (uses browser's default method if available),
+	from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js
+
+	@method atob
+	@static
+	@param {String} data String to decode
+	@return {String} Decoded string
+	*/
+	var atob = function(data, utf8) {
+		if (typeof(window.atob) === 'function') {
+			return utf8 ? utf8_decode(window.atob(data)) : window.atob(data);
+		}
+
+		// http://kevin.vanzonneveld.net
+		// +   original by: Tyler Akins (http://rumkin.com)
+		// +   improved by: Thunder.m
+		// +      input by: Aman Gupta
+		// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+		// +   bugfixed by: Onno Marsman
+		// +   bugfixed by: Pellentesque Malesuada
+		// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+		// +      input by: Brett Zamir (http://brett-zamir.me)
+		// +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+		// *     example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
+		// *     returns 1: 'Kevin van Zonneveld'
+		// mozilla has this native
+		// - but breaks in 2.0.0.12!
+		//if (typeof this.window.atob == 'function') {
+		//    return atob(data);
+		//}
+		var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+		var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
+			ac = 0,
+			dec = "",
+			tmp_arr = [];
+
+		if (!data) {
+			return data;
+		}
+
+		data += '';
+
+		do { // unpack four hexets into three octets using index points in b64
+			h1 = b64.indexOf(data.charAt(i++));
+			h2 = b64.indexOf(data.charAt(i++));
+			h3 = b64.indexOf(data.charAt(i++));
+			h4 = b64.indexOf(data.charAt(i++));
+
+			bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
+
+			o1 = bits >> 16 & 0xff;
+			o2 = bits >> 8 & 0xff;
+			o3 = bits & 0xff;
+
+			if (h3 == 64) {
+				tmp_arr[ac++] = String.fromCharCode(o1);
+			} else if (h4 == 64) {
+				tmp_arr[ac++] = String.fromCharCode(o1, o2);
+			} else {
+				tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
+			}
+		} while (i < data.length);
+
+		dec = tmp_arr.join('');
+
+		return utf8 ? utf8_decode(dec) : dec;
+	};
+	
+	/**
+	Base64 encode string (uses browser's default method if available),
+	from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js
+
+	@method btoa
+	@static
+	@param {String} data String to encode
+	@return {String} Base64 encoded string
+	*/
+	var btoa = function(data, utf8) {
+		if (utf8) {
+			data = utf8_encode(data);
+		}
+
+		if (typeof(window.btoa) === 'function') {
+			return window.btoa(data);
+		}
+
+		// http://kevin.vanzonneveld.net
+		// +   original by: Tyler Akins (http://rumkin.com)
+		// +   improved by: Bayron Guevara
+		// +   improved by: Thunder.m
+		// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+		// +   bugfixed by: Pellentesque Malesuada
+		// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+		// +   improved by: Rafał Kukawski (http://kukawski.pl)
+		// *     example 1: base64_encode('Kevin van Zonneveld');
+		// *     returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
+		// mozilla has this native
+		// - but breaks in 2.0.0.12!
+		var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+		var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
+			ac = 0,
+			enc = "",
+			tmp_arr = [];
+
+		if (!data) {
+			return data;
+		}
+
+		do { // pack three octets into four hexets
+			o1 = data.charCodeAt(i++);
+			o2 = data.charCodeAt(i++);
+			o3 = data.charCodeAt(i++);
+
+			bits = o1 << 16 | o2 << 8 | o3;
+
+			h1 = bits >> 18 & 0x3f;
+			h2 = bits >> 12 & 0x3f;
+			h3 = bits >> 6 & 0x3f;
+			h4 = bits & 0x3f;
+
+			// use hexets to index into b64, and append result to encoded string
+			tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
+		} while (i < data.length);
+
+		enc = tmp_arr.join('');
+
+		var r = data.length % 3;
+
+		return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
+	};
+
+
+	return {
+		utf8_encode: utf8_encode,
+		utf8_decode: utf8_decode,
+		atob: atob,
+		btoa: btoa
+	};
+});
+
+// Included from: src/javascript/core/utils/Env.js
+
+/**
+ * Env.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Env
+@public
+@static
+*/
+
+define("moxie/core/utils/Env", [
+	"moxie/core/utils/Basic"
+], function(Basic) {
+
+	/**
+	 * UAParser.js v0.7.7
+	 * Lightweight JavaScript-based User-Agent string parser
+	 * https://github.com/faisalman/ua-parser-js
+	 *
+	 * Copyright © 2012-2015 Faisal Salman <fyzlman@gmail.com>
+	 * Dual licensed under GPLv2 & MIT
+	 */
+	var UAParser = (function (undefined) {
+
+	    //////////////
+	    // Constants
+	    /////////////
+
+
+	    var EMPTY       = '',
+	        UNKNOWN     = '?',
+	        FUNC_TYPE   = 'function',
+	        UNDEF_TYPE  = 'undefined',
+	        OBJ_TYPE    = 'object',
+	        MAJOR       = 'major',
+	        MODEL       = 'model',
+	        NAME        = 'name',
+	        TYPE        = 'type',
+	        VENDOR      = 'vendor',
+	        VERSION     = 'version',
+	        ARCHITECTURE= 'architecture',
+	        CONSOLE     = 'console',
+	        MOBILE      = 'mobile',
+	        TABLET      = 'tablet';
+
+
+	    ///////////
+	    // Helper
+	    //////////
+
+
+	    var util = {
+	        has : function (str1, str2) {
+	            return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1;
+	        },
+	        lowerize : function (str) {
+	            return str.toLowerCase();
+	        }
+	    };
+
+
+	    ///////////////
+	    // Map helper
+	    //////////////
+
+
+	    var mapper = {
+
+	        rgx : function () {
+
+	            // loop through all regexes maps
+	            for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) {
+
+	                var regex = args[i],       // even sequence (0,2,4,..)
+	                    props = args[i + 1];   // odd sequence (1,3,5,..)
+
+	                // construct object barebones
+	                if (typeof(result) === UNDEF_TYPE) {
+	                    result = {};
+	                    for (p in props) {
+	                        q = props[p];
+	                        if (typeof(q) === OBJ_TYPE) {
+	                            result[q[0]] = undefined;
+	                        } else {
+	                            result[q] = undefined;
+	                        }
+	                    }
+	                }
+
+	                // try matching uastring with regexes
+	                for (j = k = 0; j < regex.length; j++) {
+	                    matches = regex[j].exec(this.getUA());
+	                    if (!!matches) {
+	                        for (p = 0; p < props.length; p++) {
+	                            match = matches[++k];
+	                            q = props[p];
+	                            // check if given property is actually array
+	                            if (typeof(q) === OBJ_TYPE && q.length > 0) {
+	                                if (q.length == 2) {
+	                                    if (typeof(q[1]) == FUNC_TYPE) {
+	                                        // assign modified match
+	                                        result[q[0]] = q[1].call(this, match);
+	                                    } else {
+	                                        // assign given value, ignore regex match
+	                                        result[q[0]] = q[1];
+	                                    }
+	                                } else if (q.length == 3) {
+	                                    // check whether function or regex
+	                                    if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) {
+	                                        // call function (usually string mapper)
+	                                        result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
+	                                    } else {
+	                                        // sanitize match using given regex
+	                                        result[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
+	                                    }
+	                                } else if (q.length == 4) {
+	                                        result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
+	                                }
+	                            } else {
+	                                result[q] = match ? match : undefined;
+	                            }
+	                        }
+	                        break;
+	                    }
+	                }
+
+	                if(!!matches) break; // break the loop immediately if match found
+	            }
+	            return result;
+	        },
+
+	        str : function (str, map) {
+
+	            for (var i in map) {
+	                // check if array
+	                if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) {
+	                    for (var j = 0; j < map[i].length; j++) {
+	                        if (util.has(map[i][j], str)) {
+	                            return (i === UNKNOWN) ? undefined : i;
+	                        }
+	                    }
+	                } else if (util.has(map[i], str)) {
+	                    return (i === UNKNOWN) ? undefined : i;
+	                }
+	            }
+	            return str;
+	        }
+	    };
+
+
+	    ///////////////
+	    // String map
+	    //////////////
+
+
+	    var maps = {
+
+	        browser : {
+	            oldsafari : {
+	                major : {
+	                    '1' : ['/8', '/1', '/3'],
+	                    '2' : '/4',
+	                    '?' : '/'
+	                },
+	                version : {
+	                    '1.0'   : '/8',
+	                    '1.2'   : '/1',
+	                    '1.3'   : '/3',
+	                    '2.0'   : '/412',
+	                    '2.0.2' : '/416',
+	                    '2.0.3' : '/417',
+	                    '2.0.4' : '/419',
+	                    '?'     : '/'
+	                }
+	            }
+	        },
+
+	        device : {
+	            sprint : {
+	                model : {
+	                    'Evo Shift 4G' : '7373KT'
+	                },
+	                vendor : {
+	                    'HTC'       : 'APA',
+	                    'Sprint'    : 'Sprint'
+	                }
+	            }
+	        },
+
+	        os : {
+	            windows : {
+	                version : {
+	                    'ME'        : '4.90',
+	                    'NT 3.11'   : 'NT3.51',
+	                    'NT 4.0'    : 'NT4.0',
+	                    '2000'      : 'NT 5.0',
+	                    'XP'        : ['NT 5.1', 'NT 5.2'],
+	                    'Vista'     : 'NT 6.0',
+	                    '7'         : 'NT 6.1',
+	                    '8'         : 'NT 6.2',
+	                    '8.1'       : 'NT 6.3',
+	                    'RT'        : 'ARM'
+	                }
+	            }
+	        }
+	    };
+
+
+	    //////////////
+	    // Regex map
+	    /////////////
+
+
+	    var regexes = {
+
+	        browser : [[
+
+	            // Presto based
+	            /(opera\smini)\/([\w\.-]+)/i,                                       // Opera Mini
+	            /(opera\s[mobiletab]+).+version\/([\w\.-]+)/i,                      // Opera Mobi/Tablet
+	            /(opera).+version\/([\w\.]+)/i,                                     // Opera > 9.80
+	            /(opera)[\/\s]+([\w\.]+)/i                                          // Opera < 9.80
+
+	            ], [NAME, VERSION], [
+
+	            /\s(opr)\/([\w\.]+)/i                                               // Opera Webkit
+	            ], [[NAME, 'Opera'], VERSION], [
+
+	            // Mixed
+	            /(kindle)\/([\w\.]+)/i,                                             // Kindle
+	            /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i,
+	                                                                                // Lunascape/Maxthon/Netfront/Jasmine/Blazer
+
+	            // Trident based
+	            /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i,
+	                                                                                // Avant/IEMobile/SlimBrowser/Baidu
+	            /(?:ms|\()(ie)\s([\w\.]+)/i,                                        // Internet Explorer
+
+	            // Webkit/KHTML based
+	            /(rekonq)\/([\w\.]+)*/i,                                            // Rekonq
+	            /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i
+	                                                                                // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron
+	            ], [NAME, VERSION], [
+
+	            /(trident).+rv[:\s]([\w\.]+).+like\sgecko/i                         // IE11
+	            ], [[NAME, 'IE'], VERSION], [
+
+	            /(edge)\/((\d+)?[\w\.]+)/i                                          // Microsoft Edge
+	            ], [NAME, VERSION], [
+
+	            /(yabrowser)\/([\w\.]+)/i                                           // Yandex
+	            ], [[NAME, 'Yandex'], VERSION], [
+
+	            /(comodo_dragon)\/([\w\.]+)/i                                       // Comodo Dragon
+	            ], [[NAME, /_/g, ' '], VERSION], [
+
+	            /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i,
+	                                                                                // Chrome/OmniWeb/Arora/Tizen/Nokia
+	            /(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i
+	                                                                                // UCBrowser/QQBrowser
+	            ], [NAME, VERSION], [
+
+	            /(dolfin)\/([\w\.]+)/i                                              // Dolphin
+	            ], [[NAME, 'Dolphin'], VERSION], [
+
+	            /((?:android.+)crmo|crios)\/([\w\.]+)/i                             // Chrome for Android/iOS
+	            ], [[NAME, 'Chrome'], VERSION], [
+
+	            /XiaoMi\/MiuiBrowser\/([\w\.]+)/i                                   // MIUI Browser
+	            ], [VERSION, [NAME, 'MIUI Browser']], [
+
+	            /android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i         // Android Browser
+	            ], [VERSION, [NAME, 'Android Browser']], [
+
+	            /FBAV\/([\w\.]+);/i                                                 // Facebook App for iOS
+	            ], [VERSION, [NAME, 'Facebook']], [
+
+	            /version\/([\w\.]+).+?mobile\/\w+\s(safari)/i                       // Mobile Safari
+	            ], [VERSION, [NAME, 'Mobile Safari']], [
+
+	            /version\/([\w\.]+).+?(mobile\s?safari|safari)/i                    // Safari & Safari Mobile
+	            ], [VERSION, NAME], [
+
+	            /webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i                     // Safari < 3.0
+	            ], [NAME, [VERSION, mapper.str, maps.browser.oldsafari.version]], [
+
+	            /(konqueror)\/([\w\.]+)/i,                                          // Konqueror
+	            /(webkit|khtml)\/([\w\.]+)/i
+	            ], [NAME, VERSION], [
+
+	            // Gecko based
+	            /(navigator|netscape)\/([\w\.-]+)/i                                 // Netscape
+	            ], [[NAME, 'Netscape'], VERSION], [
+	            /(swiftfox)/i,                                                      // Swiftfox
+	            /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,
+	                                                                                // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
+	            /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i,
+	                                                                                // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
+	            /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i,                          // Mozilla
+
+	            // Other
+	            /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i,
+	                                                                                // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf
+	            /(links)\s\(([\w\.]+)/i,                                            // Links
+	            /(gobrowser)\/?([\w\.]+)*/i,                                        // GoBrowser
+	            /(ice\s?browser)\/v?([\w\._]+)/i,                                   // ICE Browser
+	            /(mosaic)[\/\s]([\w\.]+)/i                                          // Mosaic
+	            ], [NAME, VERSION]
+	        ],
+
+	        engine : [[
+
+	            /windows.+\sedge\/([\w\.]+)/i                                       // EdgeHTML
+	            ], [VERSION, [NAME, 'EdgeHTML']], [
+
+	            /(presto)\/([\w\.]+)/i,                                             // Presto
+	            /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i,     // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m
+	            /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i,                          // KHTML/Tasman/Links
+	            /(icab)[\/\s]([23]\.[\d\.]+)/i                                      // iCab
+	            ], [NAME, VERSION], [
+
+	            /rv\:([\w\.]+).*(gecko)/i                                           // Gecko
+	            ], [VERSION, NAME]
+	        ],
+
+	        os : [[
+
+	            // Windows based
+	            /microsoft\s(windows)\s(vista|xp)/i                                 // Windows (iTunes)
+	            ], [NAME, VERSION], [
+	            /(windows)\snt\s6\.2;\s(arm)/i,                                     // Windows RT
+	            /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i
+	            ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
+	            /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
+	            ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
+
+	            // Mobile/Embedded OS
+	            /\((bb)(10);/i                                                      // BlackBerry 10
+	            ], [[NAME, 'BlackBerry'], VERSION], [
+	            /(blackberry)\w*\/?([\w\.]+)*/i,                                    // Blackberry
+	            /(tizen)[\/\s]([\w\.]+)/i,                                          // Tizen
+	            /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i,
+	                                                                                // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki
+	            /linux;.+(sailfish);/i                                              // Sailfish OS
+	            ], [NAME, VERSION], [
+	            /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i                 // Symbian
+	            ], [[NAME, 'Symbian'], VERSION], [
+	            /\((series40);/i                                                    // Series 40
+	            ], [NAME], [
+	            /mozilla.+\(mobile;.+gecko.+firefox/i                               // Firefox OS
+	            ], [[NAME, 'Firefox OS'], VERSION], [
+
+	            // Console
+	            /(nintendo|playstation)\s([wids3portablevu]+)/i,                    // Nintendo/Playstation
+
+	            // GNU/Linux based
+	            /(mint)[\/\s\(]?(\w+)*/i,                                           // Mint
+	            /(mageia|vectorlinux)[;\s]/i,                                       // Mageia/VectorLinux
+	            /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i,
+	                                                                                // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
+	                                                                                // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus
+	            /(hurd|linux)\s?([\w\.]+)*/i,                                       // Hurd/Linux
+	            /(gnu)\s?([\w\.]+)*/i                                               // GNU
+	            ], [NAME, VERSION], [
+
+	            /(cros)\s[\w]+\s([\w\.]+\w)/i                                       // Chromium OS
+	            ], [[NAME, 'Chromium OS'], VERSION],[
+
+	            // Solaris
+	            /(sunos)\s?([\w\.]+\d)*/i                                           // Solaris
+	            ], [[NAME, 'Solaris'], VERSION], [
+
+	            // BSD based
+	            /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i                   // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
+	            ], [NAME, VERSION],[
+
+	            /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i             // iOS
+	            ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [
+
+	            /(mac\sos\sx)\s?([\w\s\.]+\w)*/i,
+	            /(macintosh|mac(?=_powerpc)\s)/i                                    // Mac OS
+	            ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [
+
+	            // Other
+	            /((?:open)?solaris)[\/\s-]?([\w\.]+)*/i,                            // Solaris
+	            /(haiku)\s(\w+)/i,                                                  // Haiku
+	            /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i,                               // AIX
+	            /(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i,
+	                                                                                // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS
+	            /(unix)\s?([\w\.]+)*/i                                              // UNIX
+	            ], [NAME, VERSION]
+	        ]
+	    };
+
+
+	    /////////////////
+	    // Constructor
+	    ////////////////
+
+
+	    var UAParser = function (uastring) {
+
+	        var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
+
+	        this.getBrowser = function () {
+	            return mapper.rgx.apply(this, regexes.browser);
+	        };
+	        this.getEngine = function () {
+	            return mapper.rgx.apply(this, regexes.engine);
+	        };
+	        this.getOS = function () {
+	            return mapper.rgx.apply(this, regexes.os);
+	        };
+	        this.getResult = function() {
+	            return {
+	                ua      : this.getUA(),
+	                browser : this.getBrowser(),
+	                engine  : this.getEngine(),
+	                os      : this.getOS()
+	            };
+	        };
+	        this.getUA = function () {
+	            return ua;
+	        };
+	        this.setUA = function (uastring) {
+	            ua = uastring;
+	            return this;
+	        };
+	        this.setUA(ua);
+	    };
+
+	    return UAParser;
+	})();
+
+
+	function version_compare(v1, v2, operator) {
+	  // From: http://phpjs.org/functions
+	  // +      original by: Philippe Jausions (http://pear.php.net/user/jausions)
+	  // +      original by: Aidan Lister (http://aidanlister.com/)
+	  // + reimplemented by: Kankrelune (http://www.webfaktory.info/)
+	  // +      improved by: Brett Zamir (http://brett-zamir.me)
+	  // +      improved by: Scott Baker
+	  // +      improved by: Theriault
+	  // *        example 1: version_compare('8.2.5rc', '8.2.5a');
+	  // *        returns 1: 1
+	  // *        example 2: version_compare('8.2.50', '8.2.52', '<');
+	  // *        returns 2: true
+	  // *        example 3: version_compare('5.3.0-dev', '5.3.0');
+	  // *        returns 3: -1
+	  // *        example 4: version_compare('4.1.0.52','4.01.0.51');
+	  // *        returns 4: 1
+
+	  // Important: compare must be initialized at 0.
+	  var i = 0,
+	    x = 0,
+	    compare = 0,
+	    // vm maps textual PHP versions to negatives so they're less than 0.
+	    // PHP currently defines these as CASE-SENSITIVE. It is important to
+	    // leave these as negatives so that they can come before numerical versions
+	    // and as if no letters were there to begin with.
+	    // (1alpha is < 1 and < 1.1 but > 1dev1)
+	    // If a non-numerical value can't be mapped to this table, it receives
+	    // -7 as its value.
+	    vm = {
+	      'dev': -6,
+	      'alpha': -5,
+	      'a': -5,
+	      'beta': -4,
+	      'b': -4,
+	      'RC': -3,
+	      'rc': -3,
+	      '#': -2,
+	      'p': 1,
+	      'pl': 1
+	    },
+	    // This function will be called to prepare each version argument.
+	    // It replaces every _, -, and + with a dot.
+	    // It surrounds any nonsequence of numbers/dots with dots.
+	    // It replaces sequences of dots with a single dot.
+	    //    version_compare('4..0', '4.0') == 0
+	    // Important: A string of 0 length needs to be converted into a value
+	    // even less than an unexisting value in vm (-7), hence [-8].
+	    // It's also important to not strip spaces because of this.
+	    //   version_compare('', ' ') == 1
+	    prepVersion = function (v) {
+	      v = ('' + v).replace(/[_\-+]/g, '.');
+	      v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
+	      return (!v.length ? [-8] : v.split('.'));
+	    },
+	    // This converts a version component to a number.
+	    // Empty component becomes 0.
+	    // Non-numerical component becomes a negative number.
+	    // Numerical component becomes itself as an integer.
+	    numVersion = function (v) {
+	      return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
+	    };
+
+	  v1 = prepVersion(v1);
+	  v2 = prepVersion(v2);
+	  x = Math.max(v1.length, v2.length);
+	  for (i = 0; i < x; i++) {
+	    if (v1[i] == v2[i]) {
+	      continue;
+	    }
+	    v1[i] = numVersion(v1[i]);
+	    v2[i] = numVersion(v2[i]);
+	    if (v1[i] < v2[i]) {
+	      compare = -1;
+	      break;
+	    } else if (v1[i] > v2[i]) {
+	      compare = 1;
+	      break;
+	    }
+	  }
+	  if (!operator) {
+	    return compare;
+	  }
+
+	  // Important: operator is CASE-SENSITIVE.
+	  // "No operator" seems to be treated as "<."
+	  // Any other values seem to make the function return null.
+	  switch (operator) {
+	  case '>':
+	  case 'gt':
+	    return (compare > 0);
+	  case '>=':
+	  case 'ge':
+	    return (compare >= 0);
+	  case '<=':
+	  case 'le':
+	    return (compare <= 0);
+	  case '==':
+	  case '=':
+	  case 'eq':
+	    return (compare === 0);
+	  case '<>':
+	  case '!=':
+	  case 'ne':
+	    return (compare !== 0);
+	  case '':
+	  case '<':
+	  case 'lt':
+	    return (compare < 0);
+	  default:
+	    return null;
+	  }
+	}
+
+
+	var can = (function() {
+		var caps = {
+			access_global_ns: function () {
+				return !!window.moxie;
+			},
+
+			define_property: (function() {
+				/* // currently too much extra code required, not exactly worth it
+				try { // as of IE8, getters/setters are supported only on DOM elements
+					var obj = {};
+					if (Object.defineProperty) {
+						Object.defineProperty(obj, 'prop', {
+							enumerable: true,
+							configurable: true
+						});
+						return true;
+					}
+				} catch(ex) {}
+
+				if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
+					return true;
+				}*/
+				return false;
+			}()),
+
+			create_canvas: function() {
+				// On the S60 and BB Storm, getContext exists, but always returns undefined
+				// so we actually have to call getContext() to verify
+				// github.com/Modernizr/Modernizr/issues/issue/97/
+				var el = document.createElement('canvas');
+				var isSupported = !!(el.getContext && el.getContext('2d'));
+				caps.create_canvas = isSupported;
+				return isSupported;
+			},
+
+			return_response_type: function(responseType) {
+				try {
+					if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {
+						return true;
+					} else if (window.XMLHttpRequest) {
+						var xhr = new XMLHttpRequest();
+						xhr.open('get', '/'); // otherwise Gecko throws an exception
+						if ('responseType' in xhr) {
+							xhr.responseType = responseType;
+							// as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?)
+							if (xhr.responseType !== responseType) {
+								return false;
+							}
+							return true;
+						}
+					}
+				} catch (ex) {}
+				return false;
+			},
+
+			use_blob_uri: function() {
+				var URL = window.URL;
+				caps.use_blob_uri = (URL &&
+					'createObjectURL' in URL &&
+					'revokeObjectURL' in URL &&
+					(Env.browser !== 'IE' || Env.verComp(Env.version, '11.0.46', '>=')) // IE supports createObjectURL, but not fully, for example it fails to use it as a src for the image
+				);
+				return caps.use_blob_uri;
+			},
+
+			// ideas for this heavily come from Modernizr (http://modernizr.com/)
+			use_data_uri: (function() {
+				var du = new Image();
+
+				du.onload = function() {
+					caps.use_data_uri = (du.width === 1 && du.height === 1);
+				};
+
+				setTimeout(function() {
+					du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
+				}, 1);
+				return false;
+			}()),
+
+			use_data_uri_over32kb: function() { // IE8
+				return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9);
+			},
+
+			use_data_uri_of: function(bytes) {
+				return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb());
+			},
+
+			use_fileinput: function() {
+				if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) {
+					return false;
+				}
+
+				var el = document.createElement('input');
+				el.setAttribute('type', 'file');
+				return caps.use_fileinput = !el.disabled;
+			},
+
+			use_webgl: function() {
+				var canvas = document.createElement('canvas');
+				var gl = null, isSupported;
+				try {
+					gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+				}
+				catch(e) {}
+
+				if (!gl) { // it seems that sometimes it doesn't throw exception, but still fails to get context
+					gl = null;
+				}
+
+				isSupported = !!gl;
+				caps.use_webgl = isSupported; // save result of our check
+				canvas = undefined;
+				return isSupported;
+			}
+		};
+
+		return function(cap) {
+			var args = [].slice.call(arguments);
+			args.shift(); // shift of cap
+			return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap];
+		};
+	}());
+
+
+	var uaResult = new UAParser().getResult();
+
+
+	var Env = {
+		can: can,
+
+		uaParser: UAParser,
+
+		browser: uaResult.browser.name,
+		version: uaResult.browser.version,
+		os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason
+		osVersion: uaResult.os.version,
+
+		verComp: version_compare,
+
+		swf_url: "../flash/Moxie.swf",
+		xap_url: "../silverlight/Moxie.xap",
+		global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent"
+	};
+
+	// for backward compatibility
+	// @deprecated Use `Env.os` instead
+	Env.OS = Env.os;
+
+	if (MXI_DEBUG) {
+		Env.debug = {
+			runtime: true,
+			events: false
+		};
+
+		Env.log = function() {
+
+			function logObj(data) {
+				// TODO: this should recursively print out the object in a pretty way
+				console.appendChild(document.createTextNode(data + "\n"));
+			}
+
+			// if debugger present, IE8 might have window.console.log method, but not be able to apply on it (why...)
+			if (window && window.console && window.console.log && window.console.log.apply) {
+				window.console.log.apply(window.console, arguments);
+			} else if (document) {
+				var console = document.getElementById('moxie-console');
+				if (!console) {
+					console = document.createElement('pre');
+					console.id = 'moxie-console';
+					//console.style.display = 'none';
+					document.body.appendChild(console);
+				}
+
+				var data = arguments[0];
+				if (Basic.typeOf(data) === 'string') {
+					data = Basic.sprintf.apply(this, arguments);
+				} else if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) {
+					logObj(data);
+					return;
+				}
+
+				console.appendChild(document.createTextNode(data + "\n"));
+			}
+		};
+	}
+
+	return Env;
+});
+
+// Included from: src/javascript/core/Exceptions.js
+
+/**
+ * Exceptions.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/core/Exceptions', [
+	'moxie/core/utils/Basic'
+], function(Basic) {
+	
+	function _findKey(obj, value) {
+		var key;
+		for (key in obj) {
+			if (obj[key] === value) {
+				return key;
+			}
+		}
+		return null;
+	}
+
+	/**
+	@class moxie/core/Exception
+	*/
+	return {
+		RuntimeError: (function() {
+			var namecodes = {
+				NOT_INIT_ERR: 1,
+				EXCEPTION_ERR: 3,
+				NOT_SUPPORTED_ERR: 9,
+				JS_ERR: 4
+			};
+
+			function RuntimeError(code, message) {
+				this.code = code;
+				this.name = _findKey(namecodes, code);
+				this.message = this.name + (message || ": RuntimeError " + this.code);
+			}
+			
+			Basic.extend(RuntimeError, namecodes);
+			RuntimeError.prototype = Error.prototype;
+			return RuntimeError;
+		}()),
+		
+		OperationNotAllowedException: (function() {
+			
+			function OperationNotAllowedException(code) {
+				this.code = code;
+				this.name = 'OperationNotAllowedException';
+			}
+			
+			Basic.extend(OperationNotAllowedException, {
+				NOT_ALLOWED_ERR: 1
+			});
+			
+			OperationNotAllowedException.prototype = Error.prototype;
+			
+			return OperationNotAllowedException;
+		}()),
+
+		ImageError: (function() {
+			var namecodes = {
+				WRONG_FORMAT: 1,
+				MAX_RESOLUTION_ERR: 2,
+				INVALID_META_ERR: 3
+			};
+
+			function ImageError(code) {
+				this.code = code;
+				this.name = _findKey(namecodes, code);
+				this.message = this.name + ": ImageError " + this.code;
+			}
+			
+			Basic.extend(ImageError, namecodes);
+			ImageError.prototype = Error.prototype;
+
+			return ImageError;
+		}()),
+
+		FileException: (function() {
+			var namecodes = {
+				NOT_FOUND_ERR: 1,
+				SECURITY_ERR: 2,
+				ABORT_ERR: 3,
+				NOT_READABLE_ERR: 4,
+				ENCODING_ERR: 5,
+				NO_MODIFICATION_ALLOWED_ERR: 6,
+				INVALID_STATE_ERR: 7,
+				SYNTAX_ERR: 8
+			};
+
+			function FileException(code) {
+				this.code = code;
+				this.name = _findKey(namecodes, code);
+				this.message = this.name + ": FileException " + this.code;
+			}
+			
+			Basic.extend(FileException, namecodes);
+			FileException.prototype = Error.prototype;
+			return FileException;
+		}()),
+		
+		DOMException: (function() {
+			var namecodes = {
+				INDEX_SIZE_ERR: 1,
+				DOMSTRING_SIZE_ERR: 2,
+				HIERARCHY_REQUEST_ERR: 3,
+				WRONG_DOCUMENT_ERR: 4,
+				INVALID_CHARACTER_ERR: 5,
+				NO_DATA_ALLOWED_ERR: 6,
+				NO_MODIFICATION_ALLOWED_ERR: 7,
+				NOT_FOUND_ERR: 8,
+				NOT_SUPPORTED_ERR: 9,
+				INUSE_ATTRIBUTE_ERR: 10,
+				INVALID_STATE_ERR: 11,
+				SYNTAX_ERR: 12,
+				INVALID_MODIFICATION_ERR: 13,
+				NAMESPACE_ERR: 14,
+				INVALID_ACCESS_ERR: 15,
+				VALIDATION_ERR: 16,
+				TYPE_MISMATCH_ERR: 17,
+				SECURITY_ERR: 18,
+				NETWORK_ERR: 19,
+				ABORT_ERR: 20,
+				URL_MISMATCH_ERR: 21,
+				QUOTA_EXCEEDED_ERR: 22,
+				TIMEOUT_ERR: 23,
+				INVALID_NODE_TYPE_ERR: 24,
+				DATA_CLONE_ERR: 25
+			};
+
+			function DOMException(code) {
+				this.code = code;
+				this.name = _findKey(namecodes, code);
+				this.message = this.name + ": DOMException " + this.code;
+			}
+			
+			Basic.extend(DOMException, namecodes);
+			DOMException.prototype = Error.prototype;
+			return DOMException;
+		}()),
+		
+		EventException: (function() {
+			function EventException(code) {
+				this.code = code;
+				this.name = 'EventException';
+			}
+			
+			Basic.extend(EventException, {
+				UNSPECIFIED_EVENT_TYPE_ERR: 0
+			});
+			
+			EventException.prototype = Error.prototype;
+			
+			return EventException;
+		}())
+	};
+});
+
+// Included from: src/javascript/core/utils/Dom.js
+
+/**
+ * Dom.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Dom
+@public
+@static
+*/
+
+define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
+
+	/**
+	Get DOM Element by it's id.
+
+	@method get
+	@param {String} id Identifier of the DOM Element
+	@return {DOMElement}
+	*/
+	var get = function(id) {
+		if (typeof id !== 'string') {
+			return id;
+		}
+		return document.getElementById(id);
+	};
+
+	/**
+	Checks if specified DOM element has specified class.
+
+	@method hasClass
+	@static
+	@param {Object} obj DOM element like object to add handler to.
+	@param {String} name Class name
+	*/
+	var hasClass = function(obj, name) {
+		if (!obj.className) {
+			return false;
+		}
+
+		var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
+		return regExp.test(obj.className);
+	};
+
+	/**
+	Adds specified className to specified DOM element.
+
+	@method addClass
+	@static
+	@param {Object} obj DOM element like object to add handler to.
+	@param {String} name Class name
+	*/
+	var addClass = function(obj, name) {
+		if (!hasClass(obj, name)) {
+			obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name;
+		}
+	};
+
+	/**
+	Removes specified className from specified DOM element.
+
+	@method removeClass
+	@static
+	@param {Object} obj DOM element like object to add handler to.
+	@param {String} name Class name
+	*/
+	var removeClass = function(obj, name) {
+		if (obj.className) {
+			var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
+			obj.className = obj.className.replace(regExp, function($0, $1, $2) {
+				return $1 === ' ' && $2 === ' ' ? ' ' : '';
+			});
+		}
+	};
+
+	/**
+	Returns a given computed style of a DOM element.
+
+	@method getStyle
+	@static
+	@param {Object} obj DOM element like object.
+	@param {String} name Style you want to get from the DOM element
+	*/
+	var getStyle = function(obj, name) {
+		if (obj.currentStyle) {
+			return obj.currentStyle[name];
+		} else if (window.getComputedStyle) {
+			return window.getComputedStyle(obj, null)[name];
+		}
+	};
+
+
+	/**
+	Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
+
+	@method getPos
+	@static
+	@param {Element} node HTML element or element id to get x, y position from.
+	@param {Element} root Optional root element to stop calculations at.
+	@return {object} Absolute position of the specified element object with x, y fields.
+	*/
+	var getPos = function(node, root) {
+		var x = 0, y = 0, parent, doc = document, nodeRect, rootRect;
+
+		node = node;
+		root = root || doc.body;
+
+		// Returns the x, y cordinate for an element on IE 6 and IE 7
+		function getIEPos(node) {
+			var bodyElm, rect, x = 0, y = 0;
+
+			if (node) {
+				rect = node.getBoundingClientRect();
+				bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body;
+				x = rect.left + bodyElm.scrollLeft;
+				y = rect.top + bodyElm.scrollTop;
+			}
+
+			return {
+				x : x,
+				y : y
+			};
+		}
+
+		// Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode
+		if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) {
+			nodeRect = getIEPos(node);
+			rootRect = getIEPos(root);
+
+			return {
+				x : nodeRect.x - rootRect.x,
+				y : nodeRect.y - rootRect.y
+			};
+		}
+
+		parent = node;
+		while (parent && parent != root && parent.nodeType) {
+			x += parent.offsetLeft || 0;
+			y += parent.offsetTop || 0;
+			parent = parent.offsetParent;
+		}
+
+		parent = node.parentNode;
+		while (parent && parent != root && parent.nodeType) {
+			x -= parent.scrollLeft || 0;
+			y -= parent.scrollTop || 0;
+			parent = parent.parentNode;
+		}
+
+		return {
+			x : x,
+			y : y
+		};
+	};
+
+	/**
+	Returns the size of the specified node in pixels.
+
+	@method getSize
+	@static
+	@param {Node} node Node to get the size of.
+	@return {Object} Object with a w and h property.
+	*/
+	var getSize = function(node) {
+		return {
+			w : node.offsetWidth || node.clientWidth,
+			h : node.offsetHeight || node.clientHeight
+		};
+	};
+
+	return {
+		get: get,
+		hasClass: hasClass,
+		addClass: addClass,
+		removeClass: removeClass,
+		getStyle: getStyle,
+		getPos: getPos,
+		getSize: getSize
+	};
+});
+
+// Included from: src/javascript/core/EventTarget.js
+
+/**
+ * EventTarget.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/core/EventTarget', [
+	'moxie/core/utils/Env',
+	'moxie/core/Exceptions',
+	'moxie/core/utils/Basic'
+], function(Env, x, Basic) {
+
+	// hash of event listeners by object uid
+	var eventpool = {};
+
+	/**
+	Parent object for all event dispatching components and objects
+
+	@class moxie/core/EventTarget
+	@constructor EventTarget
+	*/
+	function EventTarget() {
+		/**
+		Unique id of the event dispatcher, usually overriden by children
+
+		@property uid
+		@type String
+		*/
+		this.uid = Basic.guid();
+	}
+
+
+	Basic.extend(EventTarget.prototype, {
+
+		/**
+		Can be called from within a child  in order to acquire uniqie id in automated manner
+
+		@method init
+		*/
+		init: function() {
+			if (!this.uid) {
+				this.uid = Basic.guid('uid_');
+			}
+		},
+
+		/**
+		Register a handler to a specific event dispatched by the object
+
+		@method addEventListener
+		@param {String} type Type or basically a name of the event to subscribe to
+		@param {Function} fn Callback function that will be called when event happens
+		@param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
+		@param {Object} [scope=this] A scope to invoke event handler in
+		*/
+		addEventListener: function(type, fn, priority, scope) {
+			var self = this, list;
+
+			// without uid no event handlers can be added, so make sure we got one
+			if (!this.hasOwnProperty('uid')) {
+				this.uid = Basic.guid('uid_');
+			}
+
+			type = Basic.trim(type);
+
+			if (/\s/.test(type)) {
+				// multiple event types were passed for one handler
+				Basic.each(type.split(/\s+/), function(type) {
+					self.addEventListener(type, fn, priority, scope);
+				});
+				return;
+			}
+
+			type = type.toLowerCase();
+			priority = parseInt(priority, 10) || 0;
+
+			list = eventpool[this.uid] && eventpool[this.uid][type] || [];
+			list.push({fn : fn, priority : priority, scope : scope || this});
+
+			if (!eventpool[this.uid]) {
+				eventpool[this.uid] = {};
+			}
+			eventpool[this.uid][type] = list;
+		},
+
+		/**
+		Check if any handlers were registered to the specified event
+
+		@method hasEventListener
+		@param {String} [type] Type or basically a name of the event to check
+		@return {Mixed} Returns a handler if it was found and false, if - not
+		*/
+		hasEventListener: function(type) {
+			var list;
+			if (type) {
+				type = type.toLowerCase();
+				list = eventpool[this.uid] && eventpool[this.uid][type];
+			} else {
+				list = eventpool[this.uid];
+			}
+			return list ? list : false;
+		},
+
+		/**
+		Unregister the handler from the event, or if former was not specified - unregister all handlers
+
+		@method removeEventListener
+		@param {String} type Type or basically a name of the event
+		@param {Function} [fn] Handler to unregister
+		*/
+		removeEventListener: function(type, fn) {
+			var self = this, list, i;
+
+			type = type.toLowerCase();
+
+			if (/\s/.test(type)) {
+				// multiple event types were passed for one handler
+				Basic.each(type.split(/\s+/), function(type) {
+					self.removeEventListener(type, fn);
+				});
+				return;
+			}
+
+			list = eventpool[this.uid] && eventpool[this.uid][type];
+
+			if (list) {
+				if (fn) {
+					for (i = list.length - 1; i >= 0; i--) {
+						if (list[i].fn === fn) {
+							list.splice(i, 1);
+							break;
+						}
+					}
+				} else {
+					list = [];
+				}
+
+				// delete event list if it has become empty
+				if (!list.length) {
+					delete eventpool[this.uid][type];
+
+					// and object specific entry in a hash if it has no more listeners attached
+					if (Basic.isEmptyObj(eventpool[this.uid])) {
+						delete eventpool[this.uid];
+					}
+				}
+			}
+		},
+
+		/**
+		Remove all event handlers from the object
+
+		@method removeAllEventListeners
+		*/
+		removeAllEventListeners: function() {
+			if (eventpool[this.uid]) {
+				delete eventpool[this.uid];
+			}
+		},
+
+		/**
+		Dispatch the event
+
+		@method dispatchEvent
+		@param {String/Object} Type of event or event object to dispatch
+		@param {Mixed} [...] Variable number of arguments to be passed to a handlers
+		@return {Boolean} true by default and false if any handler returned false
+		*/
+		dispatchEvent: function(type) {
+			var uid, list, args, tmpEvt, evt = {}, result = true, undef;
+
+			if (Basic.typeOf(type) !== 'string') {
+				// we can't use original object directly (because of Silverlight)
+				tmpEvt = type;
+
+				if (Basic.typeOf(tmpEvt.type) === 'string') {
+					type = tmpEvt.type;
+
+					if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event
+						evt.total = tmpEvt.total;
+						evt.loaded = tmpEvt.loaded;
+					}
+					evt.async = tmpEvt.async || false;
+				} else {
+					throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR);
+				}
+			}
+
+			// check if event is meant to be dispatched on an object having specific uid
+			if (type.indexOf('::') !== -1) {
+				(function(arr) {
+					uid = arr[0];
+					type = arr[1];
+				}(type.split('::')));
+			} else {
+				uid = this.uid;
+			}
+
+			type = type.toLowerCase();
+
+			list = eventpool[uid] && eventpool[uid][type];
+
+			if (list) {
+				// sort event list by prority
+				list.sort(function(a, b) { return b.priority - a.priority; });
+
+				args = [].slice.call(arguments);
+
+				// first argument will be pseudo-event object
+				args.shift();
+				evt.type = type;
+				args.unshift(evt);
+
+				if (MXI_DEBUG && Env.debug.events) {
+					Env.log("%cEvent '%s' fired on %s", 'color: #999;', evt.type, (this.ctorName ? this.ctorName + '::' : '') + uid);
+				}
+
+				// Dispatch event to all listeners
+				var queue = [];
+				Basic.each(list, function(handler) {
+					// explicitly set the target, otherwise events fired from shims do not get it
+					args[0].target = handler.scope;
+					// if event is marked as async, detach the handler
+					if (evt.async) {
+						queue.push(function(cb) {
+							setTimeout(function() {
+								cb(handler.fn.apply(handler.scope, args) === false);
+							}, 1);
+						});
+					} else {
+						queue.push(function(cb) {
+							cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation
+						});
+					}
+				});
+				if (queue.length) {
+					Basic.inSeries(queue, function(err) {
+						result = !err;
+					});
+				}
+			}
+			return result;
+		},
+
+		/**
+		Register a handler to the event type that will run only once
+
+		@method bindOnce
+		@since >1.4.1
+		@param {String} type Type or basically a name of the event to subscribe to
+		@param {Function} fn Callback function that will be called when event happens
+		@param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
+		@param {Object} [scope=this] A scope to invoke event handler in
+		*/
+		bindOnce: function(type, fn, priority, scope) {
+			var self = this;
+			self.bind.call(this, type, function cb() {
+				self.unbind(type, cb);
+				return fn.apply(this, arguments);
+			}, priority, scope);
+		},
+
+		/**
+		Alias for addEventListener
+
+		@method bind
+		@protected
+		*/
+		bind: function() {
+			this.addEventListener.apply(this, arguments);
+		},
+
+		/**
+		Alias for removeEventListener
+
+		@method unbind
+		@protected
+		*/
+		unbind: function() {
+			this.removeEventListener.apply(this, arguments);
+		},
+
+		/**
+		Alias for removeAllEventListeners
+
+		@method unbindAll
+		@protected
+		*/
+		unbindAll: function() {
+			this.removeAllEventListeners.apply(this, arguments);
+		},
+
+		/**
+		Alias for dispatchEvent
+
+		@method trigger
+		@protected
+		*/
+		trigger: function() {
+			return this.dispatchEvent.apply(this, arguments);
+		},
+
+
+		/**
+		Handle properties of on[event] type.
+
+		@method handleEventProps
+		@private
+		*/
+		handleEventProps: function(dispatches) {
+			var self = this;
+
+			this.bind(dispatches.join(' '), function(e) {
+				var prop = 'on' + e.type.toLowerCase();
+				if (Basic.typeOf(this[prop]) === 'function') {
+					this[prop].apply(this, arguments);
+				}
+			});
+
+			// object must have defined event properties, even if it doesn't make use of them
+			Basic.each(dispatches, function(prop) {
+				prop = 'on' + prop.toLowerCase(prop);
+				if (Basic.typeOf(self[prop]) === 'undefined') {
+					self[prop] = null;
+				}
+			});
+		}
+
+	});
+
+
+	EventTarget.instance = new EventTarget();
+
+	return EventTarget;
+});
+
+// Included from: src/javascript/runtime/Runtime.js
+
+/**
+ * Runtime.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/runtime/Runtime', [
+	"moxie/core/utils/Env",
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Dom",
+	"moxie/core/EventTarget"
+], function(Env, Basic, Dom, EventTarget) {
+	var runtimeConstructors = {}, runtimes = {};
+
+	/**
+	Common set of methods and properties for every runtime instance
+
+	@class moxie/runtime/Runtime
+
+	@param {Object} options
+	@param {String} type Sanitized name of the runtime
+	@param {Object} [caps] Set of capabilities that differentiate specified runtime
+	@param {Object} [modeCaps] Set of capabilities that do require specific operational mode
+	@param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested
+	*/
+	function Runtime(options, type, caps, modeCaps, preferredMode) {
+		/**
+		Dispatched when runtime is initialized and ready.
+		Results in RuntimeInit on a connected component.
+
+		@event Init
+		*/
+
+		/**
+		Dispatched when runtime fails to initialize.
+		Results in RuntimeError on a connected component.
+
+		@event Error
+		*/
+
+		var self = this
+		, _shim
+		, _uid = Basic.guid(type + '_')
+		, defaultMode = preferredMode || 'browser'
+		;
+
+		options = options || {};
+
+		// register runtime in private hash
+		runtimes[_uid] = this;
+
+		/**
+		Default set of capabilities, which can be redifined later by specific runtime
+
+		@private
+		@property caps
+		@type Object
+		*/
+		caps = Basic.extend({
+			// Runtime can: 
+			// provide access to raw binary data of the file
+			access_binary: false,
+			// provide access to raw binary data of the image (image extension is optional) 
+			access_image_binary: false,
+			// display binary data as thumbs for example
+			display_media: false,
+			// make cross-domain requests
+			do_cors: false,
+			// accept files dragged and dropped from the desktop
+			drag_and_drop: false,
+			// filter files in selection dialog by their extensions
+			filter_by_extension: true,
+			// resize image (and manipulate it raw data of any file in general)
+			resize_image: false,
+			// periodically report how many bytes of total in the file were uploaded (loaded)
+			report_upload_progress: false,
+			// provide access to the headers of http response 
+			return_response_headers: false,
+			// support response of specific type, which should be passed as an argument
+			// e.g. runtime.can('return_response_type', 'blob')
+			return_response_type: false,
+			// return http status code of the response
+			return_status_code: true,
+			// send custom http header with the request
+			send_custom_headers: false,
+			// pick up the files from a dialog
+			select_file: false,
+			// select whole folder in file browse dialog
+			select_folder: false,
+			// select multiple files at once in file browse dialog
+			select_multiple: true,
+			// send raw binary data, that is generated after image resizing or manipulation of other kind
+			send_binary_string: false,
+			// send cookies with http request and therefore retain session
+			send_browser_cookies: true,
+			// send data formatted as multipart/form-data
+			send_multipart: true,
+			// slice the file or blob to smaller parts
+			slice_blob: false,
+			// upload file without preloading it to memory, stream it out directly from disk
+			stream_upload: false,
+			// programmatically trigger file browse dialog
+			summon_file_dialog: false,
+			// upload file of specific size, size should be passed as argument
+			// e.g. runtime.can('upload_filesize', '500mb')
+			upload_filesize: true,
+			// initiate http request with specific http method, method should be passed as argument
+			// e.g. runtime.can('use_http_method', 'put')
+			use_http_method: true
+		}, caps);
+			
+	
+		// default to the mode that is compatible with preferred caps
+		if (options.preferred_caps) {
+			defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode);
+		}
+
+		if (MXI_DEBUG && Env.debug.runtime) {
+			Env.log("\tdefault mode: %s", defaultMode);	
+		}
+		
+		// small extension factory here (is meant to be extended with actual extensions constructors)
+		_shim = (function() {
+			var objpool = {};
+			return {
+				exec: function(uid, comp, fn, args) {
+					if (_shim[comp]) {
+						if (!objpool[uid]) {
+							objpool[uid] = {
+								context: this,
+								instance: new _shim[comp]()
+							};
+						}
+						if (objpool[uid].instance[fn]) {
+							return objpool[uid].instance[fn].apply(this, args);
+						}
+					}
+				},
+
+				removeInstance: function(uid) {
+					delete objpool[uid];
+				},
+
+				removeAllInstances: function() {
+					var self = this;
+					Basic.each(objpool, function(obj, uid) {
+						if (Basic.typeOf(obj.instance.destroy) === 'function') {
+							obj.instance.destroy.call(obj.context);
+						}
+						self.removeInstance(uid);
+					});
+				}
+			};
+		}());
+
+
+		// public methods
+		Basic.extend(this, {
+			/**
+			Specifies whether runtime instance was initialized or not
+
+			@property initialized
+			@type {Boolean}
+			@default false
+			*/
+			initialized: false, // shims require this flag to stop initialization retries
+
+			/**
+			Unique ID of the runtime
+
+			@property uid
+			@type {String}
+			*/
+			uid: _uid,
+
+			/**
+			Runtime type (e.g. flash, html5, etc)
+
+			@property type
+			@type {String}
+			*/
+			type: type,
+
+			/**
+			Runtime (not native one) may operate in browser or client mode.
+
+			@property mode
+			@private
+			@type {String|Boolean} current mode or false, if none possible
+			*/
+			mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode),
+
+			/**
+			id of the DOM container for the runtime (if available)
+
+			@property shimid
+			@type {String}
+			*/
+			shimid: _uid + '_container',
+
+			/**
+			Number of connected clients. If equal to zero, runtime can be destroyed
+
+			@property clients
+			@type {Number}
+			*/
+			clients: 0,
+
+			/**
+			Runtime initialization options
+
+			@property options
+			@type {Object}
+			*/
+			options: options,
+
+			/**
+			Checks if the runtime has specific capability
+
+			@method can
+			@param {String} cap Name of capability to check
+			@param {Mixed} [value] If passed, capability should somehow correlate to the value
+			@param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set)
+			@return {Boolean} true if runtime has such capability and false, if - not
+			*/
+			can: function(cap, value) {
+				var refCaps = arguments[2] || caps;
+
+				// if cap var is a comma-separated list of caps, convert it to object (key/value)
+				if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') {
+					cap = Runtime.parseCaps(cap);
+				}
+
+				if (Basic.typeOf(cap) === 'object') {
+					for (var key in cap) {
+						if (!this.can(key, cap[key], refCaps)) {
+							return false;
+						}
+					}
+					return true;
+				}
+
+				// check the individual cap
+				if (Basic.typeOf(refCaps[cap]) === 'function') {
+					return refCaps[cap].call(this, value);
+				} else {
+					return (value === refCaps[cap]);
+				}
+			},
+
+			/**
+			Returns container for the runtime as DOM element
+
+			@method getShimContainer
+			@return {DOMElement}
+			*/
+			getShimContainer: function() {
+				var container, shimContainer = Dom.get(this.shimid);
+
+				// if no container for shim, create one
+				if (!shimContainer) {
+					container = Dom.get(this.options.container) || document.body;
+
+					// create shim container and insert it at an absolute position into the outer container
+					shimContainer = document.createElement('div');
+					shimContainer.id = this.shimid;
+					shimContainer.className = 'moxie-shim moxie-shim-' + this.type;
+
+					Basic.extend(shimContainer.style, {
+						position: 'absolute',
+						top: '0px',
+						left: '0px',
+						width: '1px',
+						height: '1px',
+						overflow: 'hidden'
+					});
+
+					container.appendChild(shimContainer);
+					container = null;
+				}
+
+				return shimContainer;
+			},
+
+			/**
+			Returns runtime as DOM element (if appropriate)
+
+			@method getShim
+			@return {DOMElement}
+			*/
+			getShim: function() {
+				return _shim;
+			},
+
+			/**
+			Invokes a method within the runtime itself (might differ across the runtimes)
+
+			@method shimExec
+			@param {Mixed} []
+			@protected
+			@return {Mixed} Depends on the action and component
+			*/
+			shimExec: function(component, action) {
+				var args = [].slice.call(arguments, 2);
+				return self.getShim().exec.call(this, this.uid, component, action, args);
+			},
+
+			/**
+			Operaional interface that is used by components to invoke specific actions on the runtime
+			(is invoked in the scope of component)
+
+			@method exec
+			@param {Mixed} []*
+			@protected
+			@return {Mixed} Depends on the action and component
+			*/
+			exec: function(component, action) { // this is called in the context of component, not runtime
+				var args = [].slice.call(arguments, 2);
+
+				if (self[component] && self[component][action]) {
+					return self[component][action].apply(this, args);
+				}
+				return self.shimExec.apply(this, arguments);
+			},
+
+			/**
+			Destroys the runtime (removes all events and deletes DOM structures)
+
+			@method destroy
+			*/
+			destroy: function() {
+				if (!self) {
+					return; // obviously already destroyed
+				}
+
+				var shimContainer = Dom.get(this.shimid);
+				if (shimContainer) {
+					shimContainer.parentNode.removeChild(shimContainer);
+				}
+
+				if (_shim) {
+					_shim.removeAllInstances();
+				}
+
+				this.unbindAll();
+				delete runtimes[this.uid];
+				this.uid = null; // mark this runtime as destroyed
+				_uid = self = _shim = shimContainer = null;
+			}
+		});
+
+		// once we got the mode, test against all caps
+		if (this.mode && options.required_caps && !this.can(options.required_caps)) {
+			this.mode = false;
+		}	
+	}
+
+
+	/**
+	Default order to try different runtime types
+
+	@property order
+	@type String
+	@static
+	*/
+	Runtime.order = 'html5,flash,silverlight,html4';
+
+
+	/**
+	Retrieves runtime from private hash by it's uid
+
+	@method getRuntime
+	@private
+	@static
+	@param {String} uid Unique identifier of the runtime
+	@return {Runtime|Boolean} Returns runtime, if it exists and false, if - not
+	*/
+	Runtime.getRuntime = function(uid) {
+		return runtimes[uid] ? runtimes[uid] : false;
+	};
+
+
+	/**
+	Register constructor for the Runtime of new (or perhaps modified) type
+
+	@method addConstructor
+	@static
+	@param {String} type Runtime type (e.g. flash, html5, etc)
+	@param {Function} construct Constructor for the Runtime type
+	*/
+	Runtime.addConstructor = function(type, constructor) {
+		constructor.prototype = EventTarget.instance;
+		runtimeConstructors[type] = constructor;
+	};
+
+
+	/**
+	Get the constructor for the specified type.
+
+	method getConstructor
+	@static
+	@param {String} type Runtime type (e.g. flash, html5, etc)
+	@return {Function} Constructor for the Runtime type
+	*/
+	Runtime.getConstructor = function(type) {
+		return runtimeConstructors[type] || null;
+	};
+
+
+	/**
+	Get info about the runtime (uid, type, capabilities)
+
+	@method getInfo
+	@static
+	@param {String} uid Unique identifier of the runtime
+	@return {Mixed} Info object or null if runtime doesn't exist
+	*/
+	Runtime.getInfo = function(uid) {
+		var runtime = Runtime.getRuntime(uid);
+
+		if (runtime) {
+			return {
+				uid: runtime.uid,
+				type: runtime.type,
+				mode: runtime.mode,
+				can: function() {
+					return runtime.can.apply(runtime, arguments);
+				}
+			};
+		}
+		return null;
+	};
+
+
+	/**
+	Convert caps represented by a comma-separated string to the object representation.
+
+	@method parseCaps
+	@static
+	@param {String} capStr Comma-separated list of capabilities
+	@return {Object}
+	*/
+	Runtime.parseCaps = function(capStr) {
+		var capObj = {};
+
+		if (Basic.typeOf(capStr) !== 'string') {
+			return capStr || {};
+		}
+
+		Basic.each(capStr.split(','), function(key) {
+			capObj[key] = true; // we assume it to be - true
+		});
+
+		return capObj;
+	};
+
+	/**
+	Test the specified runtime for specific capabilities.
+
+	@method can
+	@static
+	@param {String} type Runtime type (e.g. flash, html5, etc)
+	@param {String|Object} caps Set of capabilities to check
+	@return {Boolean} Result of the test
+	*/
+	Runtime.can = function(type, caps) {
+		var runtime
+		, constructor = Runtime.getConstructor(type)
+		, mode
+		;
+		if (constructor) {
+			runtime = new constructor({
+				required_caps: caps
+			});
+			mode = runtime.mode;
+			runtime.destroy();
+			return !!mode;
+		}
+		return false;
+	};
+
+
+	/**
+	Figure out a runtime that supports specified capabilities.
+
+	@method thatCan
+	@static
+	@param {String|Object} caps Set of capabilities to check
+	@param {String} [runtimeOrder] Comma-separated list of runtimes to check against
+	@return {String} Usable runtime identifier or null
+	*/
+	Runtime.thatCan = function(caps, runtimeOrder) {
+		var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/);
+		for (var i in types) {
+			if (Runtime.can(types[i], caps)) {
+				return types[i];
+			}
+		}
+		return null;
+	};
+
+
+	/**
+	Figure out an operational mode for the specified set of capabilities.
+
+	@method getMode
+	@static
+	@param {Object} modeCaps Set of capabilities that depend on particular runtime mode
+	@param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for
+	@param {String|Boolean} [defaultMode='browser'] Default mode to use 
+	@return {String|Boolean} Compatible operational mode
+	*/
+	Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) {
+		var mode = null;
+
+		if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified
+			defaultMode = 'browser';
+		}
+
+		if (requiredCaps && !Basic.isEmptyObj(modeCaps)) {
+			// loop over required caps and check if they do require the same mode
+			Basic.each(requiredCaps, function(value, cap) {
+				if (modeCaps.hasOwnProperty(cap)) {
+					var capMode = modeCaps[cap](value);
+
+					// make sure we always have an array
+					if (typeof(capMode) === 'string') {
+						capMode = [capMode];
+					}
+					
+					if (!mode) {
+						mode = capMode;						
+					} else if (!(mode = Basic.arrayIntersect(mode, capMode))) {
+						// if cap requires conflicting mode - runtime cannot fulfill required caps
+
+						if (MXI_DEBUG && Env.debug.runtime) {
+							Env.log("\t\t%s: %s (conflicting mode requested: %s)", cap, value, capMode);
+						}
+
+						return (mode = false);
+					}					
+				}
+
+				if (MXI_DEBUG && Env.debug.runtime) {
+					Env.log("\t\t%s: %s (compatible modes: %s)", cap, value, mode);
+				}
+			});
+
+			if (mode) {
+				return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0];
+			} else if (mode === false) {
+				return false;
+			}
+		}
+		return defaultMode; 
+	};
+
+
+	/**
+	 * Third party shims (Flash and Silverlight) require global event target against which they
+	 * will fire their events. However when moxie is not loaded to global namespace, default
+	 * event target is not accessible and we have to create artificial ones.
+	 *
+	 * @method getGlobalEventTarget
+	 * @static
+	 * @return {String} Name of the global event target
+	 */
+	Runtime.getGlobalEventTarget = function() {
+		if (/^moxie\./.test(Env.global_event_dispatcher) && !Env.can('access_global_ns')) {
+			var uniqueCallbackName = Basic.guid('moxie_event_target_');
+
+			window[uniqueCallbackName] = function(e, data) {
+				EventTarget.instance.dispatchEvent(e, data);
+			};
+
+			Env.global_event_dispatcher = uniqueCallbackName;
+		}
+
+		return Env.global_event_dispatcher;
+	};
+
+
+	/**
+	Capability check that always returns true
+
+	@private
+	@static
+	@return {True}
+	*/
+	Runtime.capTrue = function() {
+		return true;
+	};
+
+	/**
+	Capability check that always returns false
+
+	@private
+	@static
+	@return {False}
+	*/
+	Runtime.capFalse = function() {
+		return false;
+	};
+
+	/**
+	Evaluate the expression to boolean value and create a function that always returns it.
+
+	@private
+	@static
+	@param {Mixed} expr Expression to evaluate
+	@return {Function} Function returning the result of evaluation
+	*/
+	Runtime.capTest = function(expr) {
+		return function() {
+			return !!expr;
+		};
+	};
+
+	return Runtime;
+});
+
+// Included from: src/javascript/runtime/RuntimeClient.js
+
+/**
+ * RuntimeClient.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/runtime/RuntimeClient', [
+	'moxie/core/utils/Env',
+	'moxie/core/Exceptions',
+	'moxie/core/utils/Basic',
+	'moxie/runtime/Runtime'
+], function(Env, x, Basic, Runtime) {
+	/**
+	Set of methods and properties, required by a component to acquire ability to connect to a runtime
+
+	@class moxie/runtime/RuntimeClient
+	*/
+	return function RuntimeClient() {
+		var runtime;
+
+		Basic.extend(this, {
+			/**
+			Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one.
+			Increments number of clients connected to the specified runtime.
+
+			@private
+			@method connectRuntime
+			@param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites
+			*/
+			connectRuntime: function(options) {
+				var comp = this, ruid;
+
+				function initialize(items) {
+					var type, constructor;
+
+					// if we ran out of runtimes
+					if (!items.length) {
+						comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
+						runtime = null;
+						return;
+					}
+
+					type = items.shift().toLowerCase();
+					constructor = Runtime.getConstructor(type);
+					if (!constructor) {
+						if (MXI_DEBUG && Env.debug.runtime) {
+							Env.log("Constructor for '%s' runtime is not available.", type);
+						}
+						initialize(items);
+						return;
+					}
+
+					if (MXI_DEBUG && Env.debug.runtime) {
+						Env.log("Trying runtime: %s", type);
+						Env.log(options);
+					}
+
+					// try initializing the runtime
+					runtime = new constructor(options);
+
+					runtime.bind('Init', function() {
+						// mark runtime as initialized
+						runtime.initialized = true;
+
+						if (MXI_DEBUG && Env.debug.runtime) {
+							Env.log("Runtime '%s' initialized", runtime.type);
+						}
+
+						// jailbreak ...
+						setTimeout(function() {
+							runtime.clients++;
+							comp.ruid = runtime.uid;
+							// this will be triggered on component
+							comp.trigger('RuntimeInit', runtime);
+						}, 1);
+					});
+
+					runtime.bind('Error', function() {
+						if (MXI_DEBUG && Env.debug.runtime) {
+							Env.log("Runtime '%s' failed to initialize", runtime.type);
+						}
+
+						runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here
+						initialize(items);
+					});
+
+					runtime.bind('Exception', function(e, err) {
+						var message = err.name + "(#" + err.code + ")" + (err.message ? ", from: " + err.message : '');
+						
+						if (MXI_DEBUG && Env.debug.runtime) {
+							Env.log("Runtime '%s' has thrown an exception: %s", this.type, message);
+						}
+						comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.EXCEPTION_ERR, message));
+					});
+
+					if (MXI_DEBUG && Env.debug.runtime) {
+						Env.log("\tselected mode: %s", runtime.mode);	
+					}
+
+					// check if runtime managed to pick-up operational mode
+					if (!runtime.mode) {
+						runtime.trigger('Error');
+						return;
+					}
+
+					runtime.init();
+				}
+
+				// check if a particular runtime was requested
+				if (Basic.typeOf(options) === 'string') {
+					ruid = options;
+				} else if (Basic.typeOf(options.ruid) === 'string') {
+					ruid = options.ruid;
+				}
+
+				if (ruid) {
+					runtime = Runtime.getRuntime(ruid);
+					if (runtime) {
+						comp.ruid = ruid;
+						runtime.clients++;
+						return runtime;
+					} else {
+						// there should be a runtime and there's none - weird case
+						throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR);
+					}
+				}
+
+				// initialize a fresh one, that fits runtime list and required features best
+				initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/));
+			},
+
+
+			/**
+			Disconnects from the runtime. Decrements number of clients connected to the specified runtime.
+
+			@private
+			@method disconnectRuntime
+			*/
+			disconnectRuntime: function() {
+				if (runtime && --runtime.clients <= 0) {
+					runtime.destroy();
+				}
+
+				// once the component is disconnected, it shouldn't have access to the runtime
+				runtime = null;
+			},
+
+
+			/**
+			Returns the runtime to which the client is currently connected.
+
+			@method getRuntime
+			@return {Runtime} Runtime or null if client is not connected
+			*/
+			getRuntime: function() {
+				if (runtime && runtime.uid) {
+					return runtime;
+				}
+				return runtime = null; // make sure we do not leave zombies rambling around
+			},
+
+
+			/**
+			Handy shortcut to safely invoke runtime extension methods.
+			
+			@private
+			@method exec
+			@return {Mixed} Whatever runtime extension method returns
+			*/
+			exec: function() {
+				return runtime ? runtime.exec.apply(this, arguments) : null;
+			},
+
+
+			/**
+			Test runtime client for specific capability
+			
+			@method can
+			@param {String} cap
+			@return {Bool}
+			*/
+			can: function(cap) {
+				return runtime ? runtime.can(cap) : false;
+			}
+
+		});
+	};
+
+
+});
+
+// Included from: src/javascript/file/Blob.js
+
+/**
+ * Blob.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/file/Blob', [
+	'moxie/core/utils/Basic',
+	'moxie/core/utils/Encode',
+	'moxie/runtime/RuntimeClient'
+], function(Basic, Encode, RuntimeClient) {
+	
+	var blobpool = {};
+
+	/**
+	@class moxie/file/Blob
+	@constructor
+	@param {String} ruid Unique id of the runtime, to which this blob belongs to
+	@param {Object} blob Object "Native" blob object, as it is represented in the runtime
+	*/
+	function Blob(ruid, blob) {
+
+		function _sliceDetached(start, end, type) {
+			var blob, data = blobpool[this.uid];
+
+			if (Basic.typeOf(data) !== 'string' || !data.length) {
+				return null; // or throw exception
+			}
+
+			blob = new Blob(null, {
+				type: type,
+				size: end - start
+			});
+			blob.detach(data.substr(start, blob.size));
+
+			return blob;
+		}
+
+		RuntimeClient.call(this);
+
+		if (ruid) {	
+			this.connectRuntime(ruid);
+		}
+
+		if (!blob) {
+			blob = {};
+		} else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string
+			blob = { data: blob };
+		}
+
+		Basic.extend(this, {
+			
+			/**
+			Unique id of the component
+
+			@property uid
+			@type {String}
+			*/
+			uid: blob.uid || Basic.guid('uid_'),
+			
+			/**
+			Unique id of the connected runtime, if falsy, then runtime will have to be initialized 
+			before this Blob can be used, modified or sent
+
+			@property ruid
+			@type {String}
+			*/
+			ruid: ruid,
+	
+			/**
+			Size of blob
+
+			@property size
+			@type {Number}
+			@default 0
+			*/
+			size: blob.size || 0,
+			
+			/**
+			Mime type of blob
+
+			@property type
+			@type {String}
+			@default ''
+			*/
+			type: blob.type || '',
+			
+			/**
+			@method slice
+			@param {Number} [start=0]
+			*/
+			slice: function(start, end, type) {		
+				if (this.isDetached()) {
+					return _sliceDetached.apply(this, arguments);
+				}
+				return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type);
+			},
+
+			/**
+			Returns "native" blob object (as it is represented in connected runtime) or null if not found
+
+			@method getSource
+			@return {Blob} Returns "native" blob object or null if not found
+			*/
+			getSource: function() {
+				if (!blobpool[this.uid]) {
+					return null;	
+				}
+				return blobpool[this.uid];
+			},
+
+			/** 
+			Detaches blob from any runtime that it depends on and initialize with standalone value
+
+			@method detach
+			@protected
+			@param {DOMString} [data=''] Standalone value
+			*/
+			detach: function(data) {
+				if (this.ruid) {
+					this.getRuntime().exec.call(this, 'Blob', 'destroy');
+					this.disconnectRuntime();
+					this.ruid = null;
+				}
+
+				data = data || '';
+
+				// if dataUrl, convert to binary string
+				if (data.substr(0, 5) == 'data:') {
+					var base64Offset = data.indexOf(';base64,');
+					this.type = data.substring(5, base64Offset);
+					data = Encode.atob(data.substring(base64Offset + 8));
+				}
+
+				this.size = data.length;
+
+				blobpool[this.uid] = data;
+			},
+
+			/**
+			Checks if blob is standalone (detached of any runtime)
+			
+			@method isDetached
+			@protected
+			@return {Boolean}
+			*/
+			isDetached: function() {
+				return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string';
+			},
+			
+			/** 
+			Destroy Blob and free any resources it was using
+
+			@method destroy
+			*/
+			destroy: function() {
+				this.detach();
+				delete blobpool[this.uid];
+			}
+		});
+
+		
+		if (blob.data) {
+			this.detach(blob.data); // auto-detach if payload has been passed
+		} else {
+			blobpool[this.uid] = blob;	
+		}
+	}
+	
+	return Blob;
+});
+
+// Included from: src/javascript/core/I18n.js
+
+/**
+ * I18n.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define("moxie/core/I18n", [
+	"moxie/core/utils/Basic"
+], function(Basic) {
+	var i18n = {};
+
+	/**
+	@class moxie/core/I18n
+	*/
+	return {
+		/**
+		 * Extends the language pack object with new items.
+		 *
+		 * @param {Object} pack Language pack items to add.
+		 * @return {Object} Extended language pack object.
+		 */
+		addI18n: function(pack) {
+			return Basic.extend(i18n, pack);
+		},
+
+		/**
+		 * Translates the specified string by checking for the english string in the language pack lookup.
+		 *
+		 * @param {String} str String to look for.
+		 * @return {String} Translated string or the input string if it wasn't found.
+		 */
+		translate: function(str) {
+			return i18n[str] || str;
+		},
+
+		/**
+		 * Shortcut for translate function
+		 *
+		 * @param {String} str String to look for.
+		 * @return {String} Translated string or the input string if it wasn't found.
+		 */
+		_: function(str) {
+			return this.translate(str);
+		},
+
+		/**
+		 * Pseudo sprintf implementation - simple way to replace tokens with specified values.
+		 *
+		 * @param {String} str String with tokens
+		 * @return {String} String with replaced tokens
+		 */
+		sprintf: function(str) {
+			var args = [].slice.call(arguments, 1);
+
+			return str.replace(/%[a-z]/g, function() {
+				var value = args.shift();
+				return Basic.typeOf(value) !== 'undefined' ? value : '';
+			});
+		}
+	};
+});
+
+// Included from: src/javascript/core/utils/Mime.js
+
+/**
+ * Mime.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Mime
+@public
+@static
+*/
+
+define("moxie/core/utils/Mime", [
+	"moxie/core/utils/Basic",
+	"moxie/core/I18n"
+], function(Basic, I18n) {
+
+	var mimeData = "" +
+		"application/msword,doc dot," +
+		"application/pdf,pdf," +
+		"application/pgp-signature,pgp," +
+		"application/postscript,ps ai eps," +
+		"application/rtf,rtf," +
+		"application/vnd.ms-excel,xls xlb xlt xla," +
+		"application/vnd.ms-powerpoint,ppt pps pot ppa," +
+		"application/zip,zip," +
+		"application/x-shockwave-flash,swf swfl," +
+		"application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
+		"application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
+		"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
+		"application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
+		"application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
+		"application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
+		"application/x-javascript,js," +
+		"application/json,json," +
+		"audio/mpeg,mp3 mpga mpega mp2," +
+		"audio/x-wav,wav," +
+		"audio/x-m4a,m4a," +
+		"audio/ogg,oga ogg," +
+		"audio/aiff,aiff aif," +
+		"audio/flac,flac," +
+		"audio/aac,aac," +
+		"audio/ac3,ac3," +
+		"audio/x-ms-wma,wma," +
+		"image/bmp,bmp," +
+		"image/gif,gif," +
+		"image/jpeg,jpg jpeg jpe," +
+		"image/photoshop,psd," +
+		"image/png,png," +
+		"image/svg+xml,svg svgz," +
+		"image/tiff,tiff tif," +
+		"text/plain,asc txt text diff log," +
+		"text/html,htm html xhtml," +
+		"text/css,css," +
+		"text/csv,csv," +
+		"text/rtf,rtf," +
+		"video/mpeg,mpeg mpg mpe m2v," +
+		"video/quicktime,qt mov," +
+		"video/mp4,mp4," +
+		"video/x-m4v,m4v," +
+		"video/x-flv,flv," +
+		"video/x-ms-wmv,wmv," +
+		"video/avi,avi," +
+		"video/webm,webm," +
+		"video/3gpp,3gpp 3gp," +
+		"video/3gpp2,3g2," +
+		"video/vnd.rn-realvideo,rv," +
+		"video/ogg,ogv," +
+		"video/x-matroska,mkv," +
+		"application/vnd.oasis.opendocument.formula-template,otf," +
+		"application/octet-stream,exe";
+
+
+	/**
+	 * Map of mimes to extensions
+	 *
+	 * @property mimes
+	 * @type {Object}
+	 */
+	var mimes = {};
+
+	/**
+	 * Map of extensions to mimes
+	 *
+	 * @property extensions
+	 * @type {Object}
+	 */
+	var extensions = {};
+
+
+	/**
+	* Parses mimeData string into a mimes and extensions lookup maps. String should have the
+	* following format:
+	*
+	* application/msword,doc dot,application/pdf,pdf, ...
+	*
+	* so mime-type followed by comma and followed by space-separated list of associated extensions,
+	* then comma again and then another mime-type, etc.
+	*
+	* If invoked externally will replace override internal lookup maps with user-provided data.
+	*
+	* @method addMimeType
+	* @param {String} mimeData
+	*/
+	var addMimeType = function (mimeData) {
+		var items = mimeData.split(/,/), i, ii, ext;
+
+		for (i = 0; i < items.length; i += 2) {
+			ext = items[i + 1].split(/ /);
+
+			// extension to mime lookup
+			for (ii = 0; ii < ext.length; ii++) {
+				mimes[ext[ii]] = items[i];
+			}
+			// mime to extension lookup
+			extensions[items[i]] = ext;
+		}
+	};
+
+
+	var extList2mimes = function (filters, addMissingExtensions) {
+		var ext, i, ii, type, mimes = [];
+
+		// convert extensions to mime types list
+		for (i = 0; i < filters.length; i++) {
+			ext = filters[i].extensions.toLowerCase().split(/\s*,\s*/);
+
+			for (ii = 0; ii < ext.length; ii++) {
+
+				// if there's an asterisk in the list, then accept attribute is not required
+				if (ext[ii] === '*') {
+					return [];
+				}
+
+				type = mimes[ext[ii]];
+
+				// future browsers should filter by extension, finally
+				if (addMissingExtensions && /^\w+$/.test(ext[ii])) {
+					mimes.push('.' + ext[ii]);
+				} else if (type && Basic.inArray(type, mimes) === -1) {
+					mimes.push(type);
+				} else if (!type) {
+					// if we have no type in our map, then accept all
+					return [];
+				}
+			}
+		}
+		return mimes;
+	};
+
+
+	var mimes2exts = function(mimes) {
+		var exts = [];
+
+		Basic.each(mimes, function(mime) {
+			mime = mime.toLowerCase();
+
+			if (mime === '*') {
+				exts = [];
+				return false;
+			}
+
+			// check if this thing looks like mime type
+			var m = mime.match(/^(\w+)\/(\*|\w+)$/);
+			if (m) {
+				if (m[2] === '*') {
+					// wildcard mime type detected
+					Basic.each(extensions, function(arr, mime) {
+						if ((new RegExp('^' + m[1] + '/')).test(mime)) {
+							[].push.apply(exts, extensions[mime]);
+						}
+					});
+				} else if (extensions[mime]) {
+					[].push.apply(exts, extensions[mime]);
+				}
+			}
+		});
+		return exts;
+	};
+
+
+	var mimes2extList = function(mimes) {
+		var accept = [], exts = [];
+
+		if (Basic.typeOf(mimes) === 'string') {
+			mimes = Basic.trim(mimes).split(/\s*,\s*/);
+		}
+
+		exts = mimes2exts(mimes);
+
+		accept.push({
+			title: I18n.translate('Files'),
+			extensions: exts.length ? exts.join(',') : '*'
+		});
+
+		return accept;
+	};
+
+	/**
+	 * Extract extension from the given filename
+	 *
+	 * @method getFileExtension
+	 * @param {String} fileName
+	 * @return {String} File extension
+	 */
+	var getFileExtension = function(fileName) {
+		var matches = fileName && fileName.match(/\.([^.]+)$/);
+		if (matches) {
+			return matches[1].toLowerCase();
+		}
+		return '';
+	};
+
+
+	/**
+	 * Get file mime-type from it's filename - will try to match the extension
+	 * against internal mime-type lookup map
+	 *
+	 * @method getFileMime
+	 * @param {String} fileName
+	 * @return File mime-type if found or an empty string if not
+	 */
+	var getFileMime = function(fileName) {
+		return mimes[getFileExtension(fileName)] || '';
+	};
+
+
+	addMimeType(mimeData);
+
+	return {
+		mimes: mimes,
+		extensions: extensions,
+		addMimeType: addMimeType,
+		extList2mimes: extList2mimes,
+		mimes2exts: mimes2exts,
+		mimes2extList: mimes2extList,
+		getFileExtension: getFileExtension,
+		getFileMime: getFileMime
+	}
+});
+
+// Included from: src/javascript/file/FileInput.js
+
+/**
+ * FileInput.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/file/FileInput', [
+	'moxie/core/utils/Basic',
+	'moxie/core/utils/Env',
+	'moxie/core/utils/Mime',
+	'moxie/core/utils/Dom',
+	'moxie/core/Exceptions',
+	'moxie/core/EventTarget',
+	'moxie/core/I18n',
+	'moxie/runtime/Runtime',
+	'moxie/runtime/RuntimeClient'
+], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) {
+	/**
+	Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click,
+	converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory
+	with _FileReader_ or uploaded to a server through _XMLHttpRequest_.
+
+	@class moxie/file/FileInput
+	@constructor
+	@extends EventTarget
+	@uses RuntimeClient
+	@param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_.
+		@param {String|DOMElement} options.browse_button DOM Element to turn into file picker.
+		@param {Array} [options.accept] Array of mime types to accept. By default accepts all.
+		@param {Boolean} [options.multiple=false] Enable selection of multiple files.
+		@param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time).
+		@param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode
+		for _browse\_button_.
+		@param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support.
+
+	@example
+		<div id="container">
+			<a id="file-picker" href="javascript:;">Browse...</a>
+		</div>
+
+		<script>
+			var fileInput = new moxie.file.FileInput({
+				browse_button: 'file-picker', // or document.getElementById('file-picker')
+				container: 'container',
+				accept: [
+					{title: "Image files", extensions: "jpg,gif,png"} // accept only images
+				],
+				multiple: true // allow multiple file selection
+			});
+
+			fileInput.onchange = function(e) {
+				// do something to files array
+				console.info(e.target.files); // or this.files or fileInput.files
+			};
+
+			fileInput.init(); // initialize
+		</script>
+	*/
+	var dispatches = [
+		/**
+		Dispatched when runtime is connected and file-picker is ready to be used.
+
+		@event ready
+		@param {Object} event
+		*/
+		'ready',
+
+		/**
+		Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked.
+		Check [corresponding documentation entry](#method_refresh) for more info.
+
+		@event refresh
+		@param {Object} event
+		*/
+
+		/**
+		Dispatched when selection of files in the dialog is complete.
+
+		@event change
+		@param {Object} event
+		*/
+		'change',
+
+		'cancel', // TODO: might be useful
+
+		/**
+		Dispatched when mouse cursor enters file-picker area. Can be used to style element
+		accordingly.
+
+		@event mouseenter
+		@param {Object} event
+		*/
+		'mouseenter',
+
+		/**
+		Dispatched when mouse cursor leaves file-picker area. Can be used to style element
+		accordingly.
+
+		@event mouseleave
+		@param {Object} event
+		*/
+		'mouseleave',
+
+		/**
+		Dispatched when functional mouse button is pressed on top of file-picker area.
+
+		@event mousedown
+		@param {Object} event
+		*/
+		'mousedown',
+
+		/**
+		Dispatched when functional mouse button is released on top of file-picker area.
+
+		@event mouseup
+		@param {Object} event
+		*/
+		'mouseup'
+	];
+
+	function FileInput(options) {
+		if (MXI_DEBUG) {
+			Env.log("Instantiating FileInput...");
+		}
+
+		var container, browseButton, defaults;
+
+		// if flat argument passed it should be browse_button id
+		if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) {
+			options = { browse_button : options };
+		}
+
+		// this will help us to find proper default container
+		browseButton = Dom.get(options.browse_button);
+		if (!browseButton) {
+			// browse button is required
+			throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
+		}
+
+		// figure out the options
+		defaults = {
+			accept: [{
+				title: I18n.translate('All Files'),
+				extensions: '*'
+			}],
+			multiple: false,
+			required_caps: false,
+			container: browseButton.parentNode || document.body
+		};
+
+		options = Basic.extend({}, defaults, options);
+
+		// convert to object representation
+		if (typeof(options.required_caps) === 'string') {
+			options.required_caps = Runtime.parseCaps(options.required_caps);
+		}
+
+		// normalize accept option (could be list of mime types or array of title/extensions pairs)
+		if (typeof(options.accept) === 'string') {
+			options.accept = Mime.mimes2extList(options.accept);
+		}
+
+		container = Dom.get(options.container);
+		// make sure we have container
+		if (!container) {
+			container = document.body;
+		}
+
+		// make container relative, if it's not
+		if (Dom.getStyle(container, 'position') === 'static') {
+			container.style.position = 'relative';
+		}
+
+		container = browseButton = null; // IE
+
+		RuntimeClient.call(this);
+
+		Basic.extend(this, {
+			/**
+			Unique id of the component
+
+			@property uid
+			@protected
+			@readOnly
+			@type {String}
+			@default UID
+			*/
+			uid: Basic.guid('uid_'),
+
+			/**
+			Unique id of the connected runtime, if any.
+
+			@property ruid
+			@protected
+			@type {String}
+			*/
+			ruid: null,
+
+			/**
+			Unique id of the runtime container. Useful to get hold of it for various manipulations.
+
+			@property shimid
+			@protected
+			@type {String}
+			*/
+			shimid: null,
+
+			/**
+			Array of selected moxie.file.File objects
+
+			@property files
+			@type {Array}
+			@default null
+			*/
+			files: null,
+
+			/**
+			Initializes the file-picker, connects it to runtime and dispatches event ready when done.
+
+			@method init
+			*/
+			init: function() {
+				var self = this;
+
+				self.bind('RuntimeInit', function(e, runtime) {
+					self.ruid = runtime.uid;
+					self.shimid = runtime.shimid;
+
+					self.bind("Ready", function() {
+						self.trigger("Refresh");
+					}, 999);
+
+					// re-position and resize shim container
+					self.bind('Refresh', function() {
+						var pos, size, browseButton, shimContainer, zIndex;
+
+						browseButton = Dom.get(options.browse_button);
+						shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist
+
+						if (browseButton) {
+							pos = Dom.getPos(browseButton, Dom.get(options.container));
+							size = Dom.getSize(browseButton);
+							zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 0;
+
+							if (shimContainer) {
+								Basic.extend(shimContainer.style, {
+									top: pos.y + 'px',
+									left: pos.x + 'px',
+									width: size.w + 'px',
+									height: size.h + 'px',
+									zIndex: zIndex + 1
+								});
+							}
+						}
+						shimContainer = browseButton = null;
+					});
+
+					runtime.exec.call(self, 'FileInput', 'init', options);
+				});
+
+				// runtime needs: options.required_features, options.runtime_order and options.container
+				self.connectRuntime(Basic.extend({}, options, {
+					required_caps: {
+						select_file: true
+					}
+				}));
+			},
+
+
+			/**
+			 * Get current option value by its name
+			 *
+			 * @method getOption
+			 * @param name
+			 * @return {Mixed}
+			 */
+			getOption: function(name) {
+				return options[name];
+			},
+
+
+			/**
+			 * Sets a new value for the option specified by name
+			 *
+			 * @method setOption
+			 * @param name
+			 * @param value
+			 */
+			setOption: function(name, value) {
+				if (!options.hasOwnProperty(name)) {
+					return;
+				}
+
+				var oldValue = options[name];
+
+				switch (name) {
+					case 'accept':
+						if (typeof(value) === 'string') {
+							value = Mime.mimes2extList(value);
+						}
+						break;
+
+					case 'container':
+					case 'required_caps':
+						throw new x.FileException(x.FileException.NO_MODIFICATION_ALLOWED_ERR);
+				}
+
+				options[name] = value;
+				this.exec('FileInput', 'setOption', name, value);
+
+				this.trigger('OptionChanged', name, value, oldValue);
+			},
+
+			/**
+			Disables file-picker element, so that it doesn't react to mouse clicks.
+
+			@method disable
+			@param {Boolean} [state=true] Disable component if - true, enable if - false
+			*/
+			disable: function(state) {
+				var runtime = this.getRuntime();
+				if (runtime) {
+					this.exec('FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);
+				}
+			},
+
+
+			/**
+			Reposition and resize dialog trigger to match the position and size of browse_button element.
+
+			@method refresh
+			*/
+			refresh: function() {
+				this.trigger("Refresh");
+			},
+
+
+			/**
+			Destroy component.
+
+			@method destroy
+			*/
+			destroy: function() {
+				var runtime = this.getRuntime();
+				if (runtime) {
+					runtime.exec.call(this, 'FileInput', 'destroy');
+					this.disconnectRuntime();
+				}
+
+				if (Basic.typeOf(this.files) === 'array') {
+					// no sense in leaving associated files behind
+					Basic.each(this.files, function(file) {
+						file.destroy();
+					});
+				}
+				this.files = null;
+
+				this.unbindAll();
+			}
+		});
+
+		this.handleEventProps(dispatches);
+	}
+
+	FileInput.prototype = EventTarget.instance;
+
+	return FileInput;
+});
+
+// Included from: src/javascript/file/File.js
+
+/**
+ * File.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/file/File', [
+	'moxie/core/utils/Basic',
+	'moxie/core/utils/Mime',
+	'moxie/file/Blob'
+], function(Basic, Mime, Blob) {
+	/**
+	@class moxie/file/File
+	@extends Blob
+	@constructor
+	@param {String} ruid Unique id of the runtime, to which this blob belongs to
+	@param {Object} file Object "Native" file object, as it is represented in the runtime
+	*/
+	function File(ruid, file) {
+		if (!file) { // avoid extra errors in case we overlooked something
+			file = {};
+		}
+
+		Blob.apply(this, arguments);
+
+		if (!this.type) {
+			this.type = Mime.getFileMime(file.name);
+		}
+
+		// sanitize file name or generate new one
+		var name;
+		if (file.name) {
+			name = file.name.replace(/\\/g, '/');
+			name = name.substr(name.lastIndexOf('/') + 1);
+		} else if (this.type) {
+			var prefix = this.type.split('/')[0];
+			name = Basic.guid((prefix !== '' ? prefix : 'file') + '_');
+			
+			if (Mime.extensions[this.type]) {
+				name += '.' + Mime.extensions[this.type][0]; // append proper extension if possible
+			}
+		}
+		
+		
+		Basic.extend(this, {
+			/**
+			File name
+
+			@property name
+			@type {String}
+			@default UID
+			*/
+			name: name || Basic.guid('file_'),
+
+			/**
+			Relative path to the file inside a directory
+
+			@property relativePath
+			@type {String}
+			@default ''
+			*/
+			relativePath: '',
+			
+			/**
+			Date of last modification
+
+			@property lastModifiedDate
+			@type {String}
+			@default now
+			*/
+			lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
+		});
+	}
+
+	File.prototype = Blob.prototype;
+
+	return File;
+});
+
+// Included from: src/javascript/file/FileDrop.js
+
+/**
+ * FileDrop.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/file/FileDrop', [
+	'moxie/core/I18n',
+	'moxie/core/utils/Dom',
+	'moxie/core/Exceptions',
+	'moxie/core/utils/Basic',
+	'moxie/core/utils/Env',
+	'moxie/file/File',
+	'moxie/runtime/RuntimeClient',
+	'moxie/core/EventTarget',
+	'moxie/core/utils/Mime'
+], function(I18n, Dom, x, Basic, Env, File, RuntimeClient, EventTarget, Mime) {
+	/**
+	Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used 
+	in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through 
+	_XMLHttpRequest_.
+
+	@example
+		<div id="drop_zone">
+			Drop files here
+		</div>
+		<br />
+		<div id="filelist"></div>
+
+		<script type="text/javascript">
+			var fileDrop = new moxie.file.FileDrop('drop_zone'), fileList = moxie.utils.Dom.get('filelist');
+
+			fileDrop.ondrop = function() {
+				moxie.utils.Basic.each(this.files, function(file) {
+					fileList.innerHTML += '<div>' + file.name + '</div>';
+				});
+			};
+
+			fileDrop.init();
+		</script>
+
+	@class moxie/file/FileDrop
+	@constructor
+	@extends EventTarget
+	@uses RuntimeClient
+	@param {Object|String} options If options has typeof string, argument is considered as options.drop_zone
+		@param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone
+		@param {Array} [options.accept] Array of mime types to accept. By default accepts all
+		@param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support
+	*/
+	var dispatches = [
+		/**
+		Dispatched when runtime is connected and drop zone is ready to accept files.
+
+		@event ready
+		@param {Object} event
+		*/
+		'ready', 
+
+		/**
+		Dispatched when dragging cursor enters the drop zone.
+
+		@event dragenter
+		@param {Object} event
+		*/
+		'dragenter',
+
+		/**
+		Dispatched when dragging cursor leaves the drop zone.
+
+		@event dragleave
+		@param {Object} event
+		*/
+		'dragleave', 
+
+		/**
+		Dispatched when file is dropped onto the drop zone.
+
+		@event drop
+		@param {Object} event
+		*/
+		'drop', 
+
+		/**
+		Dispatched if error occurs.
+
+		@event error
+		@param {Object} event
+		*/
+		'error'
+	];
+
+	function FileDrop(options) {
+		if (MXI_DEBUG) {
+			Env.log("Instantiating FileDrop...");	
+		}
+
+		var self = this, defaults;
+
+		// if flat argument passed it should be drop_zone id
+		if (typeof(options) === 'string') {
+			options = { drop_zone : options };
+		}
+
+		// figure out the options
+		defaults = {
+			accept: [{
+				title: I18n.translate('All Files'),
+				extensions: '*'
+			}],
+			required_caps: {
+				drag_and_drop: true
+			}
+		};
+		
+		options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults;
+
+		// this will help us to find proper default container
+		options.container = Dom.get(options.drop_zone) || document.body;
+
+		// make container relative, if it is not
+		if (Dom.getStyle(options.container, 'position') === 'static') {
+			options.container.style.position = 'relative';
+		}
+					
+		// normalize accept option (could be list of mime types or array of title/extensions pairs)
+		if (typeof(options.accept) === 'string') {
+			options.accept = Mime.mimes2extList(options.accept);
+		}
+
+		RuntimeClient.call(self);
+
+		Basic.extend(self, {
+			uid: Basic.guid('uid_'),
+
+			ruid: null,
+
+			files: null,
+
+			init: function() {		
+				self.bind('RuntimeInit', function(e, runtime) {
+					self.ruid = runtime.uid;
+					runtime.exec.call(self, 'FileDrop', 'init', options);
+					self.dispatchEvent('ready');
+				});
+							
+				// runtime needs: options.required_features, options.runtime_order and options.container
+				self.connectRuntime(options); // throws RuntimeError
+			},
+
+			destroy: function() {
+				var runtime = this.getRuntime();
+				if (runtime) {
+					runtime.exec.call(this, 'FileDrop', 'destroy');
+					this.disconnectRuntime();
+				}
+				this.files = null;
+				
+				this.unbindAll();
+			}
+		});
+
+		this.handleEventProps(dispatches);
+	}
+
+	FileDrop.prototype = EventTarget.instance;
+
+	return FileDrop;
+});
+
+// Included from: src/javascript/file/FileReader.js
+
+/**
+ * FileReader.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/file/FileReader', [
+	'moxie/core/utils/Basic',
+	'moxie/core/utils/Encode',
+	'moxie/core/Exceptions',
+	'moxie/core/EventTarget',
+	'moxie/file/Blob',
+	'moxie/runtime/RuntimeClient'
+], function(Basic, Encode, x, EventTarget, Blob, RuntimeClient) {
+	/**
+	Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader)
+	interface. Where possible uses native FileReader, where - not falls back to shims.
+
+	@class moxie/file/FileReader
+	@constructor FileReader
+	@extends EventTarget
+	@uses RuntimeClient
+	*/
+	var dispatches = [
+
+		/** 
+		Dispatched when the read starts.
+
+		@event loadstart
+		@param {Object} event
+		*/
+		'loadstart', 
+
+		/** 
+		Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total).
+
+		@event progress
+		@param {Object} event
+		*/
+		'progress', 
+
+		/** 
+		Dispatched when the read has successfully completed.
+
+		@event load
+		@param {Object} event
+		*/
+		'load', 
+
+		/** 
+		Dispatched when the read has been aborted. For instance, by invoking the abort() method.
+
+		@event abort
+		@param {Object} event
+		*/
+		'abort', 
+
+		/** 
+		Dispatched when the read has failed.
+
+		@event error
+		@param {Object} event
+		*/
+		'error', 
+
+		/** 
+		Dispatched when the request has completed (either in success or failure).
+
+		@event loadend
+		@param {Object} event
+		*/
+		'loadend'
+	];
+	
+	function FileReader() {
+
+		RuntimeClient.call(this);
+
+		Basic.extend(this, {
+			/**
+			UID of the component instance.
+
+			@property uid
+			@type {String}
+			*/
+			uid: Basic.guid('uid_'),
+
+			/**
+			Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING
+			and FileReader.DONE.
+
+			@property readyState
+			@type {Number}
+			@default FileReader.EMPTY
+			*/
+			readyState: FileReader.EMPTY,
+			
+			/**
+			Result of the successful read operation.
+
+			@property result
+			@type {String}
+			*/
+			result: null,
+			
+			/**
+			Stores the error of failed asynchronous read operation.
+
+			@property error
+			@type {DOMError}
+			*/
+			error: null,
+			
+			/**
+			Initiates reading of File/Blob object contents to binary string.
+
+			@method readAsBinaryString
+			@param {Blob|File} blob Object to preload
+			*/
+			readAsBinaryString: function(blob) {
+				_read.call(this, 'readAsBinaryString', blob);
+			},
+			
+			/**
+			Initiates reading of File/Blob object contents to dataURL string.
+
+			@method readAsDataURL
+			@param {Blob|File} blob Object to preload
+			*/
+			readAsDataURL: function(blob) {
+				_read.call(this, 'readAsDataURL', blob);
+			},
+			
+			/**
+			Initiates reading of File/Blob object contents to string.
+
+			@method readAsText
+			@param {Blob|File} blob Object to preload
+			*/
+			readAsText: function(blob) {
+				_read.call(this, 'readAsText', blob);
+			},
+			
+			/**
+			Aborts preloading process.
+
+			@method abort
+			*/
+			abort: function() {
+				this.result = null;
+				
+				if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) {
+					return;
+				} else if (this.readyState === FileReader.LOADING) {
+					this.readyState = FileReader.DONE;
+				}
+
+				this.exec('FileReader', 'abort');
+				
+				this.trigger('abort');
+				this.trigger('loadend');
+			},
+
+			/**
+			Destroy component and release resources.
+
+			@method destroy
+			*/
+			destroy: function() {
+				this.abort();
+				this.exec('FileReader', 'destroy');
+				this.disconnectRuntime();
+				this.unbindAll();
+			}
+		});
+
+		// uid must already be assigned
+		this.handleEventProps(dispatches);
+
+		this.bind('Error', function(e, err) {
+			this.readyState = FileReader.DONE;
+			this.error = err;
+		}, 999);
+		
+		this.bind('Load', function(e) {
+			this.readyState = FileReader.DONE;
+		}, 999);
+
+		
+		function _read(op, blob) {
+			var self = this;			
+
+			this.trigger('loadstart');
+
+			if (this.readyState === FileReader.LOADING) {
+				this.trigger('error', new x.DOMException(x.DOMException.INVALID_STATE_ERR));
+				this.trigger('loadend');
+				return;
+			}
+
+			// if source is not o.Blob/o.File
+			if (!(blob instanceof Blob)) {
+				this.trigger('error', new x.DOMException(x.DOMException.NOT_FOUND_ERR));
+				this.trigger('loadend');
+				return;
+			}
+
+			this.result = null;
+			this.readyState = FileReader.LOADING;
+			
+			if (blob.isDetached()) {
+				var src = blob.getSource();
+				switch (op) {
+					case 'readAsText':
+					case 'readAsBinaryString':
+						this.result = src;
+						break;
+					case 'readAsDataURL':
+						this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src);
+						break;
+				}
+				this.readyState = FileReader.DONE;
+				this.trigger('load');
+				this.trigger('loadend');
+			} else {
+				this.connectRuntime(blob.ruid);
+				this.exec('FileReader', 'read', op, blob);
+			}
+		}
+	}
+	
+	/**
+	Initial FileReader state
+
+	@property EMPTY
+	@type {Number}
+	@final
+	@static
+	@default 0
+	*/
+	FileReader.EMPTY = 0;
+
+	/**
+	FileReader switches to this state when it is preloading the source
+
+	@property LOADING
+	@type {Number}
+	@final
+	@static
+	@default 1
+	*/
+	FileReader.LOADING = 1;
+
+	/**
+	Preloading is complete, this is a final state
+
+	@property DONE
+	@type {Number}
+	@final
+	@static
+	@default 2
+	*/
+	FileReader.DONE = 2;
+
+	FileReader.prototype = EventTarget.instance;
+
+	return FileReader;
+});
+
+// Included from: src/javascript/core/utils/Url.js
+
+/**
+ * Url.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Url
+@public
+@static
+*/
+
+define('moxie/core/utils/Url', [
+	'moxie/core/utils/Basic'
+], function(Basic) {
+	/**
+	Parse url into separate components and fill in absent parts with parts from current url,
+	based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js
+
+	@method parseUrl
+	@static
+	@param {String} url Url to parse (defaults to empty string if undefined)
+	@return {Object} Hash containing extracted uri components
+	*/
+	var parseUrl = function(url, currentUrl) {
+		var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment']
+		, i = key.length
+		, ports = {
+			http: 80,
+			https: 443
+		}
+		, uri = {}
+		, regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?(\[[\da-fA-F:]+\]|[^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
+		, m = regex.exec(url || '')
+		, isRelative
+		, isSchemeLess = /^\/\/\w/.test(url)
+		;
+
+		switch (Basic.typeOf(currentUrl)) {
+			case 'undefined':
+				currentUrl = parseUrl(document.location.href, false);
+				break;
+
+			case 'string':
+				currentUrl = parseUrl(currentUrl, false);
+				break;
+		}
+
+		while (i--) {
+			if (m[i]) {
+				uri[key[i]] = m[i];
+			}
+		}
+
+		isRelative = !isSchemeLess && !uri.scheme;
+
+		if (isSchemeLess || isRelative) {
+			uri.scheme = currentUrl.scheme;
+		}
+
+		// when url is relative, we set the origin and the path ourselves
+		if (isRelative) {
+			uri.host = currentUrl.host;
+			uri.port = currentUrl.port;
+
+			var path = '';
+			// for urls without trailing slash we need to figure out the path
+			if (/^[^\/]/.test(uri.path)) {
+				path = currentUrl.path;
+				// if path ends with a filename, strip it
+				if (/\/[^\/]*\.[^\/]*$/.test(path)) {
+					path = path.replace(/\/[^\/]+$/, '/');
+				} else {
+					// avoid double slash at the end (see #127)
+					path = path.replace(/\/?$/, '/');
+				}
+			}
+			uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir
+		}
+
+		if (!uri.port) {
+			uri.port = ports[uri.scheme] || 80;
+		}
+
+		uri.port = parseInt(uri.port, 10);
+
+		if (!uri.path) {
+			uri.path = "/";
+		}
+
+		delete uri.source;
+
+		return uri;
+	};
+
+	/**
+	Resolve url - among other things will turn relative url to absolute
+
+	@method resolveUrl
+	@static
+	@param {String|Object} url Either absolute or relative, or a result of parseUrl call
+	@return {String} Resolved, absolute url
+	*/
+	var resolveUrl = function(url) {
+		var ports = { // we ignore default ports
+			http: 80,
+			https: 443
+		}
+		, urlp = typeof(url) === 'object' ? url : parseUrl(url);
+		;
+
+		return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : '');
+	};
+
+	/**
+	Check if specified url has the same origin as the current document
+
+	@method hasSameOrigin
+	@static
+	@param {String|Object} url
+	@return {Boolean}
+	*/
+	var hasSameOrigin = function(url) {
+		function origin(url) {
+			return [url.scheme, url.host, url.port].join('/');
+		}
+
+		if (typeof url === 'string') {
+			url = parseUrl(url);
+		}
+
+		return origin(parseUrl()) === origin(url);
+	};
+
+	return {
+		parseUrl: parseUrl,
+		resolveUrl: resolveUrl,
+		hasSameOrigin: hasSameOrigin
+	};
+});
+
+// Included from: src/javascript/runtime/RuntimeTarget.js
+
+/**
+ * RuntimeTarget.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/runtime/RuntimeTarget', [
+	'moxie/core/utils/Basic',
+	'moxie/runtime/RuntimeClient',
+	"moxie/core/EventTarget"
+], function(Basic, RuntimeClient, EventTarget) {
+	/**
+	Instance of this class can be used as a target for the events dispatched by shims,
+	when allowing them onto components is for either reason inappropriate
+
+	@class moxie/runtime/RuntimeTarget
+	@constructor
+	@protected
+	@extends EventTarget
+	*/
+	function RuntimeTarget() {
+		this.uid = Basic.guid('uid_');
+		
+		RuntimeClient.call(this);
+
+		this.destroy = function() {
+			this.disconnectRuntime();
+			this.unbindAll();
+		};
+	}
+
+	RuntimeTarget.prototype = EventTarget.instance;
+
+	return RuntimeTarget;
+});
+
+// Included from: src/javascript/file/FileReaderSync.js
+
+/**
+ * FileReaderSync.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/file/FileReaderSync', [
+	'moxie/core/utils/Basic',
+	'moxie/runtime/RuntimeClient',
+	'moxie/core/utils/Encode'
+], function(Basic, RuntimeClient, Encode) {
+	/**
+	Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here
+	it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be,
+	but probably < 1mb). Not meant to be used directly by user.
+
+	@class moxie/file/FileReaderSync
+	@private
+	@constructor
+	*/
+	return function() {
+		RuntimeClient.call(this);
+
+		Basic.extend(this, {
+			uid: Basic.guid('uid_'),
+
+			readAsBinaryString: function(blob) {
+				return _read.call(this, 'readAsBinaryString', blob);
+			},
+			
+			readAsDataURL: function(blob) {
+				return _read.call(this, 'readAsDataURL', blob);
+			},
+			
+			/*readAsArrayBuffer: function(blob) {
+				return _read.call(this, 'readAsArrayBuffer', blob);
+			},*/
+			
+			readAsText: function(blob) {
+				return _read.call(this, 'readAsText', blob);
+			}
+		});
+
+		function _read(op, blob) {
+			if (blob.isDetached()) {
+				var src = blob.getSource();
+				switch (op) {
+					case 'readAsBinaryString':
+						return src;
+					case 'readAsDataURL':
+						return 'data:' + blob.type + ';base64,' + Encode.btoa(src);
+					case 'readAsText':
+						var txt = '';
+						for (var i = 0, length = src.length; i < length; i++) {
+							txt += String.fromCharCode(src[i]);
+						}
+						return txt;
+				}
+			} else {
+				var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob);
+				this.disconnectRuntime();
+				return result;
+			}
+		}
+	};
+});
+
+// Included from: src/javascript/xhr/FormData.js
+
+/**
+ * FormData.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define("moxie/xhr/FormData", [
+	"moxie/core/Exceptions",
+	"moxie/core/utils/Basic",
+	"moxie/file/Blob"
+], function(x, Basic, Blob) {
+	/**
+	FormData
+
+	@class moxie/xhr/FormData
+	@constructor
+	*/
+	function FormData() {
+		var _blob, _fields = [];
+
+		Basic.extend(this, {
+			/**
+			Append another key-value pair to the FormData object
+
+			@method append
+			@param {String} name Name for the new field
+			@param {String|Blob|Array|Object} value Value for the field
+			*/
+			append: function(name, value) {
+				var self = this, valueType = Basic.typeOf(value);
+
+				// according to specs value might be either Blob or String
+				if (value instanceof Blob) {
+					_blob = {
+						name: name,
+						value: value // unfortunately we can only send single Blob in one FormData
+					};
+				} else if ('array' === valueType) {
+					name += '[]';
+
+					Basic.each(value, function(value) {
+						self.append(name, value);
+					});
+				} else if ('object' === valueType) {
+					Basic.each(value, function(value, key) {
+						self.append(name + '[' + key + ']', value);
+					});
+				} else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) {
+					self.append(name, "false");
+				} else {
+					_fields.push({
+						name: name,
+						value: value.toString()
+					});
+				}
+			},
+
+			/**
+			Checks if FormData contains Blob.
+
+			@method hasBlob
+			@return {Boolean}
+			*/
+			hasBlob: function() {
+				return !!this.getBlob();
+			},
+
+			/**
+			Retrieves blob.
+
+			@method getBlob
+			@return {Object} Either Blob if found or null
+			*/
+			getBlob: function() {
+				return _blob && _blob.value || null;
+			},
+
+			/**
+			Retrieves blob field name.
+
+			@method getBlobName
+			@return {String} Either Blob field name or null
+			*/
+			getBlobName: function() {
+				return _blob && _blob.name || null;
+			},
+
+			/**
+			Loop over the fields in FormData and invoke the callback for each of them.
+
+			@method each
+			@param {Function} cb Callback to call for each field
+			*/
+			each: function(cb) {
+				Basic.each(_fields, function(field) {
+					cb(field.value, field.name);
+				});
+
+				if (_blob) {
+					cb(_blob.value, _blob.name);
+				}
+			},
+
+			destroy: function() {
+				_blob = null;
+				_fields = [];
+			}
+		});
+	}
+
+	return FormData;
+});
+
+// Included from: src/javascript/xhr/XMLHttpRequest.js
+
+/**
+ * XMLHttpRequest.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define("moxie/xhr/XMLHttpRequest", [
+	"moxie/core/utils/Basic",
+	"moxie/core/Exceptions",
+	"moxie/core/EventTarget",
+	"moxie/core/utils/Encode",
+	"moxie/core/utils/Url",
+	"moxie/runtime/Runtime",
+	"moxie/runtime/RuntimeTarget",
+	"moxie/file/Blob",
+	"moxie/file/FileReaderSync",
+	"moxie/xhr/FormData",
+	"moxie/core/utils/Env",
+	"moxie/core/utils/Mime"
+], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) {
+
+	var httpCode = {
+		100: 'Continue',
+		101: 'Switching Protocols',
+		102: 'Processing',
+
+		200: 'OK',
+		201: 'Created',
+		202: 'Accepted',
+		203: 'Non-Authoritative Information',
+		204: 'No Content',
+		205: 'Reset Content',
+		206: 'Partial Content',
+		207: 'Multi-Status',
+		226: 'IM Used',
+
+		300: 'Multiple Choices',
+		301: 'Moved Permanently',
+		302: 'Found',
+		303: 'See Other',
+		304: 'Not Modified',
+		305: 'Use Proxy',
+		306: 'Reserved',
+		307: 'Temporary Redirect',
+
+		400: 'Bad Request',
+		401: 'Unauthorized',
+		402: 'Payment Required',
+		403: 'Forbidden',
+		404: 'Not Found',
+		405: 'Method Not Allowed',
+		406: 'Not Acceptable',
+		407: 'Proxy Authentication Required',
+		408: 'Request Timeout',
+		409: 'Conflict',
+		410: 'Gone',
+		411: 'Length Required',
+		412: 'Precondition Failed',
+		413: 'Request Entity Too Large',
+		414: 'Request-URI Too Long',
+		415: 'Unsupported Media Type',
+		416: 'Requested Range Not Satisfiable',
+		417: 'Expectation Failed',
+		422: 'Unprocessable Entity',
+		423: 'Locked',
+		424: 'Failed Dependency',
+		426: 'Upgrade Required',
+
+		500: 'Internal Server Error',
+		501: 'Not Implemented',
+		502: 'Bad Gateway',
+		503: 'Service Unavailable',
+		504: 'Gateway Timeout',
+		505: 'HTTP Version Not Supported',
+		506: 'Variant Also Negotiates',
+		507: 'Insufficient Storage',
+		510: 'Not Extended'
+	};
+
+	function XMLHttpRequestUpload() {
+		this.uid = Basic.guid('uid_');
+	}
+
+	XMLHttpRequestUpload.prototype = EventTarget.instance;
+
+	/**
+	Implementation of XMLHttpRequest
+
+	@class moxie/xhr/XMLHttpRequest
+	@constructor
+	@uses RuntimeClient
+	@extends EventTarget
+	*/
+	var dispatches = [
+		'loadstart',
+
+		'progress',
+
+		'abort',
+
+		'error',
+
+		'load',
+
+		'timeout',
+
+		'loadend'
+
+		// readystatechange (for historical reasons)
+	];
+
+	var NATIVE = 1, RUNTIME = 2;
+
+	function XMLHttpRequest() {
+		var self = this,
+			// this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible
+			props = {
+				/**
+				The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout.
+
+				@property timeout
+				@type Number
+				@default 0
+				*/
+				timeout: 0,
+
+				/**
+				Current state, can take following values:
+				UNSENT (numeric value 0)
+				The object has been constructed.
+
+				OPENED (numeric value 1)
+				The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method.
+
+				HEADERS_RECEIVED (numeric value 2)
+				All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available.
+
+				LOADING (numeric value 3)
+				The response entity body is being received.
+
+				DONE (numeric value 4)
+
+				@property readyState
+				@type Number
+				@default 0 (UNSENT)
+				*/
+				readyState: XMLHttpRequest.UNSENT,
+
+				/**
+				True when user credentials are to be included in a cross-origin request. False when they are to be excluded
+				in a cross-origin request and when cookies are to be ignored in its response. Initially false.
+
+				@property withCredentials
+				@type Boolean
+				@default false
+				*/
+				withCredentials: false,
+
+				/**
+				Returns the HTTP status code.
+
+				@property status
+				@type Number
+				@default 0
+				*/
+				status: 0,
+
+				/**
+				Returns the HTTP status text.
+
+				@property statusText
+				@type String
+				*/
+				statusText: "",
+
+				/**
+				Returns the response type. Can be set to change the response type. Values are:
+				the empty string (default), "arraybuffer", "blob", "document", "json", and "text".
+
+				@property responseType
+				@type String
+				*/
+				responseType: "",
+
+				/**
+				Returns the document response entity body.
+
+				Throws an "InvalidStateError" exception if responseType is not the empty string or "document".
+
+				@property responseXML
+				@type Document
+				*/
+				responseXML: null,
+
+				/**
+				Returns the text response entity body.
+
+				Throws an "InvalidStateError" exception if responseType is not the empty string or "text".
+
+				@property responseText
+				@type String
+				*/
+				responseText: null,
+
+				/**
+				Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body).
+				Can become: ArrayBuffer, Blob, Document, JSON, Text
+
+				@property response
+				@type Mixed
+				*/
+				response: null
+			},
+
+			_async = true,
+			_url,
+			_method,
+			_headers = {},
+			_user,
+			_password,
+			_encoding = null,
+			_mimeType = null,
+
+			// flags
+			_sync_flag = false,
+			_send_flag = false,
+			_upload_events_flag = false,
+			_upload_complete_flag = false,
+			_error_flag = false,
+			_same_origin_flag = false,
+
+			// times
+			_start_time,
+			_timeoutset_time,
+
+			_finalMime = null,
+			_finalCharset = null,
+
+			_options = {},
+			_xhr,
+			_responseHeaders = '',
+			_responseHeadersBag
+			;
+
+
+		Basic.extend(this, props, {
+			/**
+			Unique id of the component
+
+			@property uid
+			@type String
+			*/
+			uid: Basic.guid('uid_'),
+
+			/**
+			Target for Upload events
+
+			@property upload
+			@type XMLHttpRequestUpload
+			*/
+			upload: new XMLHttpRequestUpload(),
+
+
+			/**
+			Sets the request method, request URL, synchronous flag, request username, and request password.
+
+			Throws a "SyntaxError" exception if one of the following is true:
+
+			method is not a valid HTTP method.
+			url cannot be resolved.
+			url contains the "user:password" format in the userinfo production.
+			Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK.
+
+			Throws an "InvalidAccessError" exception if one of the following is true:
+
+			Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin.
+			There is an associated XMLHttpRequest document and either the timeout attribute is not zero,
+			the withCredentials attribute is true, or the responseType attribute is not the empty string.
+
+
+			@method open
+			@param {String} method HTTP method to use on request
+			@param {String} url URL to request
+			@param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default.
+			@param {String} [user] Username to use in HTTP authentication process on server-side
+			@param {String} [password] Password to use in HTTP authentication process on server-side
+			*/
+			open: function(method, url, async, user, password) {
+				var urlp;
+
+				// first two arguments are required
+				if (!method || !url) {
+					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
+				}
+
+				// 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method
+				if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) {
+					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
+				}
+
+				// 3
+				if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) {
+					_method = method.toUpperCase();
+				}
+
+
+				// 4 - allowing these methods poses a security risk
+				if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) {
+					throw new x.DOMException(x.DOMException.SECURITY_ERR);
+				}
+
+				// 5
+				url = Encode.utf8_encode(url);
+
+				// 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError".
+				urlp = Url.parseUrl(url);
+
+				_same_origin_flag = Url.hasSameOrigin(urlp);
+
+				// 7 - manually build up absolute url
+				_url = Url.resolveUrl(url);
+
+				// 9-10, 12-13
+				if ((user || password) && !_same_origin_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
+				}
+
+				_user = user || urlp.user;
+				_password = password || urlp.pass;
+
+				// 11
+				_async = async || true;
+
+				if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) {
+					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
+				}
+
+				// 14 - terminate abort()
+
+				// 15 - terminate send()
+
+				// 18
+				_sync_flag = !_async;
+				_send_flag = false;
+				_headers = {};
+				_reset.call(this);
+
+				// 19
+				_p('readyState', XMLHttpRequest.OPENED);
+
+				// 20
+				this.dispatchEvent('readystatechange');
+			},
+
+			/**
+			Appends an header to the list of author request headers, or if header is already
+			in the list of author request headers, combines its value with value.
+
+			Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
+			Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value
+			is not a valid HTTP header field value.
+
+			@method setRequestHeader
+			@param {String} header
+			@param {String|Number} value
+			*/
+			setRequestHeader: function(header, value) {
+				var uaHeaders = [ // these headers are controlled by the user agent
+						"accept-charset",
+						"accept-encoding",
+						"access-control-request-headers",
+						"access-control-request-method",
+						"connection",
+						"content-length",
+						"cookie",
+						"cookie2",
+						"content-transfer-encoding",
+						"date",
+						"expect",
+						"host",
+						"keep-alive",
+						"origin",
+						"referer",
+						"te",
+						"trailer",
+						"transfer-encoding",
+						"upgrade",
+						"user-agent",
+						"via"
+					];
+
+				// 1-2
+				if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				// 3
+				if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) {
+					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
+				}
+
+				// 4
+				/* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values
+				if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) {
+					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
+				}*/
+
+				header = Basic.trim(header).toLowerCase();
+
+				// setting of proxy-* and sec-* headers is prohibited by spec
+				if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) {
+					return false;
+				}
+
+				// camelize
+				// browsers lowercase header names (at least for custom ones)
+				// header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); });
+
+				if (!_headers[header]) {
+					_headers[header] = value;
+				} else {
+					// http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph)
+					_headers[header] += ', ' + value;
+				}
+				return true;
+			},
+
+			/**
+			 * Test if the specified header is already set on this request.
+			 * Returns a header value or boolean false if it's not yet set.
+			 *
+			 * @method hasRequestHeader
+			 * @param {String} header Name of the header to test
+			 * @return {Boolean|String}
+			 */
+			hasRequestHeader: function(header) {
+				return header && _headers[header.toLowerCase()] || false;
+			},
+
+			/**
+			Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.
+
+			@method getAllResponseHeaders
+			@return {String} reponse headers or empty string
+			*/
+			getAllResponseHeaders: function() {
+				return _responseHeaders || '';
+			},
+
+			/**
+			Returns the header field value from the response of which the field name matches header,
+			unless the field name is Set-Cookie or Set-Cookie2.
+
+			@method getResponseHeader
+			@param {String} header
+			@return {String} value(s) for the specified header or null
+			*/
+			getResponseHeader: function(header) {
+				header = header.toLowerCase();
+
+				if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) {
+					return null;
+				}
+
+				if (_responseHeaders && _responseHeaders !== '') {
+					// if we didn't parse response headers until now, do it and keep for later
+					if (!_responseHeadersBag) {
+						_responseHeadersBag = {};
+						Basic.each(_responseHeaders.split(/\r\n/), function(line) {
+							var pair = line.split(/:\s+/);
+							if (pair.length === 2) { // last line might be empty, omit
+								pair[0] = Basic.trim(pair[0]); // just in case
+								_responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form
+									header: pair[0],
+									value: Basic.trim(pair[1])
+								};
+							}
+						});
+					}
+					if (_responseHeadersBag.hasOwnProperty(header)) {
+						return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value;
+					}
+				}
+				return null;
+			},
+
+			/**
+			Sets the Content-Type header for the response to mime.
+			Throws an "InvalidStateError" exception if the state is LOADING or DONE.
+			Throws a "SyntaxError" exception if mime is not a valid media type.
+
+			@method overrideMimeType
+			@param String mime Mime type to set
+			*/
+			overrideMimeType: function(mime) {
+				var matches, charset;
+
+				// 1
+				if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				// 2
+				mime = Basic.trim(mime.toLowerCase());
+
+				if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) {
+					mime = matches[1];
+					if (matches[2]) {
+						charset = matches[2];
+					}
+				}
+
+				if (!Mime.mimes[mime]) {
+					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
+				}
+
+				// 3-4
+				_finalMime = mime;
+				_finalCharset = charset;
+			},
+
+			/**
+			Initiates the request. The optional argument provides the request entity body.
+			The argument is ignored if request method is GET or HEAD.
+
+			Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
+
+			@method send
+			@param {Blob|Document|String|FormData} [data] Request entity body
+			@param {Object} [options] Set of requirements and pre-requisities for runtime initialization
+			*/
+			send: function(data, options) {
+				if (Basic.typeOf(options) === 'string') {
+					_options = { ruid: options };
+				} else if (!options) {
+					_options = {};
+				} else {
+					_options = options;
+				}
+
+				// 1-2
+				if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				// 3
+				// sending Blob
+				if (data instanceof Blob) {
+					_options.ruid = data.ruid;
+					_mimeType = data.type || 'application/octet-stream';
+				}
+
+				// FormData
+				else if (data instanceof FormData) {
+					if (data.hasBlob()) {
+						var blob = data.getBlob();
+						_options.ruid = blob.ruid;
+						_mimeType = blob.type || 'application/octet-stream';
+					}
+				}
+
+				// DOMString
+				else if (typeof data === 'string') {
+					_encoding = 'UTF-8';
+					_mimeType = 'text/plain;charset=UTF-8';
+
+					// data should be converted to Unicode and encoded as UTF-8
+					data = Encode.utf8_encode(data);
+				}
+
+				// if withCredentials not set, but requested, set it automatically
+				if (!this.withCredentials) {
+					this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag;
+				}
+
+				// 4 - storage mutex
+				// 5
+				_upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP
+				// 6
+				_error_flag = false;
+				// 7
+				_upload_complete_flag = !data;
+				// 8 - Asynchronous steps
+				if (!_sync_flag) {
+					// 8.1
+					_send_flag = true;
+					// 8.2
+					// this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr
+					// 8.3
+					//if (!_upload_complete_flag) {
+						// this.upload.dispatchEvent('loadstart');	// will be dispatched either by native or runtime xhr
+					//}
+				}
+				// 8.5 - Return the send() method call, but continue running the steps in this algorithm.
+				_doXHR.call(this, data);
+			},
+
+			/**
+			Cancels any network activity.
+
+			@method abort
+			*/
+			abort: function() {
+				_error_flag = true;
+				_sync_flag = false;
+
+				if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) {
+					_p('readyState', XMLHttpRequest.DONE);
+					_send_flag = false;
+
+					if (_xhr) {
+						_xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag);
+					} else {
+						throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+					}
+
+					_upload_complete_flag = true;
+				} else {
+					_p('readyState', XMLHttpRequest.UNSENT);
+				}
+			},
+
+			destroy: function() {
+				if (_xhr) {
+					if (Basic.typeOf(_xhr.destroy) === 'function') {
+						_xhr.destroy();
+					}
+					_xhr = null;
+				}
+
+				this.unbindAll();
+
+				if (this.upload) {
+					this.upload.unbindAll();
+					this.upload = null;
+				}
+			}
+		});
+
+		this.handleEventProps(dispatches.concat(['readystatechange'])); // for historical reasons
+		this.upload.handleEventProps(dispatches);
+
+		/* this is nice, but maybe too lengthy
+
+		// if supported by JS version, set getters/setters for specific properties
+		o.defineProperty(this, 'readyState', {
+			configurable: false,
+
+			get: function() {
+				return _p('readyState');
+			}
+		});
+
+		o.defineProperty(this, 'timeout', {
+			configurable: false,
+
+			get: function() {
+				return _p('timeout');
+			},
+
+			set: function(value) {
+
+				if (_sync_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
+				}
+
+				// timeout still should be measured relative to the start time of request
+				_timeoutset_time = (new Date).getTime();
+
+				_p('timeout', value);
+			}
+		});
+
+		// the withCredentials attribute has no effect when fetching same-origin resources
+		o.defineProperty(this, 'withCredentials', {
+			configurable: false,
+
+			get: function() {
+				return _p('withCredentials');
+			},
+
+			set: function(value) {
+				// 1-2
+				if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				// 3-4
+				if (_anonymous_flag || _sync_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
+				}
+
+				// 5
+				_p('withCredentials', value);
+			}
+		});
+
+		o.defineProperty(this, 'status', {
+			configurable: false,
+
+			get: function() {
+				return _p('status');
+			}
+		});
+
+		o.defineProperty(this, 'statusText', {
+			configurable: false,
+
+			get: function() {
+				return _p('statusText');
+			}
+		});
+
+		o.defineProperty(this, 'responseType', {
+			configurable: false,
+
+			get: function() {
+				return _p('responseType');
+			},
+
+			set: function(value) {
+				// 1
+				if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				// 2
+				if (_sync_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
+				}
+
+				// 3
+				_p('responseType', value.toLowerCase());
+			}
+		});
+
+		o.defineProperty(this, 'responseText', {
+			configurable: false,
+
+			get: function() {
+				// 1
+				if (!~o.inArray(_p('responseType'), ['', 'text'])) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				// 2-3
+				if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				return _p('responseText');
+			}
+		});
+
+		o.defineProperty(this, 'responseXML', {
+			configurable: false,
+
+			get: function() {
+				// 1
+				if (!~o.inArray(_p('responseType'), ['', 'document'])) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				// 2-3
+				if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+
+				return _p('responseXML');
+			}
+		});
+
+		o.defineProperty(this, 'response', {
+			configurable: false,
+
+			get: function() {
+				if (!!~o.inArray(_p('responseType'), ['', 'text'])) {
+					if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {
+						return '';
+					}
+				}
+
+				if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
+					return null;
+				}
+
+				return _p('response');
+			}
+		});
+
+		*/
+
+		function _p(prop, value) {
+			if (!props.hasOwnProperty(prop)) {
+				return;
+			}
+			if (arguments.length === 1) { // get
+				return Env.can('define_property') ? props[prop] : self[prop];
+			} else { // set
+				if (Env.can('define_property')) {
+					props[prop] = value;
+				} else {
+					self[prop] = value;
+				}
+			}
+		}
+
+		/*
+		function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) {
+			// TODO: http://tools.ietf.org/html/rfc3490#section-4.1
+			return str.toLowerCase();
+		}
+		*/
+
+
+		function _doXHR(data) {
+			var self = this;
+
+			_start_time = new Date().getTime();
+
+			_xhr = new RuntimeTarget();
+
+			function loadEnd() {
+				if (_xhr) { // it could have been destroyed by now
+					_xhr.destroy();
+					_xhr = null;
+				}
+				self.dispatchEvent('loadend');
+				self = null;
+			}
+
+			function exec(runtime) {
+				_xhr.bind('LoadStart', function(e) {
+					_p('readyState', XMLHttpRequest.LOADING);
+					self.dispatchEvent('readystatechange');
+
+					self.dispatchEvent(e);
+
+					if (_upload_events_flag) {
+						self.upload.dispatchEvent(e);
+					}
+				});
+
+				_xhr.bind('Progress', function(e) {
+					if (_p('readyState') !== XMLHttpRequest.LOADING) {
+						_p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example)
+						self.dispatchEvent('readystatechange');
+					}
+					self.dispatchEvent(e);
+				});
+
+				_xhr.bind('UploadProgress', function(e) {
+					if (_upload_events_flag) {
+						self.upload.dispatchEvent({
+							type: 'progress',
+							lengthComputable: false,
+							total: e.total,
+							loaded: e.loaded
+						});
+					}
+				});
+
+				_xhr.bind('Load', function(e) {
+					_p('readyState', XMLHttpRequest.DONE);
+					_p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0));
+					_p('statusText', httpCode[_p('status')] || "");
+
+					_p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType')));
+
+					if (!!~Basic.inArray(_p('responseType'), ['text', ''])) {
+						_p('responseText', _p('response'));
+					} else if (_p('responseType') === 'document') {
+						_p('responseXML', _p('response'));
+					}
+
+					_responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders');
+
+					self.dispatchEvent('readystatechange');
+
+					if (_p('status') > 0) { // status 0 usually means that server is unreachable
+						if (_upload_events_flag) {
+							self.upload.dispatchEvent(e);
+						}
+						self.dispatchEvent(e);
+					} else {
+						_error_flag = true;
+						self.dispatchEvent('error');
+					}
+					loadEnd();
+				});
+
+				_xhr.bind('Abort', function(e) {
+					self.dispatchEvent(e);
+					loadEnd();
+				});
+
+				_xhr.bind('Error', function(e) {
+					_error_flag = true;
+					_p('readyState', XMLHttpRequest.DONE);
+					self.dispatchEvent('readystatechange');
+					_upload_complete_flag = true;
+					self.dispatchEvent(e);
+					loadEnd();
+				});
+
+				runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', {
+					url: _url,
+					method: _method,
+					async: _async,
+					user: _user,
+					password: _password,
+					headers: _headers,
+					mimeType: _mimeType,
+					encoding: _encoding,
+					responseType: self.responseType,
+					withCredentials: self.withCredentials,
+					options: _options
+				}, data);
+			}
+
+			// clarify our requirements
+			if (typeof(_options.required_caps) === 'string') {
+				_options.required_caps = Runtime.parseCaps(_options.required_caps);
+			}
+
+			_options.required_caps = Basic.extend({}, _options.required_caps, {
+				return_response_type: self.responseType
+			});
+
+			if (data instanceof FormData) {
+				_options.required_caps.send_multipart = true;
+			}
+
+			if (!Basic.isEmptyObj(_headers)) {
+				_options.required_caps.send_custom_headers = true;
+			}
+
+			if (!_same_origin_flag) {
+				_options.required_caps.do_cors = true;
+			}
+
+
+			if (_options.ruid) { // we do not need to wait if we can connect directly
+				exec(_xhr.connectRuntime(_options));
+			} else {
+				_xhr.bind('RuntimeInit', function(e, runtime) {
+					exec(runtime);
+				});
+				_xhr.bind('RuntimeError', function(e, err) {
+					self.dispatchEvent('RuntimeError', err);
+				});
+				_xhr.connectRuntime(_options);
+			}
+		}
+
+
+		function _reset() {
+			_p('responseText', "");
+			_p('responseXML', null);
+			_p('response', null);
+			_p('status', 0);
+			_p('statusText', "");
+			_start_time = _timeoutset_time = null;
+		}
+	}
+
+	XMLHttpRequest.UNSENT = 0;
+	XMLHttpRequest.OPENED = 1;
+	XMLHttpRequest.HEADERS_RECEIVED = 2;
+	XMLHttpRequest.LOADING = 3;
+	XMLHttpRequest.DONE = 4;
+
+	XMLHttpRequest.prototype = EventTarget.instance;
+
+	return XMLHttpRequest;
+});
+
+// Included from: src/javascript/runtime/Transporter.js
+
+/**
+ * Transporter.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define("moxie/runtime/Transporter", [
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Encode",
+	"moxie/runtime/RuntimeClient",
+	"moxie/core/EventTarget"
+], function(Basic, Encode, RuntimeClient, EventTarget) {
+
+	/**
+	@class moxie/runtime/Transporter
+	@private
+	@constructor
+	*/
+	function Transporter() {
+		var mod, _runtime, _data, _size, _pos, _chunk_size;
+
+		RuntimeClient.call(this);
+
+		Basic.extend(this, {
+			uid: Basic.guid('uid_'),
+
+			state: Transporter.IDLE,
+
+			result: null,
+
+			transport: function(data, type, options) {
+				var self = this;
+
+				options = Basic.extend({
+					chunk_size: 204798
+				}, options);
+
+				// should divide by three, base64 requires this
+				if ((mod = options.chunk_size % 3)) {
+					options.chunk_size += 3 - mod;
+				}
+
+				_chunk_size = options.chunk_size;
+
+				_reset.call(this);
+				_data = data;
+				_size = data.length;
+
+				if (Basic.typeOf(options) === 'string' || options.ruid) {
+					_run.call(self, type, this.connectRuntime(options));
+				} else {
+					// we require this to run only once
+					var cb = function(e, runtime) {
+						self.unbind("RuntimeInit", cb);
+						_run.call(self, type, runtime);
+					};
+					this.bind("RuntimeInit", cb);
+					this.connectRuntime(options);
+				}
+			},
+
+			abort: function() {
+				var self = this;
+
+				self.state = Transporter.IDLE;
+				if (_runtime) {
+					_runtime.exec.call(self, 'Transporter', 'clear');
+					self.trigger("TransportingAborted");
+				}
+
+				_reset.call(self);
+			},
+
+
+			destroy: function() {
+				this.unbindAll();
+				_runtime = null;
+				this.disconnectRuntime();
+				_reset.call(this);
+			}
+		});
+
+		function _reset() {
+			_size = _pos = 0;
+			_data = this.result = null;
+		}
+
+		function _run(type, runtime) {
+			var self = this;
+
+			_runtime = runtime;
+
+			//self.unbind("RuntimeInit");
+
+			self.bind("TransportingProgress", function(e) {
+				_pos = e.loaded;
+
+				if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) {
+					_transport.call(self);
+				}
+			}, 999);
+
+			self.bind("TransportingComplete", function() {
+				_pos = _size;
+				self.state = Transporter.DONE;
+				_data = null; // clean a bit
+				self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || '');
+			}, 999);
+
+			self.state = Transporter.BUSY;
+			self.trigger("TransportingStarted");
+			_transport.call(self);
+		}
+
+		function _transport() {
+			var self = this,
+				chunk,
+				bytesLeft = _size - _pos;
+
+			if (_chunk_size > bytesLeft) {
+				_chunk_size = bytesLeft;
+			}
+
+			chunk = Encode.btoa(_data.substr(_pos, _chunk_size));
+			_runtime.exec.call(self, 'Transporter', 'receive', chunk, _size);
+		}
+	}
+
+	Transporter.IDLE = 0;
+	Transporter.BUSY = 1;
+	Transporter.DONE = 2;
+
+	Transporter.prototype = EventTarget.instance;
+
+	return Transporter;
+});
+
+// Included from: src/javascript/image/Image.js
+
+/**
+ * Image.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define("moxie/image/Image", [
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Dom",
+	"moxie/core/Exceptions",
+	"moxie/file/FileReaderSync",
+	"moxie/xhr/XMLHttpRequest",
+	"moxie/runtime/Runtime",
+	"moxie/runtime/RuntimeClient",
+	"moxie/runtime/Transporter",
+	"moxie/core/utils/Env",
+	"moxie/core/EventTarget",
+	"moxie/file/Blob",
+	"moxie/file/File",
+	"moxie/core/utils/Encode"
+], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) {
+	/**
+	Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data.
+
+	@class moxie/image/Image
+	@constructor
+	@extends EventTarget
+	*/
+	var dispatches = [
+		'progress',
+
+		/**
+		Dispatched when loading is complete.
+
+		@event load
+		@param {Object} event
+		*/
+		'load',
+
+		'error',
+
+		/**
+		Dispatched when resize operation is complete.
+
+		@event resize
+		@param {Object} event
+		*/
+		'resize',
+
+		/**
+		Dispatched when visual representation of the image is successfully embedded
+		into the corresponsing container.
+
+		@event embedded
+		@param {Object} event
+		*/
+		'embedded'
+	];
+
+	function Image() {
+
+		RuntimeClient.call(this);
+
+		Basic.extend(this, {
+			/**
+			Unique id of the component
+
+			@property uid
+			@type {String}
+			*/
+			uid: Basic.guid('uid_'),
+
+			/**
+			Unique id of the connected runtime, if any.
+
+			@property ruid
+			@type {String}
+			*/
+			ruid: null,
+
+			/**
+			Name of the file, that was used to create an image, if available. If not equals to empty string.
+
+			@property name
+			@type {String}
+			@default ""
+			*/
+			name: "",
+
+			/**
+			Size of the image in bytes. Actual value is set only after image is preloaded.
+
+			@property size
+			@type {Number}
+			@default 0
+			*/
+			size: 0,
+
+			/**
+			Width of the image. Actual value is set only after image is preloaded.
+
+			@property width
+			@type {Number}
+			@default 0
+			*/
+			width: 0,
+
+			/**
+			Height of the image. Actual value is set only after image is preloaded.
+
+			@property height
+			@type {Number}
+			@default 0
+			*/
+			height: 0,
+
+			/**
+			Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded.
+
+			@property type
+			@type {String}
+			@default ""
+			*/
+			type: "",
+
+			/**
+			Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded.
+
+			@property meta
+			@type {Object}
+			@default {}
+			*/
+			meta: {},
+
+			/**
+			Alias for load method, that takes another moxie.image.Image object as a source (see load).
+
+			@method clone
+			@param {Image} src Source for the image
+			@param {Boolean} [exact=false] Whether to activate in-depth clone mode
+			*/
+			clone: function() {
+				this.load.apply(this, arguments);
+			},
+
+			/**
+			Loads image from various sources. Currently the source for new image can be: moxie.image.Image,
+			moxie.file.Blob/moxie.file.File, native Blob/File, dataUrl or URL. Depending on the type of the
+			source, arguments - differ. When source is URL, Image will be downloaded from remote destination
+			and loaded in memory.
+
+			@example
+				var img = new moxie.image.Image();
+				img.onload = function() {
+					var blob = img.getAsBlob();
+
+					var formData = new moxie.xhr.FormData();
+					formData.append('file', blob);
+
+					var xhr = new moxie.xhr.XMLHttpRequest();
+					xhr.onload = function() {
+						// upload complete
+					};
+					xhr.open('post', 'upload.php');
+					xhr.send(formData);
+				};
+				img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg)
+
+
+			@method load
+			@param {Image|Blob|File|String} src Source for the image
+			@param {Boolean|Object} [mixed]
+			*/
+			load: function() {
+				_load.apply(this, arguments);
+			},
+
+
+			/**
+			Resizes the image to fit the specified width/height. If crop is specified, image will also be
+			cropped to the exact dimensions.
+
+			@method resize
+			@since 3.0
+			@param {Object} options
+				@param {Number} options.width Resulting width
+				@param {Number} [options.height=width] Resulting height (optional, if not supplied will default to width)
+				@param {String} [options.type='image/jpeg'] MIME type of the resulting image
+				@param {Number} [options.quality=90] In the case of JPEG, controls the quality of resulting image
+				@param {Boolean} [options.crop='cc'] If not falsy, image will be cropped, by default from center
+				@param {Boolean} [options.fit=true] Whether to upscale the image to fit the exact dimensions
+				@param {Boolean} [options.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
+				@param {String} [options.resample='default'] Resampling algorithm to use during resize
+				@param {Boolean} [options.multipass=true] Whether to scale the image in steps (results in better quality)
+			*/
+			resize: function(options) {
+				var self = this;
+				var orientation;
+				var scale;
+
+				var srcRect = {
+					x: 0,
+					y: 0,
+					width: self.width,
+					height: self.height
+				};
+
+				var opts = Basic.extendIf({
+					width: self.width,
+					height: self.height,
+					type: self.type || 'image/jpeg',
+					quality: 90,
+					crop: false,
+					fit: true,
+					preserveHeaders: true,
+					resample: 'default',
+					multipass: true
+				}, options);
+
+				try {
+					if (!self.size) { // only preloaded image objects can be used as source
+						throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+					}
+
+					// no way to reliably intercept the crash due to high resolution, so we simply avoid it
+					if (self.width > Image.MAX_RESIZE_WIDTH || self.height > Image.MAX_RESIZE_HEIGHT) {
+						throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
+					}
+
+					// take into account orientation tag
+					orientation = (self.meta && self.meta.tiff && self.meta.tiff.Orientation) || 1;
+
+					if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation
+						var tmp = opts.width;
+						opts.width = opts.height;
+						opts.height = tmp;
+					}
+
+					if (opts.crop) {
+						scale = Math.max(opts.width/self.width, opts.height/self.height);
+
+						if (options.fit) {
+							// first scale it up or down to fit the original image
+							srcRect.width = Math.min(Math.ceil(opts.width/scale), self.width);
+							srcRect.height = Math.min(Math.ceil(opts.height/scale), self.height);
+
+							// recalculate the scale for adapted dimensions
+							scale = opts.width/srcRect.width;
+						} else {
+							srcRect.width = Math.min(opts.width, self.width);
+							srcRect.height = Math.min(opts.height, self.height);
+
+							// now we do not need to scale it any further
+							scale = 1;
+						}
+
+						if (typeof(opts.crop) === 'boolean') {
+							opts.crop = 'cc';
+						}
+
+						switch (opts.crop.toLowerCase().replace(/_/, '-')) {
+							case 'rb':
+							case 'right-bottom':
+								srcRect.x = self.width - srcRect.width;
+								srcRect.y = self.height - srcRect.height;
+								break;
+
+							case 'cb':
+							case 'center-bottom':
+								srcRect.x = Math.floor((self.width - srcRect.width) / 2);
+								srcRect.y = self.height - srcRect.height;
+								break;
+
+							case 'lb':
+							case 'left-bottom':
+								srcRect.x = 0;
+								srcRect.y = self.height - srcRect.height;
+								break;
+
+							case 'lt':
+							case 'left-top':
+								srcRect.x = 0;
+								srcRect.y = 0;
+								break;
+
+							case 'ct':
+							case 'center-top':
+								srcRect.x = Math.floor((self.width - srcRect.width) / 2);
+								srcRect.y = 0;
+								break;
+
+							case 'rt':
+							case 'right-top':
+								srcRect.x = self.width - srcRect.width;
+								srcRect.y = 0;
+								break;
+
+							case 'rc':
+							case 'right-center':
+							case 'right-middle':
+								srcRect.x = self.width - srcRect.width;
+								srcRect.y = Math.floor((self.height - srcRect.height) / 2);
+								break;
+
+
+							case 'lc':
+							case 'left-center':
+							case 'left-middle':
+								srcRect.x = 0;
+								srcRect.y = Math.floor((self.height - srcRect.height) / 2);
+								break;
+
+							case 'cc':
+							case 'center-center':
+							case 'center-middle':
+							default:
+								srcRect.x = Math.floor((self.width - srcRect.width) / 2);
+								srcRect.y = Math.floor((self.height - srcRect.height) / 2);
+						}
+
+						// original image might be smaller than requested crop, so - avoid negative values
+						srcRect.x = Math.max(srcRect.x, 0);
+						srcRect.y = Math.max(srcRect.y, 0);
+					} else {
+						scale = Math.min(opts.width/self.width, opts.height/self.height);
+
+						// do not upscale if we were asked to not fit it
+						if (scale > 1 && !opts.fit) {
+							scale = 1;
+						}
+					}
+
+					this.exec('Image', 'resize', srcRect, scale, opts);
+				} catch(ex) {
+					// for now simply trigger error event
+					self.trigger('error', ex.code);
+				}
+			},
+
+			/**
+			Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions.
+
+			@method downsize
+			@deprecated use resize()
+			*/
+			downsize: function(options) {
+				var defaults = {
+					width: this.width,
+					height: this.height,
+					type: this.type || 'image/jpeg',
+					quality: 90,
+					crop: false,
+					fit: false,
+					preserveHeaders: true,
+					resample: 'default'
+				}, opts;
+
+				if (typeof(options) === 'object') {
+					opts = Basic.extend(defaults, options);
+				} else {
+					// for backward compatibility
+					opts = Basic.extend(defaults, {
+						width: arguments[0],
+						height: arguments[1],
+						crop: arguments[2],
+						preserveHeaders: arguments[3]
+					});
+				}
+
+				this.resize(opts);
+			},
+
+			/**
+			Alias for downsize(width, height, true). (see downsize)
+
+			@method crop
+			@param {Number} width Resulting width
+			@param {Number} [height=width] Resulting height (optional, if not supplied will default to width)
+			@param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
+			*/
+			crop: function(width, height, preserveHeaders) {
+				this.downsize(width, height, true, preserveHeaders);
+			},
+
+			getAsCanvas: function() {
+				if (!Env.can('create_canvas')) {
+					throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
+				}
+				return this.exec('Image', 'getAsCanvas');
+			},
+
+			/**
+			Retrieves image in it's current state as moxie.file.Blob object. Cannot be run on empty or image in progress (throws
+			DOMException.INVALID_STATE_ERR).
+
+			@method getAsBlob
+			@param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
+			@param {Number} [quality=90] Applicable only together with mime type image/jpeg
+			@return {Blob} Image as Blob
+			*/
+			getAsBlob: function(type, quality) {
+				if (!this.size) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+				return this.exec('Image', 'getAsBlob', type || 'image/jpeg', quality || 90);
+			},
+
+			/**
+			Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws
+			DOMException.INVALID_STATE_ERR).
+
+			@method getAsDataURL
+			@param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
+			@param {Number} [quality=90] Applicable only together with mime type image/jpeg
+			@return {String} Image as dataURL string
+			*/
+			getAsDataURL: function(type, quality) {
+				if (!this.size) {
+					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+				}
+				return this.exec('Image', 'getAsDataURL', type || 'image/jpeg', quality || 90);
+			},
+
+			/**
+			Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws
+			DOMException.INVALID_STATE_ERR).
+
+			@method getAsBinaryString
+			@param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
+			@param {Number} [quality=90] Applicable only together with mime type image/jpeg
+			@return {String} Image as binary string
+			*/
+			getAsBinaryString: function(type, quality) {
+				var dataUrl = this.getAsDataURL(type, quality);
+				return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7));
+			},
+
+			/**
+			Embeds a visual representation of the image into the specified node. Depending on the runtime,
+			it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare,
+			can be used in legacy browsers that do not have canvas or proper dataURI support).
+
+			@method embed
+			@param {DOMElement} el DOM element to insert the image object into
+			@param {Object} [options]
+				@param {Number} [options.width] The width of an embed (defaults to the image width)
+				@param {Number} [options.height] The height of an embed (defaults to the image height)
+				@param {String} [options.type="image/jpeg"] Mime type
+				@param {Number} [options.quality=90] Quality of an embed, if mime type is image/jpeg
+				@param {Boolean} [options.crop=false] Whether to crop an embed to the specified dimensions
+				@param {Boolean} [options.fit=true] By default thumbs will be up- or downscaled as necessary to fit the dimensions
+			*/
+			embed: function(el, options) {
+				var self = this
+				, runtime // this has to be outside of all the closures to contain proper runtime
+				;
+
+				var opts = Basic.extend({
+					width: this.width,
+					height: this.height,
+					type: this.type || 'image/jpeg',
+					quality: 90,
+					fit: true,
+					resample: 'nearest'
+				}, options);
+
+
+				function render(type, quality) {
+					var img = this;
+
+					// if possible, embed a canvas element directly
+					if (Env.can('create_canvas')) {
+						var canvas = img.getAsCanvas();
+						if (canvas) {
+							el.appendChild(canvas);
+							canvas = null;
+							img.destroy();
+							self.trigger('embedded');
+							return;
+						}
+					}
+
+					var dataUrl = img.getAsDataURL(type, quality);
+					if (!dataUrl) {
+						throw new x.ImageError(x.ImageError.WRONG_FORMAT);
+					}
+
+					if (Env.can('use_data_uri_of', dataUrl.length)) {
+						el.innerHTML = '<img src="' + dataUrl + '" width="' + img.width + '" height="' + img.height + '" alt="" />';
+						img.destroy();
+						self.trigger('embedded');
+					} else {
+						var tr = new Transporter();
+
+						tr.bind("TransportingComplete", function() {
+							runtime = self.connectRuntime(this.result.ruid);
+
+							self.bind("Embedded", function() {
+								// position and size properly
+								Basic.extend(runtime.getShimContainer().style, {
+									//position: 'relative',
+									top: '0px',
+									left: '0px',
+									width: img.width + 'px',
+									height: img.height + 'px'
+								});
+
+								// some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's
+								// position type changes (in Gecko), but since we basically need this only in IEs 6/7 and
+								// sometimes 8 and they do not have this problem, we can comment this for now
+								/*tr.bind("RuntimeInit", function(e, runtime) {
+									tr.destroy();
+									runtime.destroy();
+									onResize.call(self); // re-feed our image data
+								});*/
+
+								runtime = null; // release
+							}, 999);
+
+							runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height);
+							img.destroy();
+						});
+
+						tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, {
+							required_caps: {
+								display_media: true
+							},
+							runtime_order: 'flash,silverlight',
+							container: el
+						});
+					}
+				}
+
+				try {
+					if (!(el = Dom.get(el))) {
+						throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR);
+					}
+
+					if (!this.size) { // only preloaded image objects can be used as source
+						throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+					}
+
+					// high-resolution images cannot be consistently handled across the runtimes
+					if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
+						//throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
+					}
+
+					var imgCopy = new Image();
+
+					imgCopy.bind("Resize", function() {
+						render.call(this, opts.type, opts.quality);
+					});
+
+					imgCopy.bind("Load", function() {
+						this.downsize(opts);
+					});
+
+					// if embedded thumb data is available and dimensions are big enough, use it
+					if (this.meta.thumb && this.meta.thumb.width >= opts.width && this.meta.thumb.height >= opts.height) {
+						imgCopy.load(this.meta.thumb.data);
+					} else {
+						imgCopy.clone(this, false);
+					}
+
+					return imgCopy;
+				} catch(ex) {
+					// for now simply trigger error event
+					this.trigger('error', ex.code);
+				}
+			},
+
+			/**
+			Properly destroys the image and frees resources in use. If any. Recommended way to dispose
+			moxie.image.Image object.
+
+			@method destroy
+			*/
+			destroy: function() {
+				if (this.ruid) {
+					this.getRuntime().exec.call(this, 'Image', 'destroy');
+					this.disconnectRuntime();
+				}
+				if (this.meta && this.meta.thumb) {
+					// thumb is blob, make sure we destroy it first
+					this.meta.thumb.data.destroy();
+				}
+				this.unbindAll();
+			}
+		});
+
+
+		// this is here, because in order to bind properly, we need uid, which is created above
+		this.handleEventProps(dispatches);
+
+		this.bind('Load Resize', function() {
+			return _updateInfo.call(this); // if operation fails (e.g. image is neither PNG nor JPEG) cancel all pending events
+		}, 999);
+
+
+		function _updateInfo(info) {
+			try {
+				if (!info) {
+					info = this.exec('Image', 'getInfo');
+				}
+
+				this.size = info.size;
+				this.width = info.width;
+				this.height = info.height;
+				this.type = info.type;
+				this.meta = info.meta;
+
+				// update file name, only if empty
+				if (this.name === '') {
+					this.name = info.name;
+				}
+
+				return true;
+			} catch(ex) {
+				this.trigger('error', ex.code);
+				return false;
+			}
+		}
+
+
+		function _load(src) {
+			var srcType = Basic.typeOf(src);
+
+			try {
+				// if source is Image
+				if (src instanceof Image) {
+					if (!src.size) { // only preloaded image objects can be used as source
+						throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+					}
+					_loadFromImage.apply(this, arguments);
+				}
+				// if source is o.Blob/o.File
+				else if (src instanceof Blob) {
+					if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) {
+						throw new x.ImageError(x.ImageError.WRONG_FORMAT);
+					}
+					_loadFromBlob.apply(this, arguments);
+				}
+				// if native blob/file
+				else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) {
+					_load.call(this, new File(null, src), arguments[1]);
+				}
+				// if String
+				else if (srcType === 'string') {
+					// if dataUrl String
+					if (src.substr(0, 5) === 'data:') {
+						_load.call(this, new Blob(null, { data: src }), arguments[1]);
+					}
+					// else assume Url, either relative or absolute
+					else {
+						_loadFromUrl.apply(this, arguments);
+					}
+				}
+				// if source seems to be an img node
+				else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') {
+					_load.call(this, src.src, arguments[1]);
+				}
+				else {
+					throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR);
+				}
+			} catch(ex) {
+				// for now simply trigger error event
+				this.trigger('error', ex.code);
+			}
+		}
+
+
+		function _loadFromImage(img, exact) {
+			var runtime = this.connectRuntime(img.ruid);
+			this.ruid = runtime.uid;
+			runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact));
+		}
+
+
+		function _loadFromBlob(blob, options) {
+			var self = this;
+
+			self.name = blob.name || '';
+
+			function exec(runtime) {
+				self.ruid = runtime.uid;
+				runtime.exec.call(self, 'Image', 'loadFromBlob', blob);
+			}
+
+			if (blob.isDetached()) {
+				this.bind('RuntimeInit', function(e, runtime) {
+					exec(runtime);
+				});
+
+				// convert to object representation
+				if (options && typeof(options.required_caps) === 'string') {
+					options.required_caps = Runtime.parseCaps(options.required_caps);
+				}
+
+				this.connectRuntime(Basic.extend({
+					required_caps: {
+						access_image_binary: true,
+						resize_image: true
+					}
+				}, options));
+			} else {
+				exec(this.connectRuntime(blob.ruid));
+			}
+		}
+
+
+		function _loadFromUrl(url, options) {
+			var self = this, xhr;
+
+			xhr = new XMLHttpRequest();
+
+			xhr.open('get', url);
+			xhr.responseType = 'blob';
+
+			xhr.onprogress = function(e) {
+				self.trigger(e);
+			};
+
+			xhr.onload = function() {
+				_loadFromBlob.call(self, xhr.response, true);
+			};
+
+			xhr.onerror = function(e) {
+				self.trigger(e);
+			};
+
+			xhr.onloadend = function() {
+				xhr.destroy();
+			};
+
+			xhr.bind('RuntimeError', function(e, err) {
+				self.trigger('RuntimeError', err);
+			});
+
+			xhr.send(null, options);
+		}
+	}
+
+	// virtual world will crash on you if image has a resolution higher than this:
+	Image.MAX_RESIZE_WIDTH = 8192;
+	Image.MAX_RESIZE_HEIGHT = 8192;
+
+	Image.prototype = EventTarget.instance;
+
+	return Image;
+});
+
+// Included from: src/javascript/runtime/html5/Runtime.js
+
+/**
+ * Runtime.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/*global File:true */
+
+/**
+Defines constructor for HTML5 runtime.
+
+@class moxie/runtime/html5/Runtime
+@private
+*/
+define("moxie/runtime/html5/Runtime", [
+	"moxie/core/utils/Basic",
+	"moxie/core/Exceptions",
+	"moxie/runtime/Runtime",
+	"moxie/core/utils/Env"
+], function(Basic, x, Runtime, Env) {
+	
+	var type = "html5", extensions = {};
+	
+	function Html5Runtime(options) {
+		var I = this
+		, Test = Runtime.capTest
+		, True = Runtime.capTrue
+		;
+
+		var caps = Basic.extend({
+				access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL),
+				access_image_binary: function() {
+					return I.can('access_binary') && !!extensions.Image;
+				},
+				display_media: Test(
+					(Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) && 
+					defined('moxie/image/Image')
+				),
+				do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()),
+				drag_and_drop: Test(function() {
+					// this comes directly from Modernizr: http://www.modernizr.com/
+					var div = document.createElement('div');
+					// IE has support for drag and drop since version 5, but doesn't support dropping files from desktop
+					return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 
+						(Env.browser !== 'IE' || Env.verComp(Env.version, 9, '>'));
+				}()),
+				filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest
+					return !(
+						(Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) || 
+						(Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) || 
+						(Env.browser === 'Safari' && Env.verComp(Env.version, 7, '<')) ||
+						(Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<'))
+					);
+				}()),
+				return_response_headers: True,
+				return_response_type: function(responseType) {
+					if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported
+						return true;
+					} 
+					return Env.can('return_response_type', responseType);
+				},
+				return_status_code: True,
+				report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload),
+				resize_image: function() {
+					return I.can('access_binary') && Env.can('create_canvas');
+				},
+				select_file: function() {
+					return Env.can('use_fileinput') && window.File;
+				},
+				select_folder: function() {
+					return I.can('select_file') && (
+						Env.browser === 'Chrome' && Env.verComp(Env.version, 21, '>=') ||
+						Env.browser === 'Firefox' && Env.verComp(Env.version, 42, '>=') // https://developer.mozilla.org/en-US/Firefox/Releases/42
+					);
+				},
+				select_multiple: function() {
+					// it is buggy on Safari Windows and iOS
+					return I.can('select_file') &&
+						!(Env.browser === 'Safari' && Env.os === 'Windows') &&
+						!(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.0", '>') && Env.verComp(Env.osVersion, "8.0.0", '<'));
+				},
+				send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))),
+				send_custom_headers: Test(window.XMLHttpRequest),
+				send_multipart: function() {
+					return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string');
+				},
+				slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)),
+				stream_upload: function(){
+					return I.can('slice_blob') && I.can('send_multipart');
+				},
+				summon_file_dialog: function() { // yeah... some dirty sniffing here...
+					return I.can('select_file') && !(
+						(Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '<')) ||
+						(Env.browser === 'Opera' && Env.verComp(Env.version, 12, '<')) ||
+						(Env.browser === 'IE' && Env.verComp(Env.version, 10, '<'))
+					);
+				},
+				upload_filesize: True,
+				use_http_method: True
+			}, 
+			arguments[2]
+		);
+
+		Runtime.call(this, options, (arguments[1] || type), caps);
+
+
+		Basic.extend(this, {
+
+			init : function() {
+				this.trigger("Init");
+			},
+
+			destroy: (function(destroy) { // extend default destroy method
+				return function() {
+					destroy.call(I);
+					destroy = I = null;
+				};
+			}(this.destroy))
+		});
+
+		Basic.extend(this.getShim(), extensions);
+	}
+
+	Runtime.addConstructor(type, Html5Runtime);
+
+	return extensions;
+});
+
+// Included from: src/javascript/runtime/html5/file/Blob.js
+
+/**
+ * Blob.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/file/Blob
+@private
+*/
+define("moxie/runtime/html5/file/Blob", [
+	"moxie/runtime/html5/Runtime",
+	"moxie/file/Blob"
+], function(extensions, Blob) {
+
+	function HTML5Blob() {
+		function w3cBlobSlice(blob, start, end) {
+			var blobSlice;
+
+			if (window.File.prototype.slice) {
+				try {
+					blob.slice();	// depricated version will throw WRONG_ARGUMENTS_ERR exception
+					return blob.slice(start, end);
+				} catch (e) {
+					// depricated slice method
+					return blob.slice(start, end - start);
+				}
+			// slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672
+			} else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) {
+				return blobSlice.call(blob, start, end);
+			} else {
+				return null; // or throw some exception
+			}
+		}
+
+		this.slice = function() {
+			return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments));
+		};
+
+		this.destroy = function() {
+			this.getRuntime().getShim().removeInstance(this.uid);
+		};
+	}
+
+	return (extensions.Blob = HTML5Blob);
+});
+
+// Included from: src/javascript/core/utils/Events.js
+
+/**
+ * Events.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Events
+@public
+@static
+*/
+
+define('moxie/core/utils/Events', [
+	'moxie/core/utils/Basic'
+], function(Basic) {
+	var eventhash = {}, uid = 'moxie_' + Basic.guid();
+	
+	// IE W3C like event funcs
+	function preventDefault() {
+		this.returnValue = false;
+	}
+
+	function stopPropagation() {
+		this.cancelBubble = true;
+	}
+
+	/**
+	Adds an event handler to the specified object and store reference to the handler
+	in objects internal Plupload registry (@see removeEvent).
+	
+	@method addEvent
+	@static
+	@param {Object} obj DOM element like object to add handler to.
+	@param {String} name Name to add event listener to.
+	@param {Function} callback Function to call when event occurs.
+	@param {String} [key] that might be used to add specifity to the event record.
+	*/
+	var addEvent = function(obj, name, callback, key) {
+		var func, events;
+					
+		name = name.toLowerCase();
+
+		// Add event listener
+		if (obj.addEventListener) {
+			func = callback;
+			
+			obj.addEventListener(name, func, false);
+		} else if (obj.attachEvent) {
+			func = function() {
+				var evt = window.event;
+
+				if (!evt.target) {
+					evt.target = evt.srcElement;
+				}
+
+				evt.preventDefault = preventDefault;
+				evt.stopPropagation = stopPropagation;
+
+				callback(evt);
+			};
+
+			obj.attachEvent('on' + name, func);
+		}
+		
+		// Log event handler to objects internal mOxie registry
+		if (!obj[uid]) {
+			obj[uid] = Basic.guid();
+		}
+		
+		if (!eventhash.hasOwnProperty(obj[uid])) {
+			eventhash[obj[uid]] = {};
+		}
+		
+		events = eventhash[obj[uid]];
+		
+		if (!events.hasOwnProperty(name)) {
+			events[name] = [];
+		}
+				
+		events[name].push({
+			func: func,
+			orig: callback, // store original callback for IE
+			key: key
+		});
+	};
+	
+	
+	/**
+	Remove event handler from the specified object. If third argument (callback)
+	is not specified remove all events with the specified name.
+	
+	@method removeEvent
+	@static
+	@param {Object} obj DOM element to remove event listener(s) from.
+	@param {String} name Name of event listener to remove.
+	@param {Function|String} [callback] might be a callback or unique key to match.
+	*/
+	var removeEvent = function(obj, name, callback) {
+		var type, undef;
+		
+		name = name.toLowerCase();
+		
+		if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) {
+			type = eventhash[obj[uid]][name];
+		} else {
+			return;
+		}
+			
+		for (var i = type.length - 1; i >= 0; i--) {
+			// undefined or not, key should match
+			if (type[i].orig === callback || type[i].key === callback) {
+				if (obj.removeEventListener) {
+					obj.removeEventListener(name, type[i].func, false);
+				} else if (obj.detachEvent) {
+					obj.detachEvent('on'+name, type[i].func);
+				}
+				
+				type[i].orig = null;
+				type[i].func = null;
+				type.splice(i, 1);
+				
+				// If callback was passed we are done here, otherwise proceed
+				if (callback !== undef) {
+					break;
+				}
+			}
+		}
+		
+		// If event array got empty, remove it
+		if (!type.length) {
+			delete eventhash[obj[uid]][name];
+		}
+		
+		// If mOxie registry has become empty, remove it
+		if (Basic.isEmptyObj(eventhash[obj[uid]])) {
+			delete eventhash[obj[uid]];
+			
+			// IE doesn't let you remove DOM object property with - delete
+			try {
+				delete obj[uid];
+			} catch(e) {
+				obj[uid] = undef;
+			}
+		}
+	};
+	
+	
+	/**
+	Remove all kind of events from the specified object
+	
+	@method removeAllEvents
+	@static
+	@param {Object} obj DOM element to remove event listeners from.
+	@param {String} [key] unique key to match, when removing events.
+	*/
+	var removeAllEvents = function(obj, key) {		
+		if (!obj || !obj[uid]) {
+			return;
+		}
+		
+		Basic.each(eventhash[obj[uid]], function(events, name) {
+			removeEvent(obj, name, key);
+		});
+	};
+
+	return {
+		addEvent: addEvent,
+		removeEvent: removeEvent,
+		removeAllEvents: removeAllEvents
+	};
+});
+
+// Included from: src/javascript/runtime/html5/file/FileInput.js
+
+/**
+ * FileInput.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/file/FileInput
+@private
+*/
+define("moxie/runtime/html5/file/FileInput", [
+	"moxie/runtime/html5/Runtime",
+	"moxie/file/File",
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Dom",
+	"moxie/core/utils/Events",
+	"moxie/core/utils/Mime",
+	"moxie/core/utils/Env"
+], function(extensions, File, Basic, Dom, Events, Mime, Env) {
+	
+	function FileInput() {
+		var _options, _browseBtnZIndex; // save original z-index
+
+		Basic.extend(this, {
+			init: function(options) {
+				var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top;
+
+				_options = options;
+
+				// figure out accept string
+				mimes = Mime.extList2mimes(_options.accept, I.can('filter_by_extension'));
+
+				shimContainer = I.getShimContainer();
+
+				shimContainer.innerHTML = '<input id="' + I.uid +'" type="file" style="font-size:999px;opacity:0;"' +
+					(_options.multiple && I.can('select_multiple') ? 'multiple' : '') + 
+					(_options.directory && I.can('select_folder') ? 'webkitdirectory directory' : '') + // Chrome 11+
+					(mimes ? ' accept="' + mimes.join(',') + '"' : '') + ' />';
+
+				input = Dom.get(I.uid);
+
+				// prepare file input to be placed underneath the browse_button element
+				Basic.extend(input.style, {
+					position: 'absolute',
+					top: 0,
+					left: 0,
+					width: '100%',
+					height: '100%'
+				});
+
+
+				browseButton = Dom.get(_options.browse_button);
+				_browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto';
+
+				// Route click event to the input[type=file] element for browsers that support such behavior
+				if (I.can('summon_file_dialog')) {
+					if (Dom.getStyle(browseButton, 'position') === 'static') {
+						browseButton.style.position = 'relative';
+					}
+
+					Events.addEvent(browseButton, 'click', function(e) {
+						var input = Dom.get(I.uid);
+						if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
+							input.click();
+						}
+						e.preventDefault();
+					}, comp.uid);
+
+					comp.bind('Refresh', function() {
+						zIndex = parseInt(_browseBtnZIndex, 10) || 1;
+
+						Dom.get(_options.browse_button).style.zIndex = zIndex;
+						this.getRuntime().getShimContainer().style.zIndex = zIndex - 1;
+					});
+				}
+
+				/* Since we have to place input[type=file] on top of the browse_button for some browsers,
+				browse_button loses interactivity, so we restore it here */
+				top = I.can('summon_file_dialog') ? browseButton : shimContainer;
+
+				Events.addEvent(top, 'mouseover', function() {
+					comp.trigger('mouseenter');
+				}, comp.uid);
+
+				Events.addEvent(top, 'mouseout', function() {
+					comp.trigger('mouseleave');
+				}, comp.uid);
+
+				Events.addEvent(top, 'mousedown', function() {
+					comp.trigger('mousedown');
+				}, comp.uid);
+
+				Events.addEvent(Dom.get(_options.container), 'mouseup', function() {
+					comp.trigger('mouseup');
+				}, comp.uid);
+
+				// it shouldn't be possible to tab into the hidden element
+				(I.can('summon_file_dialog') ? input : browseButton).setAttribute('tabindex', -1);
+
+				input.onchange = function onChange() { // there should be only one handler for this
+					comp.files = [];
+
+					Basic.each(this.files, function(file) {
+						var relativePath = '';
+
+						if (_options.directory) {
+							// folders are represented by dots, filter them out (Chrome 11+)
+							if (file.name == ".") {
+								// if it looks like a folder...
+								return true;
+							}
+						}
+
+						if (file.webkitRelativePath) {
+							relativePath = '/' + file.webkitRelativePath.replace(/^\//, '');
+						}
+						
+						file = new File(I.uid, file);
+						file.relativePath = relativePath;
+
+						comp.files.push(file);
+					});
+
+					// clearing the value enables the user to select the same file again if they want to
+					if (Env.browser !== 'IE' && Env.browser !== 'IEMobile') {
+						this.value = '';
+					} else {
+						// in IE input[type="file"] is read-only so the only way to reset it is to re-insert it
+						var clone = this.cloneNode(true);
+						this.parentNode.replaceChild(clone, this);
+						clone.onchange = onChange;
+					}
+
+					if (comp.files.length) {
+						comp.trigger('change');
+					}
+				};
+
+				// ready event is perfectly asynchronous
+				comp.trigger({
+					type: 'ready',
+					async: true
+				});
+
+				shimContainer = null;
+			},
+
+
+			setOption: function(name, value) {
+				var I = this.getRuntime();
+				var input = Dom.get(I.uid);
+
+				switch (name) {
+					case 'accept':
+						if (value) {
+							var mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension'));
+							input.setAttribute('accept', mimes.join(','));
+						} else {
+							input.removeAttribute('accept');
+						}
+						break;
+
+					case 'directory':
+						if (value && I.can('select_folder')) {
+							input.setAttribute('directory', '');
+							input.setAttribute('webkitdirectory', '');
+						} else {
+							input.removeAttribute('directory');
+							input.removeAttribute('webkitdirectory');
+						}
+						break;
+
+					case 'multiple':
+						if (value && I.can('select_multiple')) {
+							input.setAttribute('multiple', '');
+						} else {
+							input.removeAttribute('multiple');
+						}
+
+				}
+			},
+
+
+			disable: function(state) {
+				var I = this.getRuntime(), input;
+
+				if ((input = Dom.get(I.uid))) {
+					input.disabled = !!state;
+				}
+			},
+
+			destroy: function() {
+				var I = this.getRuntime()
+				, shim = I.getShim()
+				, shimContainer = I.getShimContainer()
+				, container = _options && Dom.get(_options.container)
+				, browseButton = _options && Dom.get(_options.browse_button)
+				;
+				
+				if (container) {
+					Events.removeAllEvents(container, this.uid);
+				}
+				
+				if (browseButton) {
+					Events.removeAllEvents(browseButton, this.uid);
+					browseButton.style.zIndex = _browseBtnZIndex; // reset to original value
+				}
+				
+				if (shimContainer) {
+					Events.removeAllEvents(shimContainer, this.uid);
+					shimContainer.innerHTML = '';
+				}
+
+				shim.removeInstance(this.uid);
+
+				_options = shimContainer = container = browseButton = shim = null;
+			}
+		});
+	}
+
+	return (extensions.FileInput = FileInput);
+});
+
+// Included from: src/javascript/runtime/html5/file/FileDrop.js
+
+/**
+ * FileDrop.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/file/FileDrop
+@private
+*/
+define("moxie/runtime/html5/file/FileDrop", [
+	"moxie/runtime/html5/Runtime",
+	'moxie/file/File',
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Dom",
+	"moxie/core/utils/Events",
+	"moxie/core/utils/Mime"
+], function(extensions, File, Basic, Dom, Events, Mime) {
+	
+	function FileDrop() {
+		var _files = [], _allowedExts = [], _options, _ruid;
+
+		Basic.extend(this, {
+			init: function(options) {
+				var comp = this, dropZone;
+
+				_options = options;
+				_ruid = comp.ruid; // every dropped-in file should have a reference to the runtime
+				_allowedExts = _extractExts(_options.accept);
+				dropZone = _options.container;
+
+				Events.addEvent(dropZone, 'dragover', function(e) {
+					if (!_hasFiles(e)) {
+						return;
+					}
+					e.preventDefault();
+					e.dataTransfer.dropEffect = 'copy';
+				}, comp.uid);
+
+				Events.addEvent(dropZone, 'drop', function(e) {
+					if (!_hasFiles(e)) {
+						return;
+					}
+					e.preventDefault();
+
+					_files = [];
+
+					// Chrome 21+ accepts folders via Drag'n'Drop
+					if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) {
+						_readItems(e.dataTransfer.items, function() {
+							comp.files = _files;
+							comp.trigger("drop");
+						});
+					} else {
+						Basic.each(e.dataTransfer.files, function(file) {
+							_addFile(file);
+						});
+						comp.files = _files;
+						comp.trigger("drop");
+					}
+				}, comp.uid);
+
+				Events.addEvent(dropZone, 'dragenter', function(e) {
+					comp.trigger("dragenter");
+				}, comp.uid);
+
+				Events.addEvent(dropZone, 'dragleave', function(e) {
+					comp.trigger("dragleave");
+				}, comp.uid);
+			},
+
+			destroy: function() {
+				Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
+				_ruid = _files = _allowedExts = _options = null;
+				this.getRuntime().getShim().removeInstance(this.uid);
+			}
+		});
+
+
+		function _hasFiles(e) {
+			if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover
+				return false;
+			}
+
+			var types = Basic.toArray(e.dataTransfer.types || []);
+
+			return Basic.inArray("Files", types) !== -1 ||
+				Basic.inArray("public.file-url", types) !== -1 || // Safari < 5
+				Basic.inArray("application/x-moz-file", types) !== -1 // Gecko < 1.9.2 (< Firefox 3.6)
+				;
+		}
+
+
+		function _addFile(file, relativePath) {
+			if (_isAcceptable(file)) {
+				var fileObj = new File(_ruid, file);
+				fileObj.relativePath = relativePath || '';
+				_files.push(fileObj);
+			}
+		}
+
+		
+		function _extractExts(accept) {
+			var exts = [];
+			for (var i = 0; i < accept.length; i++) {
+				[].push.apply(exts, accept[i].extensions.split(/\s*,\s*/));
+			}
+			return Basic.inArray('*', exts) === -1 ? exts : [];
+		}
+
+
+		function _isAcceptable(file) {
+			if (!_allowedExts.length) {
+				return true;
+			}
+			var ext = Mime.getFileExtension(file.name);
+			return !ext || Basic.inArray(ext, _allowedExts) !== -1;
+		}
+
+
+		function _readItems(items, cb) {
+			var entries = [];
+			Basic.each(items, function(item) {
+				var entry = item.webkitGetAsEntry();
+				// Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579)
+				if (entry) {
+					// file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61
+					if (entry.isFile) {
+						_addFile(item.getAsFile(), entry.fullPath);
+					} else {
+						entries.push(entry);
+					}
+				}
+			});
+
+			if (entries.length) {
+				_readEntries(entries, cb);
+			} else {
+				cb();
+			}
+		}
+
+
+		function _readEntries(entries, cb) {
+			var queue = [];
+			Basic.each(entries, function(entry) {
+				queue.push(function(cbcb) {
+					_readEntry(entry, cbcb);
+				});
+			});
+			Basic.inSeries(queue, function() {
+				cb();
+			});
+		}
+
+
+		function _readEntry(entry, cb) {
+			if (entry.isFile) {
+				entry.file(function(file) {
+					_addFile(file, entry.fullPath);
+					cb();
+				}, function() {
+					// fire an error event maybe
+					cb();
+				});
+			} else if (entry.isDirectory) {
+				_readDirEntry(entry, cb);
+			} else {
+				cb(); // not file, not directory? what then?..
+			}
+		}
+
+
+		function _readDirEntry(dirEntry, cb) {
+			var entries = [], dirReader = dirEntry.createReader();
+
+			// keep quering recursively till no more entries
+			function getEntries(cbcb) {
+				dirReader.readEntries(function(moreEntries) {
+					if (moreEntries.length) {
+						[].push.apply(entries, moreEntries);
+						getEntries(cbcb);
+					} else {
+						cbcb();
+					}
+				}, cbcb);
+			}
+
+			// ...and you thought FileReader was crazy...
+			getEntries(function() {
+				_readEntries(entries, cb);
+			}); 
+		}
+	}
+
+	return (extensions.FileDrop = FileDrop);
+});
+
+// Included from: src/javascript/runtime/html5/file/FileReader.js
+
+/**
+ * FileReader.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/file/FileReader
+@private
+*/
+define("moxie/runtime/html5/file/FileReader", [
+	"moxie/runtime/html5/Runtime",
+	"moxie/core/utils/Encode",
+	"moxie/core/utils/Basic"
+], function(extensions, Encode, Basic) {
+	
+	function FileReader() {
+		var _fr, _convertToBinary = false;
+
+		Basic.extend(this, {
+
+			read: function(op, blob) {
+				var comp = this;
+
+				comp.result = '';
+
+				_fr = new window.FileReader();
+
+				_fr.addEventListener('progress', function(e) {
+					comp.trigger(e);
+				});
+
+				_fr.addEventListener('load', function(e) {
+					comp.result = _convertToBinary ? _toBinary(_fr.result) : _fr.result;
+					comp.trigger(e);
+				});
+
+				_fr.addEventListener('error', function(e) {
+					comp.trigger(e, _fr.error);
+				});
+
+				_fr.addEventListener('loadend', function(e) {
+					_fr = null;
+					comp.trigger(e);
+				});
+
+				if (Basic.typeOf(_fr[op]) === 'function') {
+					_convertToBinary = false;
+					_fr[op](blob.getSource());
+				} else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+
+					_convertToBinary = true;
+					_fr.readAsDataURL(blob.getSource());
+				}
+			},
+
+			abort: function() {
+				if (_fr) {
+					_fr.abort();
+				}
+			},
+
+			destroy: function() {
+				_fr = null;
+				this.getRuntime().getShim().removeInstance(this.uid);
+			}
+		});
+
+		function _toBinary(str) {
+			return Encode.atob(str.substring(str.indexOf('base64,') + 7));
+		}
+	}
+
+	return (extensions.FileReader = FileReader);
+});
+
+// Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js
+
+/**
+ * XMLHttpRequest.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/*global ActiveXObject:true */
+
+/**
+@class moxie/runtime/html5/xhr/XMLHttpRequest
+@private
+*/
+define("moxie/runtime/html5/xhr/XMLHttpRequest", [
+	"moxie/runtime/html5/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Mime",
+	"moxie/core/utils/Url",
+	"moxie/file/File",
+	"moxie/file/Blob",
+	"moxie/xhr/FormData",
+	"moxie/core/Exceptions",
+	"moxie/core/utils/Env"
+], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) {
+	
+	function XMLHttpRequest() {
+		var self = this
+		, _xhr
+		, _filename
+		;
+
+		Basic.extend(this, {
+			send: function(meta, data) {
+				var target = this
+				, isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.verComp(Env.version, 4, '>=') && Env.verComp(Env.version, 7, '<'))
+				, isAndroidBrowser = Env.browser === 'Android Browser'
+				, mustSendAsBinary = false
+				;
+
+				// extract file name
+				_filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase();
+
+				_xhr = _getNativeXHR();
+				_xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password);
+
+
+				// prepare data to be sent
+				if (data instanceof Blob) {
+					if (data.isDetached()) {
+						mustSendAsBinary = true;
+					}
+					data = data.getSource();
+				} else if (data instanceof FormData) {
+
+					if (data.hasBlob()) {
+						if (data.getBlob().isDetached()) {
+							data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state
+							mustSendAsBinary = true;
+						} else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) {
+							// Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
+							// Android browsers (default one and Dolphin) seem to have the same issue, see: #613
+							_preloadAndSend.call(target, meta, data);
+							return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D
+						}	
+					}
+
+					// transfer fields to real FormData
+					if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart()
+						var fd = new window.FormData();
+						data.each(function(value, name) {
+							if (value instanceof Blob) {
+								fd.append(name, value.getSource());
+							} else {
+								fd.append(name, value);
+							}
+						});
+						data = fd;
+					}
+				}
+
+
+				// if XHR L2
+				if (_xhr.upload) {
+					if (meta.withCredentials) {
+						_xhr.withCredentials = true;
+					}
+
+					_xhr.addEventListener('load', function(e) {
+						target.trigger(e);
+					});
+
+					_xhr.addEventListener('error', function(e) {
+						target.trigger(e);
+					});
+
+					// additionally listen to progress events
+					_xhr.addEventListener('progress', function(e) {
+						target.trigger(e);
+					});
+
+					_xhr.upload.addEventListener('progress', function(e) {
+						target.trigger({
+							type: 'UploadProgress',
+							loaded: e.loaded,
+							total: e.total
+						});
+					});
+				// ... otherwise simulate XHR L2
+				} else {
+					_xhr.onreadystatechange = function onReadyStateChange() {
+						
+						// fake Level 2 events
+						switch (_xhr.readyState) {
+							
+							case 1: // XMLHttpRequest.OPENED
+								// readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu
+								break;
+							
+							// looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu
+							case 2: // XMLHttpRequest.HEADERS_RECEIVED
+								break;
+								
+							case 3: // XMLHttpRequest.LOADING 
+								// try to fire progress event for not XHR L2
+								var total, loaded;
+								
+								try {
+									if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers
+										total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here
+									}
+
+									if (_xhr.responseText) { // responseText was introduced in IE7
+										loaded = _xhr.responseText.length;
+									}
+								} catch(ex) {
+									total = loaded = 0;
+								}
+
+								target.trigger({
+									type: 'progress',
+									lengthComputable: !!total,
+									total: parseInt(total, 10),
+									loaded: loaded
+								});
+								break;
+								
+							case 4: // XMLHttpRequest.DONE
+								// release readystatechange handler (mostly for IE)
+								_xhr.onreadystatechange = function() {};
+
+								// usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout
+								try {
+									if (_xhr.status >= 200 && _xhr.status < 400) {
+										target.trigger('load');
+										break;
+									}
+								} catch(ex) {}
+
+								target.trigger('error');
+								break;
+						}
+					};
+				}
+				
+
+				// set request headers
+				if (!Basic.isEmptyObj(meta.headers)) {
+					Basic.each(meta.headers, function(value, header) {
+						_xhr.setRequestHeader(header, value);
+					});
+				}
+
+				// request response type
+				if ("" !== meta.responseType && 'responseType' in _xhr) {
+					if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one
+						_xhr.responseType = 'text';
+					} else {
+						_xhr.responseType = meta.responseType;
+					}
+				}
+
+				// send ...
+				if (!mustSendAsBinary) {
+					_xhr.send(data);
+				} else {
+					if (_xhr.sendAsBinary) { // Gecko
+						_xhr.sendAsBinary(data);
+					} else { // other browsers having support for typed arrays
+						(function() {
+							// mimic Gecko's sendAsBinary
+							var ui8a = new Uint8Array(data.length);
+							for (var i = 0; i < data.length; i++) {
+								ui8a[i] = (data.charCodeAt(i) & 0xff);
+							}
+							_xhr.send(ui8a.buffer);
+						}());
+					}
+				}
+
+				target.trigger('loadstart');
+			},
+
+			getStatus: function() {
+				// according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception
+				try {
+					if (_xhr) {
+						return _xhr.status;
+					}
+				} catch(ex) {}
+				return 0;
+			},
+
+			getResponse: function(responseType) {
+				var I = this.getRuntime();
+
+				try {
+					switch (responseType) {
+						case 'blob':
+							var file = new File(I.uid, _xhr.response);
+							
+							// try to extract file name from content-disposition if possible (might be - not, if CORS for example)	
+							var disposition = _xhr.getResponseHeader('Content-Disposition');
+							if (disposition) {
+								// extract filename from response header if available
+								var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/);
+								if (match) {
+									_filename = match[2];
+								}
+							}
+							file.name = _filename;
+
+							// pre-webkit Opera doesn't set type property on the blob response
+							if (!file.type) {
+								file.type = Mime.getFileMime(_filename);
+							}
+							return file;
+
+						case 'json':
+							if (!Env.can('return_response_type', 'json')) {
+								return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null;
+							}
+							return _xhr.response;
+
+						case 'document':
+							return _getDocument(_xhr);
+
+						default:
+							return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes
+					}
+				} catch(ex) {
+					return null;
+				}				
+			},
+
+			getAllResponseHeaders: function() {
+				try {
+					return _xhr.getAllResponseHeaders();
+				} catch(ex) {}
+				return '';
+			},
+
+			abort: function() {
+				if (_xhr) {
+					_xhr.abort();
+				}
+			},
+
+			destroy: function() {
+				self = _filename = null;
+				this.getRuntime().getShim().removeInstance(this.uid);
+			}
+		});
+
+
+		// here we go... ugly fix for ugly bug
+		function _preloadAndSend(meta, data) {
+			var target = this, blob, fr;
+				
+			// get original blob
+			blob = data.getBlob().getSource();
+			
+			// preload blob in memory to be sent as binary string
+			fr = new window.FileReader();
+			fr.onload = function() {
+				// overwrite original blob
+				data.append(data.getBlobName(), new Blob(null, {
+					type: blob.type,
+					data: fr.result
+				}));
+				// invoke send operation again
+				self.send.call(target, meta, data);
+			};
+			fr.readAsBinaryString(blob);
+		}
+
+		
+		function _getNativeXHR() {
+			if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.verComp(Env.version, 8, '<'))) { // IE7 has native XHR but it's buggy
+				return new window.XMLHttpRequest();
+			} else {
+				return (function() {
+					var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0
+					for (var i = 0; i < progIDs.length; i++) {
+						try {
+							return new ActiveXObject(progIDs[i]);
+						} catch (ex) {}
+					}
+				})();
+			}
+		}
+		
+		// @credits Sergey Ilinsky	(http://www.ilinsky.com/)
+		function _getDocument(xhr) {
+			var rXML = xhr.responseXML;
+			var rText = xhr.responseText;
+			
+			// Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type)
+			if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) {
+				rXML = new window.ActiveXObject("Microsoft.XMLDOM");
+				rXML.async = false;
+				rXML.validateOnParse = false;
+				rXML.loadXML(rText);
+			}
+	
+			// Check if there is no error in document
+			if (rXML) {
+				if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") {
+					return null;
+				}
+			}
+			return rXML;
+		}
+
+
+		function _prepareMultipart(fd) {
+			var boundary = '----moxieboundary' + new Date().getTime()
+			, dashdash = '--'
+			, crlf = '\r\n'
+			, multipart = ''
+			, I = this.getRuntime()
+			;
+
+			if (!I.can('send_binary_string')) {
+				throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
+			}
+
+			_xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
+
+			// append multipart parameters
+			fd.each(function(value, name) {
+				// Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(), 
+				// so we try it here ourselves with: unescape(encodeURIComponent(value))
+				if (value instanceof Blob) {
+					// Build RFC2388 blob
+					multipart += dashdash + boundary + crlf +
+						'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf +
+						'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf +
+						value.getSource() + crlf;
+				} else {
+					multipart += dashdash + boundary + crlf +
+						'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf +
+						unescape(encodeURIComponent(value)) + crlf;
+				}
+			});
+
+			multipart += dashdash + boundary + dashdash + crlf;
+
+			return multipart;
+		}
+	}
+
+	return (extensions.XMLHttpRequest = XMLHttpRequest);
+});
+
+// Included from: src/javascript/runtime/html5/utils/BinaryReader.js
+
+/**
+ * BinaryReader.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/utils/BinaryReader
+@private
+*/
+define("moxie/runtime/html5/utils/BinaryReader", [
+	"moxie/core/utils/Basic"
+], function(Basic) {
+
+	
+	function BinaryReader(data) {
+		if (data instanceof ArrayBuffer) {
+			ArrayBufferReader.apply(this, arguments);
+		} else {
+			UTF16StringReader.apply(this, arguments);
+		}
+	}
+
+	Basic.extend(BinaryReader.prototype, {
+		
+		littleEndian: false,
+
+
+		read: function(idx, size) {
+			var sum, mv, i;
+
+			if (idx + size > this.length()) {
+				throw new Error("You are trying to read outside the source boundaries.");
+			}
+			
+			mv = this.littleEndian 
+				? 0 
+				: -8 * (size - 1)
+			;
+
+			for (i = 0, sum = 0; i < size; i++) {
+				sum |= (this.readByteAt(idx + i) << Math.abs(mv + i*8));
+			}
+			return sum;
+		},
+
+
+		write: function(idx, num, size) {
+			var mv, i, str = '';
+
+			if (idx > this.length()) {
+				throw new Error("You are trying to write outside the source boundaries.");
+			}
+
+			mv = this.littleEndian 
+				? 0 
+				: -8 * (size - 1)
+			;
+
+			for (i = 0; i < size; i++) {
+				this.writeByteAt(idx + i, (num >> Math.abs(mv + i*8)) & 255);
+			}
+		},
+
+
+		BYTE: function(idx) {
+			return this.read(idx, 1);
+		},
+
+
+		SHORT: function(idx) {
+			return this.read(idx, 2);
+		},
+
+
+		LONG: function(idx) {
+			return this.read(idx, 4);
+		},
+
+
+		SLONG: function(idx) { // 2's complement notation
+			var num = this.read(idx, 4);
+			return (num > 2147483647 ? num - 4294967296 : num);
+		},
+
+
+		CHAR: function(idx) {
+			return String.fromCharCode(this.read(idx, 1));
+		},
+
+
+		STRING: function(idx, count) {
+			return this.asArray('CHAR', idx, count).join('');
+		},
+
+
+		asArray: function(type, idx, count) {
+			var values = [];
+
+			for (var i = 0; i < count; i++) {
+				values[i] = this[type](idx + i);
+			}
+			return values;
+		}
+	});
+
+
+	function ArrayBufferReader(data) {
+		var _dv = new DataView(data);
+
+		Basic.extend(this, {
+			
+			readByteAt: function(idx) {
+				return _dv.getUint8(idx);
+			},
+
+
+			writeByteAt: function(idx, value) {
+				_dv.setUint8(idx, value);
+			},
+			
+
+			SEGMENT: function(idx, size, value) {
+				switch (arguments.length) {
+					case 2:
+						return data.slice(idx, idx + size);
+
+					case 1:
+						return data.slice(idx);
+
+					case 3:
+						if (value === null) {
+							value = new ArrayBuffer();
+						}
+
+						if (value instanceof ArrayBuffer) {					
+							var arr = new Uint8Array(this.length() - size + value.byteLength);
+							if (idx > 0) {
+								arr.set(new Uint8Array(data.slice(0, idx)), 0);
+							}
+							arr.set(new Uint8Array(value), idx);
+							arr.set(new Uint8Array(data.slice(idx + size)), idx + value.byteLength);
+
+							this.clear();
+							data = arr.buffer;
+							_dv = new DataView(data);
+							break;
+						}
+
+					default: return data;
+				}
+			},
+
+
+			length: function() {
+				return data ? data.byteLength : 0;
+			},
+
+
+			clear: function() {
+				_dv = data = null;
+			}
+		});
+	}
+
+
+	function UTF16StringReader(data) {
+		Basic.extend(this, {
+			
+			readByteAt: function(idx) {
+				return data.charCodeAt(idx);
+			},
+
+
+			writeByteAt: function(idx, value) {
+				putstr(String.fromCharCode(value), idx, 1);
+			},
+
+
+			SEGMENT: function(idx, length, segment) {
+				switch (arguments.length) {
+					case 1:
+						return data.substr(idx);
+					case 2:
+						return data.substr(idx, length);
+					case 3:
+						putstr(segment !== null ? segment : '', idx, length);
+						break;
+					default: return data;
+				}
+			},
+
+
+			length: function() {
+				return data ? data.length : 0;
+			}, 
+
+			clear: function() {
+				data = null;
+			}
+		});
+
+
+		function putstr(segment, idx, length) {
+			length = arguments.length === 3 ? length : data.length - idx - 1;
+			data = data.substr(0, idx) + segment + data.substr(length + idx);
+		}
+	}
+
+
+	return BinaryReader;
+});
+
+// Included from: src/javascript/runtime/html5/image/JPEGHeaders.js
+
+/**
+ * JPEGHeaders.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+ 
+/**
+@class moxie/runtime/html5/image/JPEGHeaders
+@private
+*/
+define("moxie/runtime/html5/image/JPEGHeaders", [
+	"moxie/runtime/html5/utils/BinaryReader",
+	"moxie/core/Exceptions"
+], function(BinaryReader, x) {
+	
+	return function JPEGHeaders(data) {
+		var headers = [], _br, idx, marker, length = 0;
+
+		_br = new BinaryReader(data);
+
+		// Check if data is jpeg
+		if (_br.SHORT(0) !== 0xFFD8) {
+			_br.clear();
+			throw new x.ImageError(x.ImageError.WRONG_FORMAT);
+		}
+
+		idx = 2;
+
+		while (idx <= _br.length()) {
+			marker = _br.SHORT(idx);
+
+			// omit RST (restart) markers
+			if (marker >= 0xFFD0 && marker <= 0xFFD7) {
+				idx += 2;
+				continue;
+			}
+
+			// no headers allowed after SOS marker
+			if (marker === 0xFFDA || marker === 0xFFD9) {
+				break;
+			}
+
+			length = _br.SHORT(idx + 2) + 2;
+
+			// APPn marker detected
+			if (marker >= 0xFFE1 && marker <= 0xFFEF) {
+				headers.push({
+					hex: marker,
+					name: 'APP' + (marker & 0x000F),
+					start: idx,
+					length: length,
+					segment: _br.SEGMENT(idx, length)
+				});
+			}
+
+			idx += length;
+		}
+
+		_br.clear();
+
+		return {
+			headers: headers,
+
+			restore: function(data) {
+				var max, i, br;
+
+				br = new BinaryReader(data);
+
+				idx = br.SHORT(2) == 0xFFE0 ? 4 + br.SHORT(4) : 2;
+
+				for (i = 0, max = headers.length; i < max; i++) {
+					br.SEGMENT(idx, 0, headers[i].segment);
+					idx += headers[i].length;
+				}
+
+				data = br.SEGMENT();
+				br.clear();
+				return data;
+			},
+
+			strip: function(data) {
+				var br, headers, jpegHeaders, i;
+
+				jpegHeaders = new JPEGHeaders(data);
+				headers = jpegHeaders.headers;
+				jpegHeaders.purge();
+
+				br = new BinaryReader(data);
+
+				i = headers.length;
+				while (i--) {
+					br.SEGMENT(headers[i].start, headers[i].length, '');
+				}
+				
+				data = br.SEGMENT();
+				br.clear();
+				return data;
+			},
+
+			get: function(name) {
+				var array = [];
+
+				for (var i = 0, max = headers.length; i < max; i++) {
+					if (headers[i].name === name.toUpperCase()) {
+						array.push(headers[i].segment);
+					}
+				}
+				return array;
+			},
+
+			set: function(name, segment) {
+				var array = [], i, ii, max;
+
+				if (typeof(segment) === 'string') {
+					array.push(segment);
+				} else {
+					array = segment;
+				}
+
+				for (i = ii = 0, max = headers.length; i < max; i++) {
+					if (headers[i].name === name.toUpperCase()) {
+						headers[i].segment = array[ii];
+						headers[i].length = array[ii].length;
+						ii++;
+					}
+					if (ii >= array.length) {
+						break;
+					}
+				}
+			},
+
+			purge: function() {
+				this.headers = headers = [];
+			}
+		};
+	};
+});
+
+// Included from: src/javascript/runtime/html5/image/ExifParser.js
+
+/**
+ * ExifParser.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/image/ExifParser
+@private
+*/
+define("moxie/runtime/html5/image/ExifParser", [
+	"moxie/core/utils/Basic",
+	"moxie/runtime/html5/utils/BinaryReader",
+	"moxie/core/Exceptions"
+], function(Basic, BinaryReader, x) {
+	
+	function ExifParser(data) {
+		var __super__, tags, tagDescs, offsets, idx, Tiff;
+		
+		BinaryReader.call(this, data);
+
+		tags = {
+			tiff: {
+				/*
+				The image orientation viewed in terms of rows and columns.
+
+				1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
+				2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
+				3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
+				4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
+				5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
+				6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
+				7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
+				8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
+				*/
+				0x0112: 'Orientation',
+				0x010E: 'ImageDescription',
+				0x010F: 'Make',
+				0x0110: 'Model',
+				0x0131: 'Software',
+				0x8769: 'ExifIFDPointer',
+				0x8825:	'GPSInfoIFDPointer'
+			},
+			exif: {
+				0x9000: 'ExifVersion',
+				0xA001: 'ColorSpace',
+				0xA002: 'PixelXDimension',
+				0xA003: 'PixelYDimension',
+				0x9003: 'DateTimeOriginal',
+				0x829A: 'ExposureTime',
+				0x829D: 'FNumber',
+				0x8827: 'ISOSpeedRatings',
+				0x9201: 'ShutterSpeedValue',
+				0x9202: 'ApertureValue'	,
+				0x9207: 'MeteringMode',
+				0x9208: 'LightSource',
+				0x9209: 'Flash',
+				0x920A: 'FocalLength',
+				0xA402: 'ExposureMode',
+				0xA403: 'WhiteBalance',
+				0xA406: 'SceneCaptureType',
+				0xA404: 'DigitalZoomRatio',
+				0xA408: 'Contrast',
+				0xA409: 'Saturation',
+				0xA40A: 'Sharpness'
+			},
+			gps: {
+				0x0000: 'GPSVersionID',
+				0x0001: 'GPSLatitudeRef',
+				0x0002: 'GPSLatitude',
+				0x0003: 'GPSLongitudeRef',
+				0x0004: 'GPSLongitude'
+			},
+
+			thumb: {
+				0x0201: 'JPEGInterchangeFormat',
+				0x0202: 'JPEGInterchangeFormatLength'
+			}
+		};
+
+		tagDescs = {
+			'ColorSpace': {
+				1: 'sRGB',
+				0: 'Uncalibrated'
+			},
+
+			'MeteringMode': {
+				0: 'Unknown',
+				1: 'Average',
+				2: 'CenterWeightedAverage',
+				3: 'Spot',
+				4: 'MultiSpot',
+				5: 'Pattern',
+				6: 'Partial',
+				255: 'Other'
+			},
+
+			'LightSource': {
+				1: 'Daylight',
+				2: 'Fliorescent',
+				3: 'Tungsten',
+				4: 'Flash',
+				9: 'Fine weather',
+				10: 'Cloudy weather',
+				11: 'Shade',
+				12: 'Daylight fluorescent (D 5700 - 7100K)',
+				13: 'Day white fluorescent (N 4600 -5400K)',
+				14: 'Cool white fluorescent (W 3900 - 4500K)',
+				15: 'White fluorescent (WW 3200 - 3700K)',
+				17: 'Standard light A',
+				18: 'Standard light B',
+				19: 'Standard light C',
+				20: 'D55',
+				21: 'D65',
+				22: 'D75',
+				23: 'D50',
+				24: 'ISO studio tungsten',
+				255: 'Other'
+			},
+
+			'Flash': {
+				0x0000: 'Flash did not fire',
+				0x0001: 'Flash fired',
+				0x0005: 'Strobe return light not detected',
+				0x0007: 'Strobe return light detected',
+				0x0009: 'Flash fired, compulsory flash mode',
+				0x000D: 'Flash fired, compulsory flash mode, return light not detected',
+				0x000F: 'Flash fired, compulsory flash mode, return light detected',
+				0x0010: 'Flash did not fire, compulsory flash mode',
+				0x0018: 'Flash did not fire, auto mode',
+				0x0019: 'Flash fired, auto mode',
+				0x001D: 'Flash fired, auto mode, return light not detected',
+				0x001F: 'Flash fired, auto mode, return light detected',
+				0x0020: 'No flash function',
+				0x0041: 'Flash fired, red-eye reduction mode',
+				0x0045: 'Flash fired, red-eye reduction mode, return light not detected',
+				0x0047: 'Flash fired, red-eye reduction mode, return light detected',
+				0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode',
+				0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
+				0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
+				0x0059: 'Flash fired, auto mode, red-eye reduction mode',
+				0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode',
+				0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode'
+			},
+
+			'ExposureMode': {
+				0: 'Auto exposure',
+				1: 'Manual exposure',
+				2: 'Auto bracket'
+			},
+
+			'WhiteBalance': {
+				0: 'Auto white balance',
+				1: 'Manual white balance'
+			},
+
+			'SceneCaptureType': {
+				0: 'Standard',
+				1: 'Landscape',
+				2: 'Portrait',
+				3: 'Night scene'
+			},
+
+			'Contrast': {
+				0: 'Normal',
+				1: 'Soft',
+				2: 'Hard'
+			},
+
+			'Saturation': {
+				0: 'Normal',
+				1: 'Low saturation',
+				2: 'High saturation'
+			},
+
+			'Sharpness': {
+				0: 'Normal',
+				1: 'Soft',
+				2: 'Hard'
+			},
+
+			// GPS related
+			'GPSLatitudeRef': {
+				N: 'North latitude',
+				S: 'South latitude'
+			},
+
+			'GPSLongitudeRef': {
+				E: 'East longitude',
+				W: 'West longitude'
+			}
+		};
+
+		offsets = {
+			tiffHeader: 10
+		};
+		
+		idx = offsets.tiffHeader;
+
+		__super__ = {
+			clear: this.clear
+		};
+
+		// Public functions
+		Basic.extend(this, {
+			
+			read: function() {
+				try {
+					return ExifParser.prototype.read.apply(this, arguments);
+				} catch (ex) {
+					throw new x.ImageError(x.ImageError.INVALID_META_ERR);
+				}
+			},
+
+
+			write: function() {
+				try {
+					return ExifParser.prototype.write.apply(this, arguments);
+				} catch (ex) {
+					throw new x.ImageError(x.ImageError.INVALID_META_ERR);
+				}
+			},
+
+
+			UNDEFINED: function() {
+				return this.BYTE.apply(this, arguments);
+			},
+
+
+			RATIONAL: function(idx) {
+				return this.LONG(idx) / this.LONG(idx + 4)
+			},
+
+
+			SRATIONAL: function(idx) {
+				return this.SLONG(idx) / this.SLONG(idx + 4)
+			},
+
+			ASCII: function(idx) {
+				return this.CHAR(idx);
+			},
+
+			TIFF: function() {
+				return Tiff || null;
+			},
+
+
+			EXIF: function() {
+				var Exif = null;
+
+				if (offsets.exifIFD) {
+					try {
+						Exif = extractTags.call(this, offsets.exifIFD, tags.exif);
+					} catch(ex) {
+						return null;
+					}
+
+					// Fix formatting of some tags
+					if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') {
+						for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) {
+							exifVersion += String.fromCharCode(Exif.ExifVersion[i]);
+						}
+						Exif.ExifVersion = exifVersion;
+					}
+				}
+
+				return Exif;
+			},
+
+
+			GPS: function() {
+				var GPS = null;
+
+				if (offsets.gpsIFD) {
+					try {
+						GPS = extractTags.call(this, offsets.gpsIFD, tags.gps);
+					} catch (ex) {
+						return null;
+					}
+
+					// iOS devices (and probably some others) do not put in GPSVersionID tag (why?..)
+					if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') {
+						GPS.GPSVersionID = GPS.GPSVersionID.join('.');
+					}
+				}
+
+				return GPS;
+			},
+
+
+			thumb: function() {
+				if (offsets.IFD1) {
+					try {
+						var IFD1Tags = extractTags.call(this, offsets.IFD1, tags.thumb);
+						
+						if ('JPEGInterchangeFormat' in IFD1Tags) {
+							return this.SEGMENT(offsets.tiffHeader + IFD1Tags.JPEGInterchangeFormat, IFD1Tags.JPEGInterchangeFormatLength);
+						}
+					} catch (ex) {}
+				}
+				return null;
+			},
+
+
+			setExif: function(tag, value) {
+				// Right now only setting of width/height is possible
+				if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') { return false; }
+
+				return setTag.call(this, 'exif', tag, value);
+			},
+
+
+			clear: function() {
+				__super__.clear();
+				data = tags = tagDescs = Tiff = offsets = __super__ = null;
+			}
+		});
+
+
+		// Check if that's APP1 and that it has EXIF
+		if (this.SHORT(0) !== 0xFFE1 || this.STRING(4, 5).toUpperCase() !== "EXIF\0") {
+			throw new x.ImageError(x.ImageError.INVALID_META_ERR);
+		}
+
+		// Set read order of multi-byte data
+		this.littleEndian = (this.SHORT(idx) == 0x4949);
+
+		// Check if always present bytes are indeed present
+		if (this.SHORT(idx+=2) !== 0x002A) {
+			throw new x.ImageError(x.ImageError.INVALID_META_ERR);
+		}
+
+		offsets.IFD0 = offsets.tiffHeader + this.LONG(idx += 2);
+		Tiff = extractTags.call(this, offsets.IFD0, tags.tiff);
+
+		if ('ExifIFDPointer' in Tiff) {
+			offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer;
+			delete Tiff.ExifIFDPointer;
+		}
+
+		if ('GPSInfoIFDPointer' in Tiff) {
+			offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer;
+			delete Tiff.GPSInfoIFDPointer;
+		}
+
+		if (Basic.isEmptyObj(Tiff)) {
+			Tiff = null;
+		}
+
+		// check if we have a thumb as well
+		var IFD1Offset = this.LONG(offsets.IFD0 + this.SHORT(offsets.IFD0) * 12 + 2);
+		if (IFD1Offset) {
+			offsets.IFD1 = offsets.tiffHeader + IFD1Offset;
+		}
+
+
+		function extractTags(IFD_offset, tags2extract) {
+			var data = this;
+			var length, i, tag, type, count, size, offset, value, values = [], hash = {};
+			
+			var types = {
+				1 : 'BYTE',
+				7 : 'UNDEFINED',
+				2 : 'ASCII',
+				3 : 'SHORT',
+				4 : 'LONG',
+				5 : 'RATIONAL',
+				9 : 'SLONG',
+				10: 'SRATIONAL'
+			};
+
+			var sizes = {
+				'BYTE' 		: 1,
+				'UNDEFINED'	: 1,
+				'ASCII'		: 1,
+				'SHORT'		: 2,
+				'LONG' 		: 4,
+				'RATIONAL' 	: 8,
+				'SLONG'		: 4,
+				'SRATIONAL'	: 8
+			};
+
+			length = data.SHORT(IFD_offset);
+
+			// The size of APP1 including all these elements shall not exceed the 64 Kbytes specified in the JPEG standard.
+
+			for (i = 0; i < length; i++) {
+				values = [];
+
+				// Set binary reader pointer to beginning of the next tag
+				offset = IFD_offset + 2 + i*12;
+
+				tag = tags2extract[data.SHORT(offset)];
+
+				if (tag === undefined) {
+					continue; // Not the tag we requested
+				}
+
+				type = types[data.SHORT(offset+=2)];
+				count = data.LONG(offset+=2);
+				size = sizes[type];
+
+				if (!size) {
+					throw new x.ImageError(x.ImageError.INVALID_META_ERR);
+				}
+
+				offset += 4;
+
+				// tag can only fit 4 bytes of data, if data is larger we should look outside
+				if (size * count > 4) {
+					// instead of data tag contains an offset of the data
+					offset = data.LONG(offset) + offsets.tiffHeader;
+				}
+
+				// in case we left the boundaries of data throw an early exception
+				if (offset + size * count >= this.length()) {
+					throw new x.ImageError(x.ImageError.INVALID_META_ERR);
+				} 
+
+				// special care for the string
+				if (type === 'ASCII') {
+					hash[tag] = Basic.trim(data.STRING(offset, count).replace(/\0$/, '')); // strip trailing NULL
+					continue;
+				} else {
+					values = data.asArray(type, offset, count);
+					value = (count == 1 ? values[0] : values);
+
+					if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') {
+						hash[tag] = tagDescs[tag][value];
+					} else {
+						hash[tag] = value;
+					}
+				}
+			}
+
+			return hash;
+		}
+
+		// At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported
+		function setTag(ifd, tag, value) {
+			var offset, length, tagOffset, valueOffset = 0;
+
+			// If tag name passed translate into hex key
+			if (typeof(tag) === 'string') {
+				var tmpTags = tags[ifd.toLowerCase()];
+				for (var hex in tmpTags) {
+					if (tmpTags[hex] === tag) {
+						tag = hex;
+						break;
+					}
+				}
+			}
+			offset = offsets[ifd.toLowerCase() + 'IFD'];
+			length = this.SHORT(offset);
+
+			for (var i = 0; i < length; i++) {
+				tagOffset = offset + 12 * i + 2;
+
+				if (this.SHORT(tagOffset) == tag) {
+					valueOffset = tagOffset + 8;
+					break;
+				}
+			}
+
+			if (!valueOffset) {
+				return false;
+			}
+
+			try {
+				this.write(valueOffset, value, 4);
+			} catch(ex) {
+				return false;
+			}
+
+			return true;
+		}
+	}
+
+	ExifParser.prototype = BinaryReader.prototype;
+
+	return ExifParser;
+});
+
+// Included from: src/javascript/runtime/html5/image/JPEG.js
+
+/**
+ * JPEG.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/image/JPEG
+@private
+*/
+define("moxie/runtime/html5/image/JPEG", [
+	"moxie/core/utils/Basic",
+	"moxie/core/Exceptions",
+	"moxie/runtime/html5/image/JPEGHeaders",
+	"moxie/runtime/html5/utils/BinaryReader",
+	"moxie/runtime/html5/image/ExifParser"
+], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) {
+	
+	function JPEG(data) {
+		var _br, _hm, _ep, _info;
+
+		_br = new BinaryReader(data);
+
+		// check if it is jpeg
+		if (_br.SHORT(0) !== 0xFFD8) {
+			throw new x.ImageError(x.ImageError.WRONG_FORMAT);
+		}
+
+		// backup headers
+		_hm = new JPEGHeaders(data);
+
+		// extract exif info
+		try {
+			_ep = new ExifParser(_hm.get('app1')[0]);
+		} catch(ex) {}
+
+		// get dimensions
+		_info = _getDimensions.call(this);
+
+		Basic.extend(this, {
+			type: 'image/jpeg',
+
+			size: _br.length(),
+
+			width: _info && _info.width || 0,
+
+			height: _info && _info.height || 0,
+
+			setExif: function(tag, value) {
+				if (!_ep) {
+					return false; // or throw an exception
+				}
+
+				if (Basic.typeOf(tag) === 'object') {
+					Basic.each(tag, function(value, tag) {
+						_ep.setExif(tag, value);
+					});
+				} else {
+					_ep.setExif(tag, value);
+				}
+
+				// update internal headers
+				_hm.set('app1', _ep.SEGMENT());
+			},
+
+			writeHeaders: function() {
+				if (!arguments.length) {
+					// if no arguments passed, update headers internally
+					return _hm.restore(data);
+				}
+				return _hm.restore(arguments[0]);
+			},
+
+			stripHeaders: function(data) {
+				return _hm.strip(data);
+			},
+
+			purge: function() {
+				_purge.call(this);
+			}
+		});
+
+		if (_ep) {
+			this.meta = {
+				tiff: _ep.TIFF(),
+				exif: _ep.EXIF(),
+				gps: _ep.GPS(),
+				thumb: _getThumb()
+			};
+		}
+
+
+		function _getDimensions(br) {
+			var idx = 0
+			, marker
+			, length
+			;
+
+			if (!br) {
+				br = _br;
+			}
+
+			// examine all through the end, since some images might have very large APP segments
+			while (idx <= br.length()) {
+				marker = br.SHORT(idx += 2);
+
+				if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn
+					idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte)
+					return {
+						height: br.SHORT(idx),
+						width: br.SHORT(idx += 2)
+					};
+				}
+				length = br.SHORT(idx += 2);
+				idx += length - 2;
+			}
+			return null;
+		}
+
+
+		function _getThumb() {
+			var data =  _ep.thumb()
+			, br
+			, info
+			;
+
+			if (data) {
+				br = new BinaryReader(data);
+				info = _getDimensions(br);
+				br.clear();
+
+				if (info) {
+					info.data = data;
+					return info;
+				}
+			}
+			return null;
+		}
+
+
+		function _purge() {
+			if (!_ep || !_hm || !_br) { 
+				return; // ignore any repeating purge requests
+			}
+			_ep.clear();
+			_hm.purge();
+			_br.clear();
+			_info = _hm = _ep = _br = null;
+		}
+	}
+
+	return JPEG;
+});
+
+// Included from: src/javascript/runtime/html5/image/PNG.js
+
+/**
+ * PNG.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/image/PNG
+@private
+*/
+define("moxie/runtime/html5/image/PNG", [
+	"moxie/core/Exceptions",
+	"moxie/core/utils/Basic",
+	"moxie/runtime/html5/utils/BinaryReader"
+], function(x, Basic, BinaryReader) {
+	
+	function PNG(data) {
+		var _br, _hm, _ep, _info;
+
+		_br = new BinaryReader(data);
+
+		// check if it's png
+		(function() {
+			var idx = 0, i = 0
+			, signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A]
+			;
+
+			for (i = 0; i < signature.length; i++, idx += 2) {
+				if (signature[i] != _br.SHORT(idx)) {
+					throw new x.ImageError(x.ImageError.WRONG_FORMAT);
+				}
+			}
+		}());
+
+		function _getDimensions() {
+			var chunk, idx;
+
+			chunk = _getChunkAt.call(this, 8);
+
+			if (chunk.type == 'IHDR') {
+				idx = chunk.start;
+				return {
+					width: _br.LONG(idx),
+					height: _br.LONG(idx += 4)
+				};
+			}
+			return null;
+		}
+
+		function _purge() {
+			if (!_br) {
+				return; // ignore any repeating purge requests
+			}
+			_br.clear();
+			data = _info = _hm = _ep = _br = null;
+		}
+
+		_info = _getDimensions.call(this);
+
+		Basic.extend(this, {
+			type: 'image/png',
+
+			size: _br.length(),
+
+			width: _info.width,
+
+			height: _info.height,
+
+			purge: function() {
+				_purge.call(this);
+			}
+		});
+
+		// for PNG we can safely trigger purge automatically, as we do not keep any data for later
+		_purge.call(this);
+
+		function _getChunkAt(idx) {
+			var length, type, start, CRC;
+
+			length = _br.LONG(idx);
+			type = _br.STRING(idx += 4, 4);
+			start = idx += 4;
+			CRC = _br.LONG(idx + length);
+
+			return {
+				length: length,
+				type: type,
+				start: start,
+				CRC: CRC
+			};
+		}
+	}
+
+	return PNG;
+});
+
+// Included from: src/javascript/runtime/html5/image/ImageInfo.js
+
+/**
+ * ImageInfo.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+Optional image investigation tool for HTML5 runtime. Provides the following features:
+- ability to distinguish image type (JPEG or PNG) by signature
+- ability to extract image width/height directly from it's internals, without preloading in memory (fast)
+- ability to extract APP headers from JPEGs (Exif, GPS, etc)
+- ability to replace width/height tags in extracted JPEG headers
+- ability to restore APP headers, that were for example stripped during image manipulation
+
+@class moxie/runtime/html5/image/ImageInfo
+@private
+@param {String} data Image source as binary string
+*/
+define("moxie/runtime/html5/image/ImageInfo", [
+	"moxie/core/utils/Basic",
+	"moxie/core/Exceptions",
+	"moxie/runtime/html5/image/JPEG",
+	"moxie/runtime/html5/image/PNG"
+], function(Basic, x, JPEG, PNG) {
+
+	return function(data) {
+		var _cs = [JPEG, PNG], _img;
+
+		// figure out the format, throw: ImageError.WRONG_FORMAT if not supported
+		_img = (function() {
+			for (var i = 0; i < _cs.length; i++) {
+				try {
+					return new _cs[i](data);
+				} catch (ex) {
+					// console.info(ex);
+				}
+			}
+			throw new x.ImageError(x.ImageError.WRONG_FORMAT);
+		}());
+
+		Basic.extend(this, {
+			/**
+			Image Mime Type extracted from it's depths
+
+			@property type
+			@type {String}
+			@default ''
+			*/
+			type: '',
+
+			/**
+			Image size in bytes
+
+			@property size
+			@type {Number}
+			@default 0
+			*/
+			size: 0,
+
+			/**
+			Image width extracted from image source
+
+			@property width
+			@type {Number}
+			@default 0
+			*/
+			width: 0,
+
+			/**
+			Image height extracted from image source
+
+			@property height
+			@type {Number}
+			@default 0
+			*/
+			height: 0,
+
+			/**
+			Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs.
+
+			@method setExif
+			@param {String} tag Tag to set
+			@param {Mixed} value Value to assign to the tag
+			*/
+			setExif: function() {},
+
+			/**
+			Restores headers to the source.
+
+			@method writeHeaders
+			@param {String} data Image source as binary string
+			@return {String} Updated binary string
+			*/
+			writeHeaders: function(data) {
+				return data;
+			},
+
+			/**
+			Strip all headers from the source.
+
+			@method stripHeaders
+			@param {String} data Image source as binary string
+			@return {String} Updated binary string
+			*/
+			stripHeaders: function(data) {
+				return data;
+			},
+
+			/**
+			Dispose resources.
+
+			@method purge
+			*/
+			purge: function() {
+				data = null;
+			}
+		});
+
+		Basic.extend(this, _img);
+
+		this.purge = function() {
+			_img.purge();
+			_img = null;
+		};
+	};
+});
+
+// Included from: src/javascript/runtime/html5/image/ResizerCanvas.js
+
+/**
+ * ResizerCanvas.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+ * Resizes image/canvas using canvas
+ */
+define("moxie/runtime/html5/image/ResizerCanvas", [], function() {
+
+    function scale(image, ratio, resample) {
+        var sD = image.width > image.height ? 'width' : 'height'; // take the largest side
+        var dD = Math.round(image[sD] * ratio);
+        var scaleCapped = false;
+
+        if (resample !== 'nearest' && (ratio < 0.5 || ratio > 2)) {
+            ratio = ratio < 0.5 ? 0.5 : 2;
+            scaleCapped = true;
+        }
+
+        var tCanvas = _scale(image, ratio);
+
+        if (scaleCapped) {
+            return scale(tCanvas, dD / tCanvas[sD], resample);
+        } else {
+            return tCanvas;
+        }
+    }
+
+
+    function _scale(image, ratio) {
+        var sW = image.width;
+        var sH = image.height;
+        var dW = Math.round(sW * ratio);
+        var dH = Math.round(sH * ratio);
+
+        var canvas = document.createElement('canvas');
+        canvas.width = dW;
+        canvas.height = dH;
+        canvas.getContext("2d").drawImage(image, 0, 0, sW, sH, 0, 0, dW, dH);
+
+        image = null; // just in case
+        return canvas;
+    }
+
+    return {
+        scale: scale
+    };
+
+});
+
+// Included from: src/javascript/runtime/html5/image/Image.js
+
+/**
+ * Image.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html5/image/Image
+@private
+*/
+define("moxie/runtime/html5/image/Image", [
+	"moxie/runtime/html5/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/core/Exceptions",
+	"moxie/core/utils/Encode",
+	"moxie/file/Blob",
+	"moxie/file/File",
+	"moxie/runtime/html5/image/ImageInfo",
+	"moxie/runtime/html5/image/ResizerCanvas",
+	"moxie/core/utils/Mime",
+	"moxie/core/utils/Env"
+], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, ResizerCanvas, Mime, Env) {
+
+	function HTML5Image() {
+		var me = this
+		, _img, _imgInfo, _canvas, _binStr, _blob
+		, _modified = false // is set true whenever image is modified
+		, _preserveHeaders = true
+		;
+
+		Basic.extend(this, {
+			loadFromBlob: function(blob) {
+				var I = this.getRuntime()
+				, asBinary = arguments.length > 1 ? arguments[1] : true
+				;
+
+				if (!I.can('access_binary')) {
+					throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
+				}
+
+				_blob = blob;
+
+				if (blob.isDetached()) {
+					_binStr = blob.getSource();
+					_preload.call(this, _binStr);
+					return;
+				} else {
+					_readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
+						if (asBinary) {
+							_binStr = _toBinary(dataUrl);
+						}
+						_preload.call(this, dataUrl);
+					});
+				}
+			},
+
+			loadFromImage: function(img, exact) {
+				this.meta = img.meta;
+
+				_blob = new File(null, {
+					name: img.name,
+					size: img.size,
+					type: img.type
+				});
+
+				_preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
+			},
+
+			getInfo: function() {
+				var I = this.getRuntime(), info;
+
+				if (!_imgInfo && _binStr && I.can('access_image_binary')) {
+					_imgInfo = new ImageInfo(_binStr);
+				}
+
+				// this stuff below is definitely having fun with itself
+				info = {
+					width: _getImg().width || 0,
+					height: _getImg().height || 0,
+					type: _blob.type || Mime.getFileMime(_blob.name),
+					size: _binStr && _binStr.length || _blob.size || 0,
+					name: _blob.name || '',
+					meta: null
+				};
+
+				if (_preserveHeaders) {
+					info.meta = _imgInfo && _imgInfo.meta || this.meta || {};
+
+					// if data was taken from ImageInfo it will be a binary string, so we convert it to blob
+					if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) {
+						info.meta.thumb.data = new Blob(null, {
+							type: 'image/jpeg',
+							data: info.meta.thumb.data
+						});
+					}
+				}
+
+				return info;
+			},
+
+
+			resize: function(rect, ratio, options) {
+				var canvas = document.createElement('canvas');
+				canvas.width = rect.width;
+				canvas.height = rect.height;
+
+				canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height);
+
+				_canvas = ResizerCanvas.scale(canvas, ratio);
+
+				_preserveHeaders = options.preserveHeaders;
+
+				// rotate if required, according to orientation tag
+				if (!_preserveHeaders) {
+					var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
+					_canvas = _rotateToOrientaion(_canvas, orientation);
+				}
+
+				this.width = _canvas.width;
+				this.height = _canvas.height;
+
+				_modified = true;
+
+				this.trigger('Resize');
+			},
+
+			getAsCanvas: function() {
+				if (!_canvas) {
+					_canvas = _getCanvas();
+				}
+				_canvas.id = this.uid + '_canvas';
+				return _canvas;
+			},
+
+			getAsBlob: function(type, quality) {
+				if (type !== this.type) {
+					_modified = true; // reconsider the state
+					return new File(null, {
+						name: _blob.name || '',
+						type: type,
+						data: me.getAsDataURL(type, quality)
+					});
+				}
+				return new File(null, {
+					name: _blob.name || '',
+					type: type,
+					data: me.getAsBinaryString(type, quality)
+				});
+			},
+
+			getAsDataURL: function(type) {
+				var quality = arguments[1] || 90;
+
+				// if image has not been modified, return the source right away
+				if (!_modified) {
+					return _img.src;
+				}
+
+				// make sure we have a canvas to work with
+				_getCanvas();
+
+				if ('image/jpeg' !== type) {
+					return _canvas.toDataURL('image/png');
+				} else {
+					try {
+						// older Geckos used to result in an exception on quality argument
+						return _canvas.toDataURL('image/jpeg', quality/100);
+					} catch (ex) {
+						return _canvas.toDataURL('image/jpeg');
+					}
+				}
+			},
+
+			getAsBinaryString: function(type, quality) {
+				// if image has not been modified, return the source right away
+				if (!_modified) {
+					// if image was not loaded from binary string
+					if (!_binStr) {
+						_binStr = _toBinary(me.getAsDataURL(type, quality));
+					}
+					return _binStr;
+				}
+
+				if ('image/jpeg' !== type) {
+					_binStr = _toBinary(me.getAsDataURL(type, quality));
+				} else {
+					var dataUrl;
+
+					// if jpeg
+					if (!quality) {
+						quality = 90;
+					}
+
+					// make sure we have a canvas to work with
+					_getCanvas();
+
+					try {
+						// older Geckos used to result in an exception on quality argument
+						dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
+					} catch (ex) {
+						dataUrl = _canvas.toDataURL('image/jpeg');
+					}
+
+					_binStr = _toBinary(dataUrl);
+
+					if (_imgInfo) {
+						_binStr = _imgInfo.stripHeaders(_binStr);
+
+						if (_preserveHeaders) {
+							// update dimensions info in exif
+							if (_imgInfo.meta && _imgInfo.meta.exif) {
+								_imgInfo.setExif({
+									PixelXDimension: this.width,
+									PixelYDimension: this.height
+								});
+							}
+
+							// re-inject the headers
+							_binStr = _imgInfo.writeHeaders(_binStr);
+						}
+
+						// will be re-created from fresh on next getInfo call
+						_imgInfo.purge();
+						_imgInfo = null;
+					}
+				}
+
+				_modified = false;
+
+				return _binStr;
+			},
+
+			destroy: function() {
+				me = null;
+				_purge.call(this);
+				this.getRuntime().getShim().removeInstance(this.uid);
+			}
+		});
+
+
+		function _getImg() {
+			if (!_canvas && !_img) {
+				throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
+			}
+			return _canvas || _img;
+		}
+
+
+		function _getCanvas() {
+			var canvas = _getImg();
+			if (canvas.nodeName.toLowerCase() == 'canvas') {
+				return canvas;
+			}
+			_canvas = document.createElement('canvas');
+			_canvas.width = canvas.width;
+			_canvas.height = canvas.height;
+			_canvas.getContext("2d").drawImage(canvas, 0, 0);
+			return _canvas;
+		}
+
+
+		function _toBinary(str) {
+			return Encode.atob(str.substring(str.indexOf('base64,') + 7));
+		}
+
+
+		function _toDataUrl(str, type) {
+			return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
+		}
+
+
+		function _preload(str) {
+			var comp = this;
+
+			_img = new Image();
+			_img.onerror = function() {
+				_purge.call(this);
+				comp.trigger('error', x.ImageError.WRONG_FORMAT);
+			};
+			_img.onload = function() {
+				comp.trigger('load');
+			};
+
+			_img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
+		}
+
+
+		function _readAsDataUrl(file, callback) {
+			var comp = this, fr;
+
+			// use FileReader if it's available
+			if (window.FileReader) {
+				fr = new FileReader();
+				fr.onload = function() {
+					callback.call(comp, this.result);
+				};
+				fr.onerror = function() {
+					comp.trigger('error', x.ImageError.WRONG_FORMAT);
+				};
+				fr.readAsDataURL(file);
+			} else {
+				return callback.call(this, file.getAsDataURL());
+			}
+		}
+
+		/**
+		* Transform canvas coordination according to specified frame size and orientation
+		* Orientation value is from EXIF tag
+		* @author Shinichi Tomita <shinichi.tomita@gmail.com>
+		*/
+		function _rotateToOrientaion(img, orientation) {
+			var RADIANS = Math.PI/180;
+			var canvas = document.createElement('canvas');
+			var ctx = canvas.getContext('2d');
+			var width = img.width;
+			var height = img.height;
+
+			if (Basic.inArray(orientation, [5,6,7,8]) > -1) {
+				canvas.width = height;
+				canvas.height = width;
+			} else {
+				canvas.width = width;
+				canvas.height = height;
+			}
+
+			/**
+			1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
+			2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
+			3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
+			4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
+			5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
+			6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
+			7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
+			8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
+			*/
+			switch (orientation) {
+				case 2:
+					// horizontal flip
+					ctx.translate(width, 0);
+					ctx.scale(-1, 1);
+					break;
+				case 3:
+					// 180 rotate left
+					ctx.translate(width, height);
+					ctx.rotate(180 * RADIANS);
+					break;
+				case 4:
+					// vertical flip
+					ctx.translate(0, height);
+					ctx.scale(1, -1);
+					break;
+				case 5:
+					// vertical flip + 90 rotate right
+					ctx.rotate(90 * RADIANS);
+					ctx.scale(1, -1);
+					break;
+				case 6:
+					// 90 rotate right
+					ctx.rotate(90 * RADIANS);
+					ctx.translate(0, -height);
+					break;
+				case 7:
+					// horizontal flip + 90 rotate right
+					ctx.rotate(90 * RADIANS);
+					ctx.translate(width, -height);
+					ctx.scale(-1, 1);
+					break;
+				case 8:
+					// 90 rotate left
+					ctx.rotate(-90 * RADIANS);
+					ctx.translate(-width, 0);
+					break;
+			}
+
+			ctx.drawImage(img, 0, 0, width, height);
+			return canvas;
+		}
+
+
+		function _purge() {
+			if (_imgInfo) {
+				_imgInfo.purge();
+				_imgInfo = null;
+			}
+
+			_binStr = _img = _canvas = _blob = null;
+			_modified = false;
+		}
+	}
+
+	return (extensions.Image = HTML5Image);
+});
+
+// Included from: src/javascript/runtime/flash/Runtime.js
+
+/**
+ * Runtime.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/*global ActiveXObject:true */
+
+/**
+Defines constructor for Flash runtime.
+
+@class moxie/runtime/flash/Runtime
+@private
+*/
+define("moxie/runtime/flash/Runtime", [
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Env",
+	"moxie/core/utils/Dom",
+	"moxie/core/Exceptions",
+	"moxie/runtime/Runtime"
+], function(Basic, Env, Dom, x, Runtime) {
+	
+	var type = 'flash', extensions = {};
+
+	/**
+	Get the version of the Flash Player
+
+	@method getShimVersion
+	@private
+	@return {Number} Flash Player version
+	*/
+	function getShimVersion() {
+		var version;
+
+		try {
+			version = navigator.plugins['Shockwave Flash'];
+			version = version.description;
+		} catch (e1) {
+			try {
+				version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
+			} catch (e2) {
+				version = '0.0';
+			}
+		}
+		version = version.match(/\d+/g);
+		return parseFloat(version[0] + '.' + version[1]);
+	}
+
+
+	/**
+	Cross-browser SWF removal
+    	- Especially needed to safely and completely remove a SWF in Internet Explorer
+
+   	Originated from SWFObject v2.2 <http://code.google.com/p/swfobject/> 
+	*/
+	function removeSWF(id) {
+        var obj = Dom.get(id);
+        if (obj && obj.nodeName == "OBJECT") {
+            if (Env.browser === 'IE') {
+                obj.style.display = "none";
+                (function onInit(){
+                	// http://msdn.microsoft.com/en-us/library/ie/ms534360(v=vs.85).aspx
+                    if (obj.readyState == 4) {
+                        removeObjectInIE(id);
+                    }
+                    else {
+                        setTimeout(onInit, 10);
+                    }
+                })();
+            }
+            else {
+                obj.parentNode.removeChild(obj);
+            }
+        }
+    }
+
+
+	function removeObjectInIE(id) {
+        var obj = Dom.get(id);
+        if (obj) {
+            for (var i in obj) {
+                if (typeof obj[i] == "function") {
+                    obj[i] = null;
+                }
+            }
+            obj.parentNode.removeChild(obj);
+        }
+    }
+
+	/**
+	Constructor for the Flash Runtime
+	*/
+	function FlashRuntime(options) {
+		var I = this, initTimer;
+
+		options = Basic.extend({ swf_url: Env.swf_url }, options);
+
+		Runtime.call(this, options, type, {
+			access_binary: function(value) {
+				return value && I.mode === 'browser';
+			},
+			access_image_binary: function(value) {
+				return value && I.mode === 'browser';
+			},
+			display_media: Runtime.capTest(defined('moxie/image/Image')),
+			do_cors: Runtime.capTrue,
+			drag_and_drop: false,
+			report_upload_progress: function() {
+				return I.mode === 'client';
+			},
+			resize_image: Runtime.capTrue,
+			return_response_headers: false,
+			return_response_type: function(responseType) {
+				if (responseType === 'json' && !!window.JSON) {
+					return true;
+				} 
+				return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser';
+			},
+			return_status_code: function(code) {
+				return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]);
+			},
+			select_file: Runtime.capTrue,
+			select_multiple: Runtime.capTrue,
+			send_binary_string: function(value) {
+				return value && I.mode === 'browser';
+			},
+			send_browser_cookies: function(value) {
+				return value && I.mode === 'browser';
+			},
+			send_custom_headers: function(value) {
+				return value && I.mode === 'browser';
+			},
+			send_multipart: Runtime.capTrue,
+			slice_blob: function(value) {
+				return value && I.mode === 'browser';
+			},
+			stream_upload: function(value) {
+				return value && I.mode === 'browser';
+			},
+			summon_file_dialog: false,
+			upload_filesize: function(size) {
+				return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client';
+			},
+			use_http_method: function(methods) {
+				return !Basic.arrayDiff(methods, ['GET', 'POST']);
+			}
+		}, { 
+			// capabilities that require specific mode
+			access_binary: function(value) {
+				return value ? 'browser' : 'client';
+			},
+			access_image_binary: function(value) {
+				return value ? 'browser' : 'client';
+			},
+			report_upload_progress: function(value) {
+				return value ? 'browser' : 'client';
+			},
+			return_response_type: function(responseType) {
+				return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser'];
+			},
+			return_status_code: function(code) {
+				return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser'];
+			},
+			send_binary_string: function(value) {
+				return value ? 'browser' : 'client';
+			},
+			send_browser_cookies: function(value) {
+				return value ? 'browser' : 'client';
+			},
+			send_custom_headers: function(value) {
+				return value ? 'browser' : 'client';
+			},
+			slice_blob: function(value) {
+				return value ? 'browser' : 'client';
+			},
+			stream_upload: function(value) {
+				return value ? 'client' : 'browser';
+			},
+			upload_filesize: function(size) {
+				return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser';
+			}
+		}, 'client');
+
+
+		// minimal requirement for Flash Player version
+		if (getShimVersion() < 11.3) {
+			if (MXI_DEBUG && Env.debug.runtime) {
+				Env.log("\tFlash didn't meet minimal version requirement (11.3).");	
+			}
+
+			this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before
+		}
+
+
+		Basic.extend(this, {
+
+			getShim: function() {
+				return Dom.get(this.uid);
+			},
+
+			shimExec: function(component, action) {
+				var args = [].slice.call(arguments, 2);
+				return I.getShim().exec(this.uid, component, action, args);
+			},
+
+			init: function() {
+				var html, el, container;
+
+				container = this.getShimContainer();
+
+				// if not the minimal height, shims are not initialized in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)
+				Basic.extend(container.style, {
+					position: 'absolute',
+					top: '-8px',
+					left: '-8px',
+					width: '9px',
+					height: '9px',
+					overflow: 'hidden'
+				});
+
+				// insert flash object
+				html = '<object id="' + this.uid + '" type="application/x-shockwave-flash" data="' +  options.swf_url + '" ';
+
+				if (Env.browser === 'IE') {
+					html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
+				}
+
+				html += 'width="100%" height="100%" style="outline:0">'  +
+					'<param name="movie" value="' + options.swf_url + '" />' +
+					'<param name="flashvars" value="uid=' + escape(this.uid) + '&target=' + Runtime.getGlobalEventTarget() + '" />' +
+					'<param name="wmode" value="transparent" />' +
+					'<param name="allowscriptaccess" value="always" />' +
+				'</object>';
+
+				if (Env.browser === 'IE') {
+					el = document.createElement('div');
+					container.appendChild(el);
+					el.outerHTML = html;
+					el = container = null; // just in case
+				} else {
+					container.innerHTML = html;
+				}
+
+				// Init is dispatched by the shim
+				initTimer = setTimeout(function() {
+					if (I && !I.initialized) { // runtime might be already destroyed by this moment
+						I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
+
+						if (MXI_DEBUG && Env.debug.runtime) {
+							Env.log("\tFlash failed to initialize within a specified period of time (typically 5s).");	
+						}
+					}
+				}, 5000);
+			},
+
+			destroy: (function(destroy) { // extend default destroy method
+				return function() {
+					removeSWF(I.uid); // SWF removal requires special care in IE
+
+					destroy.call(I);
+					clearTimeout(initTimer); // initialization check might be still onwait
+					options = initTimer = destroy = I = null;
+				};
+			}(this.destroy))
+
+		}, extensions);
+	}
+
+	Runtime.addConstructor(type, FlashRuntime);
+
+	return extensions;
+});
+
+// Included from: src/javascript/runtime/flash/file/Blob.js
+
+/**
+ * Blob.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/flash/file/Blob
+@private
+*/
+define("moxie/runtime/flash/file/Blob", [
+	"moxie/runtime/flash/Runtime",
+	"moxie/file/Blob"
+], function(extensions, Blob) {
+
+	var FlashBlob = {
+		slice: function(blob, start, end, type) {
+			var self = this.getRuntime();
+
+			if (start < 0) {
+				start = Math.max(blob.size + start, 0);
+			} else if (start > 0) {
+				start = Math.min(start, blob.size);
+			}
+
+			if (end < 0) {
+				end = Math.max(blob.size + end, 0);
+			} else if (end > 0) {
+				end = Math.min(end, blob.size);
+			}
+
+			blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || '');
+
+			if (blob) {
+				blob = new Blob(self.uid, blob);
+			}
+			return blob;
+		}
+	};
+
+	return (extensions.Blob = FlashBlob);
+});
+
+// Included from: src/javascript/runtime/flash/file/FileInput.js
+
+/**
+ * FileInput.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/flash/file/FileInput
+@private
+*/
+define("moxie/runtime/flash/file/FileInput", [
+	"moxie/runtime/flash/Runtime",
+	"moxie/file/File",
+	"moxie/core/utils/Dom",
+	"moxie/core/utils/Basic"
+], function(extensions, File, Dom, Basic) {
+
+	var FileInput = {
+		init: function(options) {
+			var comp = this, I = this.getRuntime();
+			var browseButton = Dom.get(options.browse_button);
+
+			if (browseButton) {
+				browseButton.setAttribute('tabindex', -1);
+				browseButton = null;
+			}
+
+			this.bind("Change", function() {
+				var files = I.shimExec.call(comp, 'FileInput', 'getFiles');
+				comp.files = [];
+				Basic.each(files, function(file) {
+					comp.files.push(new File(I.uid, file));
+				});
+			}, 999);
+
+			this.getRuntime().shimExec.call(this, 'FileInput', 'init', {
+				accept: options.accept,
+				multiple: options.multiple
+			});
+
+			this.trigger('ready');
+		}
+	};
+
+	return (extensions.FileInput = FileInput);
+});
+
+// Included from: src/javascript/runtime/flash/file/FileReader.js
+
+/**
+ * FileReader.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/flash/file/FileReader
+@private
+*/
+define("moxie/runtime/flash/file/FileReader", [
+	"moxie/runtime/flash/Runtime",
+	"moxie/core/utils/Encode"
+], function(extensions, Encode) {
+
+	function _formatData(data, op) {
+		switch (op) {
+			case 'readAsText':
+				return Encode.atob(data, 'utf8');
+			case 'readAsBinaryString':
+				return Encode.atob(data);
+			case 'readAsDataURL':
+				return data;
+		}
+		return null;
+	}
+
+	var FileReader = {
+		read: function(op, blob) {
+			var comp = this;
+
+			comp.result = '';
+
+			// special prefix for DataURL read mode
+			if (op === 'readAsDataURL') {
+				comp.result = 'data:' + (blob.type || '') + ';base64,';
+			}
+
+			comp.bind('Progress', function(e, data) {
+				if (data) {
+					comp.result += _formatData(data, op);
+				}
+			}, 999);
+
+			return comp.getRuntime().shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid);
+		}
+	};
+
+	return (extensions.FileReader = FileReader);
+});
+
+// Included from: src/javascript/runtime/flash/file/FileReaderSync.js
+
+/**
+ * FileReaderSync.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/flash/file/FileReaderSync
+@private
+*/
+define("moxie/runtime/flash/file/FileReaderSync", [
+	"moxie/runtime/flash/Runtime",
+	"moxie/core/utils/Encode"
+], function(extensions, Encode) {
+	
+	function _formatData(data, op) {
+		switch (op) {
+			case 'readAsText':
+				return Encode.atob(data, 'utf8');
+			case 'readAsBinaryString':
+				return Encode.atob(data);
+			case 'readAsDataURL':
+				return data;
+		}
+		return null;
+	}
+
+	var FileReaderSync = {
+		read: function(op, blob) {
+			var result, self = this.getRuntime();
+
+			result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid);
+			if (!result) {
+				return null; // or throw ex
+			}
+
+			// special prefix for DataURL read mode
+			if (op === 'readAsDataURL') {
+				result = 'data:' + (blob.type || '') + ';base64,' + result;
+			}
+
+			return _formatData(result, op, blob.type);
+		}
+	};
+
+	return (extensions.FileReaderSync = FileReaderSync);
+});
+
+// Included from: src/javascript/runtime/flash/runtime/Transporter.js
+
+/**
+ * Transporter.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/flash/runtime/Transporter
+@private
+*/
+define("moxie/runtime/flash/runtime/Transporter", [
+	"moxie/runtime/flash/Runtime",
+	"moxie/file/Blob"
+], function(extensions, Blob) {
+
+	var Transporter = {
+		getAsBlob: function(type) {
+			var self = this.getRuntime()
+			, blob = self.shimExec.call(this, 'Transporter', 'getAsBlob', type)
+			;
+			if (blob) {
+				return new Blob(self.uid, blob);
+			}
+			return null;
+		}
+	};
+
+	return (extensions.Transporter = Transporter);
+});
+
+// Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js
+
+/**
+ * XMLHttpRequest.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/flash/xhr/XMLHttpRequest
+@private
+*/
+define("moxie/runtime/flash/xhr/XMLHttpRequest", [
+	"moxie/runtime/flash/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/file/Blob",
+	"moxie/file/File",
+	"moxie/file/FileReaderSync",
+	"moxie/runtime/flash/file/FileReaderSync",
+	"moxie/xhr/FormData",
+	"moxie/runtime/Transporter",
+	"moxie/runtime/flash/runtime/Transporter"
+], function(extensions, Basic, Blob, File, FileReaderSync, FileReaderSyncFlash, FormData, Transporter, TransporterFlash) {
+	
+	var XMLHttpRequest = {
+
+		send: function(meta, data) {
+			var target = this, self = target.getRuntime();
+
+			function send() {
+				meta.transport = self.mode;
+				self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data);
+			}
+
+
+			function appendBlob(name, blob) {
+				self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid);
+				data = null;
+				send();
+			}
+
+
+			function attachBlob(blob, cb) {
+				var tr = new Transporter();
+
+				tr.bind("TransportingComplete", function() {
+					cb(this.result);
+				});
+
+				tr.transport(blob.getSource(), blob.type, {
+					ruid: self.uid
+				});
+			}
+
+			// copy over the headers if any
+			if (!Basic.isEmptyObj(meta.headers)) {
+				Basic.each(meta.headers, function(value, header) {
+					self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object
+				});
+			}
+
+			// transfer over multipart params and blob itself
+			if (data instanceof FormData) {
+				var blobField;
+				data.each(function(value, name) {
+					if (value instanceof Blob) {
+						blobField = name;
+					} else {
+						self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value);
+					}
+				});
+
+				if (!data.hasBlob()) {
+					data = null;
+					send();
+				} else {
+					var blob = data.getBlob();
+					if (blob.isDetached()) {
+						attachBlob(blob, function(attachedBlob) {
+							blob.destroy();
+							appendBlob(blobField, attachedBlob);		
+						});
+					} else {
+						appendBlob(blobField, blob);
+					}
+				}
+			} else if (data instanceof Blob) {
+				if (data.isDetached()) {
+					attachBlob(data, function(attachedBlob) {
+						data.destroy();
+						data = attachedBlob.uid;
+						send();
+					});
+				} else {
+					data = data.uid;
+					send();
+				}
+			} else {
+				send();
+			}
+		},
+
+		getResponse: function(responseType) {
+			var frs, blob, self = this.getRuntime();
+
+			blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob');
+
+			if (blob) {
+				blob = new File(self.uid, blob);
+
+				if ('blob' === responseType) {
+					return blob;
+				}
+
+				try { 
+					frs = new FileReaderSync();
+
+					if (!!~Basic.inArray(responseType, ["", "text"])) {
+						return frs.readAsText(blob);
+					} else if ('json' === responseType && !!window.JSON) {
+						return JSON.parse(frs.readAsText(blob));
+					}
+				} finally {
+					blob.destroy();
+				}
+			}
+			return null;
+		},
+
+		abort: function(upload_complete_flag) {
+			var self = this.getRuntime();
+
+			self.shimExec.call(this, 'XMLHttpRequest', 'abort');
+
+			this.dispatchEvent('readystatechange');
+			// this.dispatchEvent('progress');
+			this.dispatchEvent('abort');
+
+			//if (!upload_complete_flag) {
+				// this.dispatchEvent('uploadprogress');
+			//}
+		}
+	};
+
+	return (extensions.XMLHttpRequest = XMLHttpRequest);
+});
+
+// Included from: src/javascript/runtime/flash/image/Image.js
+
+/**
+ * Image.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/flash/image/Image
+@private
+*/
+define("moxie/runtime/flash/image/Image", [
+	"moxie/runtime/flash/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/runtime/Transporter",
+	"moxie/file/Blob",
+	"moxie/file/FileReaderSync"
+], function(extensions, Basic, Transporter, Blob, FileReaderSync) {
+	
+	var Image = {
+		loadFromBlob: function(blob) {
+			var comp = this, self = comp.getRuntime();
+
+			function exec(srcBlob) {
+				self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid);
+				comp = self = null;
+			}
+
+			if (blob.isDetached()) { // binary string
+				var tr = new Transporter();
+				tr.bind("TransportingComplete", function() {
+					exec(tr.result.getSource());
+				});
+				tr.transport(blob.getSource(), blob.type, { ruid: self.uid });
+			} else {
+				exec(blob.getSource());
+			}
+		},
+
+		loadFromImage: function(img) {
+			var self = this.getRuntime();
+			return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid);
+		},
+
+		getInfo: function() {
+			var self = this.getRuntime()
+			, info = self.shimExec.call(this, 'Image', 'getInfo')
+			;
+
+			if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) {
+				info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data);
+			}
+			return info;
+		},
+
+		getAsBlob: function(type, quality) {
+			var self = this.getRuntime()
+			, blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality)
+			;
+			if (blob) {
+				return new Blob(self.uid, blob);
+			}
+			return null;
+		},
+
+		getAsDataURL: function() {
+			var self = this.getRuntime()
+			, blob = self.Image.getAsBlob.apply(this, arguments)
+			, frs
+			;
+			if (!blob) {
+				return null;
+			}
+			frs = new FileReaderSync();
+			return frs.readAsDataURL(blob);
+		}
+	};
+
+	return (extensions.Image = Image);
+});
+
+// Included from: src/javascript/runtime/silverlight/Runtime.js
+
+/**
+ * RunTime.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/*global ActiveXObject:true */
+
+/**
+Defines constructor for Silverlight runtime.
+
+@class moxie/runtime/silverlight/Runtime
+@private
+*/
+define("moxie/runtime/silverlight/Runtime", [
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Env",
+	"moxie/core/utils/Dom",
+	"moxie/core/Exceptions",
+	"moxie/runtime/Runtime"
+], function(Basic, Env, Dom, x, Runtime) {
+	
+	var type = "silverlight", extensions = {};
+
+	function isInstalled(version) {
+		var isVersionSupported = false, control = null, actualVer,
+			actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0;
+
+		try {
+			try {
+				control = new ActiveXObject('AgControl.AgControl');
+
+				if (control.IsVersionSupported(version)) {
+					isVersionSupported = true;
+				}
+
+				control = null;
+			} catch (e) {
+				var plugin = navigator.plugins["Silverlight Plug-In"];
+
+				if (plugin) {
+					actualVer = plugin.description;
+
+					if (actualVer === "1.0.30226.2") {
+						actualVer = "2.0.30226.2";
+					}
+
+					actualVerArray = actualVer.split(".");
+
+					while (actualVerArray.length > 3) {
+						actualVerArray.pop();
+					}
+
+					while ( actualVerArray.length < 4) {
+						actualVerArray.push(0);
+					}
+
+					reqVerArray = version.split(".");
+
+					while (reqVerArray.length > 4) {
+						reqVerArray.pop();
+					}
+
+					do {
+						requiredVersionPart = parseInt(reqVerArray[index], 10);
+						actualVersionPart = parseInt(actualVerArray[index], 10);
+						index++;
+					} while (index < reqVerArray.length && requiredVersionPart === actualVersionPart);
+
+					if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) {
+						isVersionSupported = true;
+					}
+				}
+			}
+		} catch (e2) {
+			isVersionSupported = false;
+		}
+
+		return isVersionSupported;
+	}
+
+	/**
+	Constructor for the Silverlight Runtime
+	*/
+	function SilverlightRuntime(options) {
+		var I = this, initTimer;
+
+		options = Basic.extend({ xap_url: Env.xap_url }, options);
+
+		Runtime.call(this, options, type, {
+			access_binary: Runtime.capTrue,
+			access_image_binary: Runtime.capTrue,
+			display_media: Runtime.capTest(defined('moxie/image/Image')),
+			do_cors: Runtime.capTrue,
+			drag_and_drop: false,
+			report_upload_progress: Runtime.capTrue,
+			resize_image: Runtime.capTrue,
+			return_response_headers: function(value) {
+				return value && I.mode === 'client';
+			},
+			return_response_type: function(responseType) {
+				if (responseType !== 'json') {
+					return true;
+				} else {
+					return !!window.JSON;
+				}
+			},
+			return_status_code: function(code) {
+				return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]);
+			},
+			select_file: Runtime.capTrue,
+			select_multiple: Runtime.capTrue,
+			send_binary_string: Runtime.capTrue,
+			send_browser_cookies: function(value) {
+				return value && I.mode === 'browser';
+			},
+			send_custom_headers: function(value) {
+				return value && I.mode === 'client';
+			},
+			send_multipart: Runtime.capTrue,
+			slice_blob: Runtime.capTrue,
+			stream_upload: true,
+			summon_file_dialog: false,
+			upload_filesize: Runtime.capTrue,
+			use_http_method: function(methods) {
+				return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']);
+			}
+		}, { 
+			// capabilities that require specific mode
+			return_response_headers: function(value) {
+				return value ? 'client' : 'browser';
+			},
+			return_status_code: function(code) {
+				return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser'];
+			},
+			send_browser_cookies: function(value) {
+				return value ? 'browser' : 'client';
+			},
+			send_custom_headers: function(value) {
+				return value ? 'client' : 'browser';
+			},
+			use_http_method: function(methods) {
+				return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser'];
+			}
+		});
+
+
+		// minimal requirement
+		if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') {
+			if (MXI_DEBUG && Env.debug.runtime) {
+				Env.log("\tSilverlight is not installed or minimal version (2.0.31005.0) requirement not met (not likely).");	
+			}
+
+			this.mode = false;
+		}
+
+
+		Basic.extend(this, {
+			getShim: function() {
+				return Dom.get(this.uid).content.Moxie;
+			},
+
+			shimExec: function(component, action) {
+				var args = [].slice.call(arguments, 2);
+				return I.getShim().exec(this.uid, component, action, args);
+			},
+
+			init : function() {
+				var container;
+
+				container = this.getShimContainer();
+
+				container.innerHTML = '<object id="' + this.uid + '" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;">' +
+					'<param name="source" value="' + options.xap_url + '"/>' +
+					'<param name="background" value="Transparent"/>' +
+					'<param name="windowless" value="true"/>' +
+					'<param name="enablehtmlaccess" value="true"/>' +
+					'<param name="initParams" value="uid=' + this.uid + ',target=' + Runtime.getGlobalEventTarget() + '"/>' +
+				'</object>';
+
+				// Init is dispatched by the shim
+				initTimer = setTimeout(function() {
+					if (I && !I.initialized) { // runtime might be already destroyed by this moment
+						I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
+
+						if (MXI_DEBUG && Env.debug.runtime) {
+							Env.log("\Silverlight failed to initialize within a specified period of time (5-10s).");	
+						}
+					}
+				}, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac)
+			},
+
+			destroy: (function(destroy) { // extend default destroy method
+				return function() {
+					destroy.call(I);
+					clearTimeout(initTimer); // initialization check might be still onwait
+					options = initTimer = destroy = I = null;
+				};
+			}(this.destroy))
+
+		}, extensions);
+	}
+
+	Runtime.addConstructor(type, SilverlightRuntime); 
+
+	return extensions;
+});
+
+// Included from: src/javascript/runtime/silverlight/file/Blob.js
+
+/**
+ * Blob.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/silverlight/file/Blob
+@private
+*/
+define("moxie/runtime/silverlight/file/Blob", [
+	"moxie/runtime/silverlight/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/runtime/flash/file/Blob"
+], function(extensions, Basic, Blob) {
+	return (extensions.Blob = Basic.extend({}, Blob));
+});
+
+// Included from: src/javascript/runtime/silverlight/file/FileInput.js
+
+/**
+ * FileInput.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/silverlight/file/FileInput
+@private
+*/
+define("moxie/runtime/silverlight/file/FileInput", [
+	"moxie/runtime/silverlight/Runtime",
+	"moxie/file/File",
+	"moxie/core/utils/Dom",
+	"moxie/core/utils/Basic"
+], function(extensions, File, Dom, Basic) {
+
+	function toFilters(accept) {
+		var filter = '';
+		for (var i = 0; i < accept.length; i++) {
+			filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.');
+		}
+		return filter;
+	}
+
+	
+	var FileInput = {
+		init: function(options) {
+			var comp = this, I = this.getRuntime();
+			var browseButton = Dom.get(options.browse_button);
+
+			if (browseButton) {
+				browseButton.setAttribute('tabindex', -1);
+				browseButton = null;
+			}
+
+			this.bind("Change", function() {
+				var files = I.shimExec.call(comp, 'FileInput', 'getFiles');
+				comp.files = [];
+				Basic.each(files, function(file) {
+					comp.files.push(new File(I.uid, file));
+				});
+			}, 999);
+			
+			I.shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.multiple);
+			this.trigger('ready');
+		},
+
+		setOption: function(name, value) {
+			if (name == 'accept') {
+				value = toFilters(value);
+			}
+			this.getRuntime().shimExec.call(this, 'FileInput', 'setOption', name, value);
+		}
+	};
+
+	return (extensions.FileInput = FileInput);
+});
+
+// Included from: src/javascript/runtime/silverlight/file/FileDrop.js
+
+/**
+ * FileDrop.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/silverlight/file/FileDrop
+@private
+*/
+define("moxie/runtime/silverlight/file/FileDrop", [
+	"moxie/runtime/silverlight/Runtime",
+	"moxie/core/utils/Dom", 
+	"moxie/core/utils/Events"
+], function(extensions, Dom, Events) {
+
+	// not exactly useful, since works only in safari (...crickets...)
+	var FileDrop = {
+		init: function() {
+			var comp = this, self = comp.getRuntime(), dropZone;
+
+			dropZone = self.getShimContainer();
+
+			Events.addEvent(dropZone, 'dragover', function(e) {
+				e.preventDefault();
+				e.stopPropagation();
+				e.dataTransfer.dropEffect = 'copy';
+			}, comp.uid);
+
+			Events.addEvent(dropZone, 'dragenter', function(e) {
+				e.preventDefault();
+				var flag = Dom.get(self.uid).dragEnter(e);
+				// If handled, then stop propagation of event in DOM
+				if (flag) {
+					e.stopPropagation();
+				}
+			}, comp.uid);
+
+			Events.addEvent(dropZone, 'drop', function(e) {
+				e.preventDefault();
+				var flag = Dom.get(self.uid).dragDrop(e);
+				// If handled, then stop propagation of event in DOM
+				if (flag) {
+					e.stopPropagation();
+				}
+			}, comp.uid);
+
+			return self.shimExec.call(this, 'FileDrop', 'init');
+		}
+	};
+
+	return (extensions.FileDrop = FileDrop);
+});
+
+// Included from: src/javascript/runtime/silverlight/file/FileReader.js
+
+/**
+ * FileReader.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/silverlight/file/FileReader
+@private
+*/
+define("moxie/runtime/silverlight/file/FileReader", [
+	"moxie/runtime/silverlight/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/runtime/flash/file/FileReader"
+], function(extensions, Basic, FileReader) {
+	return (extensions.FileReader = Basic.extend({}, FileReader));
+});
+
+// Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js
+
+/**
+ * FileReaderSync.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/silverlight/file/FileReaderSync
+@private
+*/
+define("moxie/runtime/silverlight/file/FileReaderSync", [
+	"moxie/runtime/silverlight/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/runtime/flash/file/FileReaderSync"
+], function(extensions, Basic, FileReaderSync) {
+	return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync));
+});
+
+// Included from: src/javascript/runtime/silverlight/runtime/Transporter.js
+
+/**
+ * Transporter.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/silverlight/runtime/Transporter
+@private
+*/
+define("moxie/runtime/silverlight/runtime/Transporter", [
+	"moxie/runtime/silverlight/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/runtime/flash/runtime/Transporter"
+], function(extensions, Basic, Transporter) {
+	return (extensions.Transporter = Basic.extend({}, Transporter));
+});
+
+// Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js
+
+/**
+ * XMLHttpRequest.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/silverlight/xhr/XMLHttpRequest
+@private
+*/
+define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [
+	"moxie/runtime/silverlight/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/runtime/flash/xhr/XMLHttpRequest",
+	"moxie/runtime/silverlight/file/FileReaderSync",
+	"moxie/runtime/silverlight/runtime/Transporter"
+], function(extensions, Basic, XMLHttpRequest, FileReaderSyncSilverlight, TransporterSilverlight) {
+	return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest));
+});
+
+// Included from: src/javascript/runtime/silverlight/image/Image.js
+
+/**
+ * Image.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+ 
+/**
+@class moxie/runtime/silverlight/image/Image
+@private
+*/
+define("moxie/runtime/silverlight/image/Image", [
+	"moxie/runtime/silverlight/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/file/Blob",
+	"moxie/runtime/flash/image/Image"
+], function(extensions, Basic, Blob, Image) {
+	return (extensions.Image = Basic.extend({}, Image, {
+
+		getInfo: function() {
+			var self = this.getRuntime()
+			, grps = ['tiff', 'exif', 'gps', 'thumb']
+			, info = { meta: {} }
+			, rawInfo = self.shimExec.call(this, 'Image', 'getInfo')
+			;
+
+			if (rawInfo.meta) {
+				Basic.each(grps, function(grp) {
+					var meta = rawInfo.meta[grp]
+					, tag
+					, i
+					, length
+					, value
+					;
+					if (meta && meta.keys) {
+						info.meta[grp] = {};
+						for (i = 0, length = meta.keys.length; i < length; i++) {
+							tag = meta.keys[i];
+							value = meta[tag];
+							if (value) {
+								// convert numbers
+								if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero)
+									value = parseInt(value, 10);
+								} else if (/^\d*\.\d+$/.test(value)) { // double
+									value = parseFloat(value);
+								}
+								info.meta[grp][tag] = value;
+							}
+						}
+					}
+				});
+
+				// save thumb data as blob
+				if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) {
+					info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data);
+				}
+			}
+
+			info.width = parseInt(rawInfo.width, 10);
+			info.height = parseInt(rawInfo.height, 10);
+			info.size = parseInt(rawInfo.size, 10);
+			info.type = rawInfo.type;
+			info.name = rawInfo.name;
+
+			return info;
+		},
+
+		resize: function(rect, ratio, opts) {
+			this.getRuntime().shimExec.call(this, 'Image', 'resize', rect.x, rect.y, rect.width, rect.height, ratio, opts.preserveHeaders, opts.resample);
+		}
+	}));
+});
+
+// Included from: src/javascript/runtime/html4/Runtime.js
+
+/**
+ * Runtime.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/*global File:true */
+
+/**
+Defines constructor for HTML4 runtime.
+
+@class moxie/runtime/html4/Runtime
+@private
+*/
+define("moxie/runtime/html4/Runtime", [
+	"moxie/core/utils/Basic",
+	"moxie/core/Exceptions",
+	"moxie/runtime/Runtime",
+	"moxie/core/utils/Env"
+], function(Basic, x, Runtime, Env) {
+	
+	var type = 'html4', extensions = {};
+
+	function Html4Runtime(options) {
+		var I = this
+		, Test = Runtime.capTest
+		, True = Runtime.capTrue
+		;
+
+		Runtime.call(this, options, type, {
+			access_binary: Test(window.FileReader || window.File && File.getAsDataURL),
+			access_image_binary: false,
+			display_media: Test(
+				(Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) && 
+				defined('moxie/image/Image')
+			),
+			do_cors: false,
+			drag_and_drop: false,
+			filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest
+				return !(
+					(Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) || 
+					(Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) || 
+					(Env.browser === 'Safari' && Env.verComp(Env.version, 7, '<')) ||
+					(Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<'))
+				);
+			}()),
+			resize_image: function() {
+				return extensions.Image && I.can('access_binary') && Env.can('create_canvas');
+			},
+			report_upload_progress: false,
+			return_response_headers: false,
+			return_response_type: function(responseType) {
+				if (responseType === 'json' && !!window.JSON) {
+					return true;
+				} 
+				return !!~Basic.inArray(responseType, ['text', 'document', '']);
+			},
+			return_status_code: function(code) {
+				return !Basic.arrayDiff(code, [200, 404]);
+			},
+			select_file: function() {
+				return Env.can('use_fileinput');
+			},
+			select_multiple: false,
+			send_binary_string: false,
+			send_custom_headers: false,
+			send_multipart: true,
+			slice_blob: false,
+			stream_upload: function() {
+				return I.can('select_file');
+			},
+			summon_file_dialog: function() { // yeah... some dirty sniffing here...
+				return I.can('select_file') && !(
+					(Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '<')) ||
+					(Env.browser === 'Opera' && Env.verComp(Env.version, 12, '<')) ||
+					(Env.browser === 'IE' && Env.verComp(Env.version, 10, '<'))
+				);
+			},
+			upload_filesize: True,
+			use_http_method: function(methods) {
+				return !Basic.arrayDiff(methods, ['GET', 'POST']);
+			}
+		});
+
+
+		Basic.extend(this, {
+			init : function() {
+				this.trigger("Init");
+			},
+
+			destroy: (function(destroy) { // extend default destroy method
+				return function() {
+					destroy.call(I);
+					destroy = I = null;
+				};
+			}(this.destroy))
+		});
+
+		Basic.extend(this.getShim(), extensions);
+	}
+
+	Runtime.addConstructor(type, Html4Runtime);
+
+	return extensions;
+});
+
+// Included from: src/javascript/runtime/html4/file/FileInput.js
+
+/**
+ * FileInput.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html4/file/FileInput
+@private
+*/
+define("moxie/runtime/html4/file/FileInput", [
+	"moxie/runtime/html4/Runtime",
+	"moxie/file/File",
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Dom",
+	"moxie/core/utils/Events",
+	"moxie/core/utils/Mime",
+	"moxie/core/utils/Env"
+], function(extensions, File, Basic, Dom, Events, Mime, Env) {
+	
+	function FileInput() {
+		var _uid, _mimes = [], _options, _browseBtnZIndex; // save original z-index;
+
+		function addInput() {
+			var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid;
+
+			uid = Basic.guid('uid_');
+
+			shimContainer = I.getShimContainer(); // we get new ref every time to avoid memory leaks in IE
+
+			if (_uid) { // move previous form out of the view
+				currForm = Dom.get(_uid + '_form');
+				if (currForm) {
+					Basic.extend(currForm.style, { top: '100%' });
+					// it shouldn't be possible to tab into the hidden element
+					currForm.firstChild.setAttribute('tabindex', -1);
+				}
+			}
+
+			// build form in DOM, since innerHTML version not able to submit file for some reason
+			form = document.createElement('form');
+			form.setAttribute('id', uid + '_form');
+			form.setAttribute('method', 'post');
+			form.setAttribute('enctype', 'multipart/form-data');
+			form.setAttribute('encoding', 'multipart/form-data');
+
+			Basic.extend(form.style, {
+				overflow: 'hidden',
+				position: 'absolute',
+				top: 0,
+				left: 0,
+				width: '100%',
+				height: '100%'
+			});
+
+			input = document.createElement('input');
+			input.setAttribute('id', uid);
+			input.setAttribute('type', 'file');
+			input.setAttribute('accept', _mimes.join(','));
+
+			if (I.can('summon_file_dialog')) {
+				input.setAttribute('tabindex', -1);
+			}
+
+			Basic.extend(input.style, {
+				fontSize: '999px',
+				opacity: 0
+			});
+
+			form.appendChild(input);
+			shimContainer.appendChild(form);
+
+			// prepare file input to be placed underneath the browse_button element
+			Basic.extend(input.style, {
+				position: 'absolute',
+				top: 0,
+				left: 0,
+				width: '100%',
+				height: '100%'
+			});
+
+			if (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) {
+				Basic.extend(input.style, {
+					filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)"
+				});
+			}
+
+			input.onchange = function() { // there should be only one handler for this
+				var file;
+
+				if (!this.value) {
+					return;
+				}
+
+				if (this.files) { // check if browser is fresh enough
+					file = this.files[0];
+				} else {
+					file = {
+						name: this.value
+					};
+				}
+
+				file = new File(I.uid, file);
+
+				// clear event handler
+				this.onchange = function() {}; 
+				addInput.call(comp); 
+
+				comp.files = [file];
+
+				// substitute all ids with file uids (consider file.uid read-only - we cannot do it the other way around)
+				input.setAttribute('id', file.uid);
+				form.setAttribute('id', file.uid + '_form');
+				
+				comp.trigger('change');
+
+				input = form = null;
+			};
+
+
+			// route click event to the input
+			if (I.can('summon_file_dialog')) {
+				browseButton = Dom.get(_options.browse_button);
+				Events.removeEvent(browseButton, 'click', comp.uid);
+				Events.addEvent(browseButton, 'click', function(e) {
+					if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
+						input.click();
+					}
+					e.preventDefault();
+				}, comp.uid);
+			}
+
+			_uid = uid;
+
+			shimContainer = currForm = browseButton = null;
+		}
+
+		Basic.extend(this, {
+			init: function(options) {
+				var comp = this, I = comp.getRuntime(), shimContainer;
+
+				// figure out accept string
+				_options = options;
+				_mimes = Mime.extList2mimes(options.accept, I.can('filter_by_extension'));
+
+				shimContainer = I.getShimContainer();
+
+				(function() {
+					var browseButton, zIndex, top;
+
+					browseButton = Dom.get(options.browse_button);
+					_browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto';
+
+					// Route click event to the input[type=file] element for browsers that support such behavior
+					if (I.can('summon_file_dialog')) {
+						if (Dom.getStyle(browseButton, 'position') === 'static') {
+							browseButton.style.position = 'relative';
+						}						
+
+						comp.bind('Refresh', function() {
+							zIndex = parseInt(_browseBtnZIndex, 10) || 1;
+
+							Dom.get(_options.browse_button).style.zIndex = zIndex;
+							this.getRuntime().getShimContainer().style.zIndex = zIndex - 1;
+						});
+					} else {
+						// it shouldn't be possible to tab into the hidden element
+						browseButton.setAttribute('tabindex', -1);
+					}
+
+					/* Since we have to place input[type=file] on top of the browse_button for some browsers,
+					browse_button loses interactivity, so we restore it here */
+					top = I.can('summon_file_dialog') ? browseButton : shimContainer;
+
+					Events.addEvent(top, 'mouseover', function() {
+						comp.trigger('mouseenter');
+					}, comp.uid);
+
+					Events.addEvent(top, 'mouseout', function() {
+						comp.trigger('mouseleave');
+					}, comp.uid);
+
+					Events.addEvent(top, 'mousedown', function() {
+						comp.trigger('mousedown');
+					}, comp.uid);
+
+					Events.addEvent(Dom.get(options.container), 'mouseup', function() {
+						comp.trigger('mouseup');
+					}, comp.uid);
+
+					browseButton = null;
+				}());
+
+				addInput.call(this);
+
+				shimContainer = null;
+
+				// trigger ready event asynchronously
+				comp.trigger({
+					type: 'ready',
+					async: true
+				});
+			},
+
+			setOption: function(name, value) {
+				var I = this.getRuntime();
+				var input;
+
+				if (name == 'accept') {
+					_mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension'));
+				}
+
+				// update current input
+				input = Dom.get(_uid)
+				if (input) {
+					input.setAttribute('accept', _mimes.join(','));
+				}
+			},
+
+
+			disable: function(state) {
+				var input;
+
+				if ((input = Dom.get(_uid))) {
+					input.disabled = !!state;
+				}
+			},
+
+			destroy: function() {
+				var I = this.getRuntime()
+				, shim = I.getShim()
+				, shimContainer = I.getShimContainer()
+				, container = _options && Dom.get(_options.container)
+				, browseButton = _options && Dom.get(_options.browse_button)
+				;
+				
+				if (container) {
+					Events.removeAllEvents(container, this.uid);
+				}
+				
+				if (browseButton) {
+					Events.removeAllEvents(browseButton, this.uid);
+					browseButton.style.zIndex = _browseBtnZIndex; // reset to original value
+				}
+				
+				if (shimContainer) {
+					Events.removeAllEvents(shimContainer, this.uid);
+					shimContainer.innerHTML = '';
+				}
+
+				shim.removeInstance(this.uid);
+
+				_uid = _mimes = _options = shimContainer = container = browseButton = shim = null;
+			}
+		});
+	}
+
+	return (extensions.FileInput = FileInput);
+});
+
+// Included from: src/javascript/runtime/html4/file/FileReader.js
+
+/**
+ * FileReader.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html4/file/FileReader
+@private
+*/
+define("moxie/runtime/html4/file/FileReader", [
+	"moxie/runtime/html4/Runtime",
+	"moxie/runtime/html5/file/FileReader"
+], function(extensions, FileReader) {
+	return (extensions.FileReader = FileReader);
+});
+
+// Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js
+
+/**
+ * XMLHttpRequest.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html4/xhr/XMLHttpRequest
+@private
+*/
+define("moxie/runtime/html4/xhr/XMLHttpRequest", [
+	"moxie/runtime/html4/Runtime",
+	"moxie/core/utils/Basic",
+	"moxie/core/utils/Dom",
+	"moxie/core/utils/Url",
+	"moxie/core/Exceptions",
+	"moxie/core/utils/Events",
+	"moxie/file/Blob",
+	"moxie/xhr/FormData"
+], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) {
+	
+	function XMLHttpRequest() {
+		var _status, _response, _iframe;
+
+		function cleanup(cb) {
+			var target = this, uid, form, inputs, i, hasFile = false;
+
+			if (!_iframe) {
+				return;
+			}
+
+			uid = _iframe.id.replace(/_iframe$/, '');
+
+			form = Dom.get(uid + '_form');
+			if (form) {
+				inputs = form.getElementsByTagName('input');
+				i = inputs.length;
+
+				while (i--) {
+					switch (inputs[i].getAttribute('type')) {
+						case 'hidden':
+							inputs[i].parentNode.removeChild(inputs[i]);
+							break;
+						case 'file':
+							hasFile = true; // flag the case for later
+							break;
+					}
+				}
+				inputs = [];
+
+				if (!hasFile) { // we need to keep the form for sake of possible retries
+					form.parentNode.removeChild(form);
+				}
+				form = null;
+			}
+
+			// without timeout, request is marked as canceled (in console)
+			setTimeout(function() {
+				Events.removeEvent(_iframe, 'load', target.uid);
+				if (_iframe.parentNode) { // #382
+					_iframe.parentNode.removeChild(_iframe);
+				}
+
+				// check if shim container has any other children, if - not, remove it as well
+				var shimContainer = target.getRuntime().getShimContainer();
+				if (!shimContainer.children.length) {
+					shimContainer.parentNode.removeChild(shimContainer);
+				}
+
+				shimContainer = _iframe = null;
+				cb();
+			}, 1);
+		}
+
+		Basic.extend(this, {
+			send: function(meta, data) {
+				var target = this, I = target.getRuntime(), uid, form, input, blob;
+
+				_status = _response = null;
+
+				function createIframe() {
+					var container = I.getShimContainer() || document.body
+					, temp = document.createElement('div')
+					;
+
+					// IE 6 won't be able to set the name using setAttribute or iframe.name
+					temp.innerHTML = '<iframe id="' + uid + '_iframe" name="' + uid + '_iframe" src="javascript:&quot;&quot;" style="display:none"></iframe>';
+					_iframe = temp.firstChild;
+					container.appendChild(_iframe);
+
+					/* _iframe.onreadystatechange = function() {
+						console.info(_iframe.readyState);
+					};*/
+
+					Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8
+						var el;
+
+						try {
+							el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document;
+
+							// try to detect some standard error pages
+							if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error
+								_status = el.title.replace(/^(\d+).*$/, '$1');
+							} else {
+								_status = 200;
+								// get result
+								_response = Basic.trim(el.body.innerHTML);
+
+								// we need to fire these at least once
+								target.trigger({
+									type: 'progress',
+									loaded: _response.length,
+									total: _response.length
+								});
+
+								if (blob) { // if we were uploading a file
+									target.trigger({
+										type: 'uploadprogress',
+										loaded: blob.size || 1025,
+										total: blob.size || 1025
+									});
+								}
+							}
+						} catch (ex) {
+							if (Url.hasSameOrigin(meta.url)) {
+								// if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm
+								// which obviously results to cross domain error (wtf?)
+								_status = 404;
+							} else {
+								cleanup.call(target, function() {
+									target.trigger('error');
+								});
+								return;
+							}
+						}	
+					
+						cleanup.call(target, function() {
+							target.trigger('load');
+						});
+					}, target.uid);
+				} // end createIframe
+
+				// prepare data to be sent and convert if required
+				if (data instanceof FormData && data.hasBlob()) {
+					blob = data.getBlob();
+					uid = blob.uid;
+					input = Dom.get(uid);
+					form = Dom.get(uid + '_form');
+					if (!form) {
+						throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
+					}
+				} else {
+					uid = Basic.guid('uid_');
+
+					form = document.createElement('form');
+					form.setAttribute('id', uid + '_form');
+					form.setAttribute('method', meta.method);
+					form.setAttribute('enctype', 'multipart/form-data');
+					form.setAttribute('encoding', 'multipart/form-data');
+
+					I.getShimContainer().appendChild(form);
+				}
+
+				// set upload target
+				form.setAttribute('target', uid + '_iframe');
+
+				if (data instanceof FormData) {
+					data.each(function(value, name) {
+						if (value instanceof Blob) {
+							if (input) {
+								input.setAttribute('name', name);
+							}
+						} else {
+							var hidden = document.createElement('input');
+
+							Basic.extend(hidden, {
+								type : 'hidden',
+								name : name,
+								value : value
+							});
+
+							// make sure that input[type="file"], if it's there, comes last
+							if (input) {
+								form.insertBefore(hidden, input);
+							} else {
+								form.appendChild(hidden);
+							}
+						}
+					});
+				}
+
+				// set destination url
+				form.setAttribute("action", meta.url);
+
+				createIframe();
+				form.submit();
+				target.trigger('loadstart');
+			},
+
+			getStatus: function() {
+				return _status;
+			},
+
+			getResponse: function(responseType) {
+				if ('json' === responseType) {
+					// strip off <pre>..</pre> tags that might be enclosing the response
+					if (Basic.typeOf(_response) === 'string' && !!window.JSON) {
+						try {
+							return JSON.parse(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, ''));
+						} catch (ex) {
+							return null;
+						}
+					} 
+				} else if ('document' === responseType) {
+
+				}
+				return _response;
+			},
+
+			abort: function() {
+				var target = this;
+
+				if (_iframe && _iframe.contentWindow) {
+					if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome
+						_iframe.contentWindow.stop();
+					} else if (_iframe.contentWindow.document.execCommand) { // IE
+						_iframe.contentWindow.document.execCommand('Stop');
+					} else {
+						_iframe.src = "about:blank";
+					}
+				}
+
+				cleanup.call(this, function() {
+					// target.dispatchEvent('readystatechange');
+					target.dispatchEvent('abort');
+				});
+			},
+
+			destroy: function() {
+				this.getRuntime().getShim().removeInstance(this.uid);
+			}
+		});
+	}
+
+	return (extensions.XMLHttpRequest = XMLHttpRequest);
+});
+
+// Included from: src/javascript/runtime/html4/image/Image.js
+
+/**
+ * Image.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/runtime/html4/image/Image
+@private
+*/
+define("moxie/runtime/html4/image/Image", [
+	"moxie/runtime/html4/Runtime",
+	"moxie/runtime/html5/image/Image"
+], function(extensions, Image) {
+	return (extensions.Image = Image);
+});
+
+expose(["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/core/utils/Env","moxie/core/Exceptions","moxie/core/utils/Dom","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/core/I18n","moxie/core/utils/Mime","moxie/file/FileInput","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/image/Image","moxie/core/utils/Events","moxie/runtime/html5/image/ResizerCanvas"]);
+})(this);
+}));

Разница между файлами не показана из-за своего большого размера
+ 12 - 0
app/assets/js/plupload-2.3.7/js/moxie.min.js


Некоторые файлы не были показаны из-за большого количества измененных файлов