diff --git a/.idea/django-qiniu-fields.iml b/.idea/django-qiniu-fields.iml
new file mode 100644
index 0000000..7823e3b
--- /dev/null
+++ b/.idea/django-qiniu-fields.iml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..c23ecac
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..609d0ab
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..920fb38
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..6789543
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,535 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1506571539244
+
+
+ 1506571539244
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/__init__.py b/demo/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/demo/adminx.py b/demo/adminx.py
new file mode 100644
index 0000000..48c2f99
--- /dev/null
+++ b/demo/adminx.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+import xadmin
+import xadmin.views as xviews
+from xadmin.layout import Main, Fieldset, Side
+
+from .models import Banner
+
+
+class BaseSetting(object):
+ enable_themes = True
+ use_bootswatch = True
+
+xadmin.site.register(xviews.BaseAdminView, BaseSetting)
+
+
+class AdminSettings(object):
+ global_search_models = [Banner]
+ site_title = 'QiniuFields'
+ site_footer = 'QiniuFields Inc. 2017'
+ menu_style = 'default' # accordion
+
+ def get_site_menu(self):
+ return (
+ {'title': '内容管理', 'menus': (
+ {'title': 'Banner', 'icon': 'fa fa-gift', 'url': self.get_model_url(Banner, 'changelist')},
+ )},
+ )
+
+xadmin.site.register(xviews.CommAdminView, AdminSettings)
+
+
+class BannerAdmin(object):
+ list_display = ('title', 'banner_img', 'created_time')
+ search_fields = ['title']
+ form_layout = (
+ Main(Fieldset(u'基本信息', 'title', 'img_url')),
+ Side(Fieldset(u'其他信息', 'created_time', 'updated_time'))
+ )
+ readonly_fields = ('created_time', 'updated_time')
+
+
+xadmin.site.register(Banner, BannerAdmin)
diff --git a/demo/apps.py b/demo/apps.py
new file mode 100644
index 0000000..57920c3
--- /dev/null
+++ b/demo/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class DemoConfig(AppConfig):
+ name = 'demo'
diff --git a/demo/migrations/0001_initial.py b/demo/migrations/0001_initial.py
new file mode 100644
index 0000000..8307914
--- /dev/null
+++ b/demo/migrations/0001_initial.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.5 on 2017-09-28 12:23
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import qiniu_fields.fields
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Banner',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=100, verbose_name='标题')),
+ ('img_url', qiniu_fields.fields.QiniuFileField(max_length=500, verbose_name='图片')),
+ ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
+ ('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
+ ],
+ options={
+ 'verbose_name_plural': 'Banner',
+ 'verbose_name': 'Banner',
+ },
+ ),
+ ]
diff --git a/demo/migrations/__init__.py b/demo/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/demo/models.py b/demo/models.py
new file mode 100644
index 0000000..d1731c0
--- /dev/null
+++ b/demo/models.py
@@ -0,0 +1,24 @@
+from django.db import models
+from django.utils.html import format_html
+
+from qiniu_fields import QiniuFileField
+
+
+class Banner(models.Model):
+ title = models.CharField(max_length=100, verbose_name='标题')
+ img_url = QiniuFileField(prefix='banner', file_type='image', verbose_name='图片')
+ created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
+ updated_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
+
+ def __str__(self):
+ return self.title
+
+ def banner_img(self):
+ return format_html(' ', self.img_url)
+ banner_img.short_description = u'图片'
+ banner_img.allow_tags = True
+
+ class Meta:
+ app_label = 'demo'
+ verbose_name = 'Banner'
+ verbose_name_plural = 'Banner'
diff --git a/demo/qiniu_utils.py b/demo/qiniu_utils.py
new file mode 100644
index 0000000..caf3caf
--- /dev/null
+++ b/demo/qiniu_utils.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+import hashlib
+
+from django.conf import settings
+
+from qiniu import Auth, BucketManager, put_file, build_batch_delete
+
+
+EXPIRE_TIME = 24 * 3600 # 1 day
+
+Q = Auth(settings.QINIU_ACCESS_KEY, settings.QINIU_SECRET_KEY)
+
+
+def get_token():
+ token = Q.upload_token(settings.QINIU_BUCKET, expires=EXPIRE_TIME)
+ return token
+
+
+def delete_data(urls, key_prefix=''):
+ keys = []
+ for url in urls:
+ if not url.endswith('/'):
+ url += '/'
+ key = url.split('/')[-2]
+ if key_prefix:
+ key = '%s/%s' % (key_prefix, key)
+ keys.append(key)
+
+ ops = build_batch_delete(settings.QINIU_BUCKET, keys)
+ b = BucketManager(Q)
+ ret, info = b.batch(ops)
+ print(ret, info)
+
+
+def upload_file(file_data, key_prefix=''):
+ file_ext = file_data.name.split('.')[-1]
+ file_name = '.'.join([hashlib.md5(file_data.read()).hexdigest(), file_ext])
+ if key_prefix and not key_prefix.endswith('/'):
+ key_prefix += '/'
+ key = '%s%s' % (key_prefix, file_name)
+ token = get_token()
+
+ ret, info = put_file(token, key, file_data.temporary_file_path(), check_crc=False)
+ if not ret or ret.get('key') != key:
+ print('fail to upload image to qiniu, info: %s' % info)
+
+ return settings.QINIU_DOMAIN + key
diff --git a/demo/views.py b/demo/views.py
new file mode 100644
index 0000000..8d54976
--- /dev/null
+++ b/demo/views.py
@@ -0,0 +1,10 @@
+#! -*- coding: utf-8 -*-
+from django.contrib.auth.decorators import login_required
+from django.http import JsonResponse
+
+from . import qiniu_utils
+
+
+@login_required
+def get_qiniu_token(request):
+ return JsonResponse({'uptoken': qiniu_utils.get_token()})
diff --git a/manage.py b/manage.py
new file mode 100755
index 0000000..d9827d9
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "qiniu_fields_demo.settings")
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError:
+ # The above import may fail for some other reason. Ensure that the
+ # issue is really that Django is missing to avoid masking other
+ # exceptions on Python 2.
+ try:
+ import django
+ except ImportError:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ )
+ raise
+ execute_from_command_line(sys.argv)
diff --git a/qiniu_fields/__init__.py b/qiniu_fields/__init__.py
new file mode 100644
index 0000000..07bdb59
--- /dev/null
+++ b/qiniu_fields/__init__.py
@@ -0,0 +1,3 @@
+from .fields import QiniuFileField, QiniuFileListField
+
+__all__ = ["QiniuFileField", "QiniuFileListField"]
diff --git a/qiniu_fields/fields.py b/qiniu_fields/fields.py
new file mode 100644
index 0000000..1b25db7
--- /dev/null
+++ b/qiniu_fields/fields.py
@@ -0,0 +1,39 @@
+#! -*- coding: utf-8 -*-
+from django.db import models
+
+from .widgets import QiniuFileWidget, QiniuFileListWidget
+from .forms import QiniuFileFormField
+
+
+class QiniuFileField(models.URLField):
+ widget_clz = QiniuFileWidget
+ form_field_clz = QiniuFileFormField
+
+ def __init__(self, verbose_name=None, name=None, prefix='', file_type='all', **kwargs):
+ self.prefix = prefix
+ self.file_type = file_type
+ kwargs['max_length'] = 500
+ super(QiniuFileField, self).__init__(verbose_name, name, **kwargs)
+
+ def formfield(self, **kwargs):
+ self.form_field_clz.prefix = self.prefix
+ self.form_field_clz.file_type = self.file_type
+ kwargs.update({
+ 'form_class': self.form_field_clz,
+ 'widget': self.widget_clz(attrs={'prefix': self.prefix, 'file_type': self.file_type})
+ })
+ return super(QiniuFileField, self).formfield(**kwargs)
+
+
+class QiniuFileListField(models.TextField):
+
+ def __init__(self, *args, prefix='', file_type='all', **kwargs):
+ self.prefix = prefix
+ self.file_type = file_type
+ super(QiniuFileListField, self).__init__(*args, **kwargs)
+
+ def formfield(self, **kwargs):
+ kwargs.update({
+ 'widget': QiniuFileListWidget(attrs={'prefix': self.prefix, 'file_type': self.file_type}),
+ })
+ return super(QiniuFileListField, self).formfield(**kwargs)
diff --git a/qiniu_fields/forms.py b/qiniu_fields/forms.py
new file mode 100644
index 0000000..00058db
--- /dev/null
+++ b/qiniu_fields/forms.py
@@ -0,0 +1,14 @@
+#! -*- coding: utf-8 -*-
+from django import forms
+
+from .widgets import QiniuFileWidget, QiniuFileListWidget
+
+
+class QiniuFileFormField(forms.URLField):
+ prefix = ''
+ file_type = 'all'
+ widget = QiniuFileWidget
+
+ def __init__(self, *args, **kwargs):
+ kwargs["widget"] = QiniuFileWidget(attrs={'prefix': self.prefix, 'file_type': self.file_type})
+ super(QiniuFileFormField, self).__init__(*args, **kwargs)
diff --git a/qiniu_fields/static/qiniu_fields/plupload/Moxie.swf b/qiniu_fields/static/qiniu_fields/plupload/Moxie.swf
new file mode 100644
index 0000000..e477cf9
Binary files /dev/null and b/qiniu_fields/static/qiniu_fields/plupload/Moxie.swf differ
diff --git a/qiniu_fields/static/qiniu_fields/plupload/Moxie.xap b/qiniu_fields/static/qiniu_fields/plupload/Moxie.xap
new file mode 100644
index 0000000..fc7fbfe
Binary files /dev/null and b/qiniu_fields/static/qiniu_fields/plupload/Moxie.xap differ
diff --git a/qiniu_fields/static/qiniu_fields/plupload/i18n/en.js b/qiniu_fields/static/qiniu_fields/plupload/i18n/en.js
new file mode 100644
index 0000000..6ab3e2e
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/plupload/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","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.","Filename":"Filename","Image format either wrong or not supported.":"Image format either wrong or not supported.","Status":"Status","HTTP Error.":"HTTP Error.","Start Upload":"Start Upload","mb":"mb","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.","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","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.","Error: File too large:":"Error: File too large:","Add Files":"Add Files"});
\ No newline at end of file
diff --git a/qiniu_fields/static/qiniu_fields/plupload/i18n/zh_CN.js b/qiniu_fields/static/qiniu_fields/plupload/i18n/zh_CN.js
new file mode 100644
index 0000000..f48e0c4
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/plupload/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":"关闭","Init error.":"初始化错误。","Add files to the upload queue and click the start button.":"将文件添加到上传队列,然后点击”开始上传“按钮。","Filename":"文件名","Image format either wrong or not supported.":"图片格式错误或者不支持。","Status":"状态","HTTP Error.":"HTTP 错误。","Start Upload":"开始上传","mb":"mb","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 已经在当前队列里。","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","Drag files here.":"把文件拖到这里。","Runtime ran out of available memory.":"运行时已消耗所有可用内存。","File count error.":"文件数量错误。","File extension error.":"文件扩展名错误。","Error: File too large:":"错误: 文件太大:","Add Files":"增加文件"});
\ No newline at end of file
diff --git a/qiniu_fields/static/qiniu_fields/plupload/moxie.js b/qiniu_fields/static/qiniu_fields/plupload/moxie.js
new file mode 100644
index 0000000..c7624ff
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/plupload/moxie.js
@@ -0,0 +1,11158 @@
+;var MXI_DEBUG = true;
+/**
+ * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
+ * v1.3.4
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ *
+ * Date: 2015-07-18
+ */
+/**
+ * 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
+ */
+
+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
+ @for Utils
+ @static
+ @param {Object} o Object to check.
+ @return {String} Object [[Class]]
+ */
+ var typeOf = function(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.
+
+ @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.
+ */
+ var extend = function(target) {
+ var undef;
+
+ each(arguments, function(arg, i) {
+ if (i > 0) {
+ each(arg, function(value, key) {
+ if (value !== undef) {
+ if (typeOf(target[key]) === typeOf(value) && !!~inArray(typeOf(value), ['array', 'object'])) {
+ extend(target[key], value);
+ } else {
+ target[key] = value;
+ }
+ }
+ });
+ }
+ });
+ return target;
+ };
+
+ /**
+ 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.
+ */
+ var each = function(obj, callback) {
+ var length, key, i, undef;
+
+ if (obj) {
+ if (typeOf(obj.length) === 'number') { // it might be Array, FileList or even arguments object
+ // Loop array items
+ for (i = 0, length = obj.length; i < length; i++) {
+ if (callback(obj[i], i) === false) {
+ return;
+ }
+ }
+ } else if (typeOf(obj) === 'object') {
+ // Loop object items
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ if (callback(obj[key], key) === false) {
+ return;
+ }
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ Checks if object is empty.
+
+ @method isEmptyObj
+ @static
+ @param {Object} o Object to check.
+ @return {Boolean}
+ */
+ var isEmptyObj = function(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
+ */
+ var inSeries = function(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 error
+ */
+ var inParallel = function(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
+ */
+ var inArray = function(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}
+ */
+ var arrayDiff = function(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
+ */
+ var arrayIntersect = function(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.
+ */
+ var toArray = function(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}
+ */
+ var trim = function(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.
+ */
+ var parseSizeStr = function(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
+ */
+ var sprintf = function(str) {
+ var args = [].slice.call(arguments, 1);
+
+ return str.replace(/%[a-z]/g, function() {
+ var value = args.shift();
+ return typeOf(value) !== 'undefined' ? value : '';
+ });
+ };
+
+
+ return {
+ guid: guid,
+ typeOf: typeOf,
+ extend: extend,
+ each: each,
+ isEmptyObj: isEmptyObj,
+ inSeries: inSeries,
+ inParallel: inParallel,
+ inArray: inArray,
+ arrayDiff: arrayDiff,
+ arrayIntersect: arrayIntersect,
+ toArray: toArray,
+ trim: trim,
+ sprintf: sprintf,
+ parseSizeStr: parseSizeStr
+ };
+});
+
+// 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
+ */
+
+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
+ * 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 = {
+ 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');
+ return !!(el.getContext && el.getContext('2d'));
+ }()),
+
+ 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;
+ },
+
+ // 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 !el.disabled;
+ }
+ };
+
+ 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"));
+ }
+
+ var data = arguments[0];
+
+ if (Basic.typeOf(data) === 'string') {
+ data = Basic.sprintf.apply(this, arguments);
+ }
+
+ if (window && window.console && window.console.log) {
+ window.console.log(data);
+ } 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);
+ }
+
+ if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) {
+ logObj(data);
+ } else {
+ console.appendChild(document.createTextNode(data + "\n"));
+ }
+ }
+ };
+ }
+
+ return Env;
+});
+
+// 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 = {};
+
+ 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
+ */
+
+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," +
+ "application/vnd.ms-powerpoint,ppt pps pot," +
+ "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";
+
+
+ var Mime = {
+
+ mimes: {},
+
+ extensions: {},
+
+ // Parses the default mime types string into a mimes and extensions lookup maps
+ 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++) {
+ this.mimes[ext[ii]] = items[i];
+ }
+ // mime to extension lookup
+ this.extensions[items[i]] = ext;
+ }
+ },
+
+
+ extList2mimes: function (filters, addMissingExtensions) {
+ var self = this, ext, i, ii, type, mimes = [];
+
+ // convert extensions to mime types list
+ for (i = 0; i < filters.length; i++) {
+ ext = filters[i].extensions.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 = self.mimes[ext[ii]];
+ if (type && Basic.inArray(type, mimes) === -1) {
+ mimes.push(type);
+ }
+
+ // future browsers should filter by extension, finally
+ if (addMissingExtensions && /^\w+$/.test(ext[ii])) {
+ mimes.push('.' + ext[ii]);
+ } else if (!type) {
+ // if we have no type in our map, then accept all
+ return [];
+ }
+ }
+ }
+ return mimes;
+ },
+
+
+ mimes2exts: function(mimes) {
+ var self = this, exts = [];
+
+ Basic.each(mimes, function(mime) {
+ 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(self.extensions, function(arr, mime) {
+ if ((new RegExp('^' + m[1] + '/')).test(mime)) {
+ [].push.apply(exts, self.extensions[mime]);
+ }
+ });
+ } else if (self.extensions[mime]) {
+ [].push.apply(exts, self.extensions[mime]);
+ }
+ }
+ });
+ return exts;
+ },
+
+
+ mimes2extList: function(mimes) {
+ var accept = [], exts = [];
+
+ if (Basic.typeOf(mimes) === 'string') {
+ mimes = Basic.trim(mimes).split(/\s*,\s*/);
+ }
+
+ exts = this.mimes2exts(mimes);
+
+ accept.push({
+ title: I18n.translate('Files'),
+ extensions: exts.length ? exts.join(',') : '*'
+ });
+
+ // save original mimes string
+ accept.mimes = mimes;
+
+ return accept;
+ },
+
+
+ getFileExtension: function(fileName) {
+ var matches = fileName && fileName.match(/\.([^.]+)$/);
+ if (matches) {
+ return matches[1].toLowerCase();
+ }
+ return '';
+ },
+
+ getFileMime: function(fileName) {
+ return this.mimes[this.getFileExtension(fileName)] || '';
+ }
+ };
+
+ Mime.addMimeType(mimeData);
+
+ return Mime;
+});
+
+// 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
+ */
+
+define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
+
+ /**
+ Get DOM Element by it's id.
+
+ @method get
+ @for Utils
+ @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/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;
+ }
+
+ return {
+ RuntimeError: (function() {
+ var namecodes = {
+ NOT_INIT_ERR: 1,
+ NOT_SUPPORTED_ERR: 9,
+ JS_ERR: 4
+ };
+
+ function RuntimeError(code) {
+ this.code = code;
+ this.name = _findKey(namecodes, code);
+ this.message = this.name + ": 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/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) {
+ /**
+ Parent object for all event dispatching components and objects
+
+ @class EventTarget
+ @constructor EventTarget
+ */
+ function EventTarget() {
+ // hash of event listeners by object uid
+ var eventpool = {};
+
+ Basic.extend(this, {
+
+ /**
+ Unique id of the event dispatcher, usually overriden by children
+
+ @property uid
+ @type String
+ */
+ uid: null,
+
+ /**
+ 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 = type ? eventpool[this.uid] && eventpool[this.uid][type] : 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) {
+ type = type.toLowerCase();
+
+ var list = eventpool[this.uid] && eventpool[this.uid][type], i;
+
+ 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("Event '%s' fired on %u", evt.type, 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;
+ },
+
+ /**
+ 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 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 = this.options.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%c: %v (conflicting mode requested: %s)", cap, value, capMode);
+ }
+
+ return (mode = false);
+ }
+ }
+
+ if (MXI_DEBUG && Env.debug.runtime) {
+ Env.log("\t\t%c: %v (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;
+ };
+
+
+ /**
+ 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 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) {
+ 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++;
+ // 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() { });*/
+
+ 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) {
+ 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() {
+ if (runtime) {
+ return runtime.exec.apply(this, arguments);
+ }
+ return null;
+ }
+
+ });
+ };
+
+
+});
+
+// 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 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 {String} [options.file='file'] Name of the file field (not the filename).
+ @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
+
+
+
+ */
+ 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 self = this,
+ 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: '*'
+ }],
+ name: 'file',
+ 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(self);
+
+ Basic.extend(self, {
+ /**
+ 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 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() {
+ 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;
+
+ 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);
+
+ if (shimContainer) {
+ Basic.extend(shimContainer.style, {
+ top : pos.y + 'px',
+ left : pos.x + 'px',
+ width : size.w + 'px',
+ height : size.h + 'px'
+ });
+ }
+ }
+ 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
+ }
+ }));
+ },
+
+ /**
+ 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) {
+ runtime.exec.call(this, '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() {
+ self.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/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
+ */
+
+define('moxie/core/utils/Encode', [], function() {
+
+ /**
+ Encode string with UTF-8
+
+ @method utf8_encode
+ @for Utils
+ @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/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 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/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 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
+
+ Drop files here
+
+
+
+
+
+
+ @class 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 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
+ */
+
+define('moxie/core/utils/Url', [], function() {
+ /**
+ 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
+ @for Utils
+ @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 = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
+ , m = regex.exec(url || '')
+ ;
+
+ while (i--) {
+ if (m[i]) {
+ uri[key[i]] = m[i];
+ }
+ }
+
+ // when url is relative, we set the origin and the path ourselves
+ if (!uri.scheme) {
+ // come up with defaults
+ if (!currentUrl || typeof(currentUrl) === 'string') {
+ currentUrl = parseUrl(currentUrl || document.location.href);
+ }
+
+ uri.scheme = currentUrl.scheme;
+ 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
+ @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 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 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 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 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;
+ },
+
+ /**
+ 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) {
+ 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 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 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, mOxie.Blob/mOxie.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();
+ img.onload = function() {
+ var blob = img.getAsBlob();
+
+ var formData = new mOxie.FormData();
+ formData.append('file', blob);
+
+ var xhr = new mOxie.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);
+ },
+
+ /**
+ Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions.
+
+ @method downsize
+ @param {Object} opts
+ @param {Number} opts.width Resulting width
+ @param {Number} [opts.height=width] Resulting height (optional, if not supplied will default to width)
+ @param {Boolean} [opts.crop=false] Whether to crop the image to exact dimensions
+ @param {Boolean} [opts.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
+ @param {String} [opts.resample=false] Resampling algorithm to use for resizing
+ */
+ downsize: function(opts) {
+ var defaults = {
+ width: this.width,
+ height: this.height,
+ type: this.type || 'image/jpeg',
+ quality: 90,
+ crop: false,
+ preserveHeaders: true,
+ resample: false
+ };
+
+ if (typeof(opts) === 'object') {
+ opts = Basic.extend(defaults, opts);
+ } else {
+ // for backward compatibility
+ opts = Basic.extend(defaults, {
+ width: arguments[0],
+ height: arguments[1],
+ crop: arguments[2],
+ preserveHeaders: arguments[3]
+ });
+ }
+
+ try {
+ if (!this.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 (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
+ throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
+ }
+
+ this.exec('Image', 'downsize', opts.width, opts.height, opts.crop, opts.preserveHeaders);
+ } catch(ex) {
+ // for now simply trigger error event
+ this.trigger('error', ex.code);
+ }
+ },
+
+ /**
+ 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);
+ }
+
+ var runtime = this.connectRuntime(this.ruid);
+ return runtime.exec.call(this, 'Image', 'getAsCanvas');
+ },
+
+ /**
+ Retrieves image in it's current state as mOxie.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} [opts]
+ @param {Number} [opts.width] The width of an embed (defaults to the image width)
+ @param {Number} [opts.height] The height of an embed (defaults to the image height)
+ @param {String} [type="image/jpeg"] Mime type
+ @param {Number} [quality=90] Quality of an embed, if mime type is image/jpeg
+ @param {Boolean} [crop=false] Whether to crop an embed to the specified dimensions
+ */
+ embed: function(el, opts) {
+ var self = this
+ , runtime // this has to be outside of all the closures to contain proper runtime
+ ;
+
+ opts = Basic.extend({
+ width: this.width,
+ height: this.height,
+ type: this.type || 'image/jpeg',
+ quality: 90
+ }, opts || {});
+
+
+ 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.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() {
+ imgCopy.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 object.
+
+ @method destroy
+ */
+ destroy: function() {
+ if (this.ruid) {
+ this.getRuntime().exec.call(this, 'Image', 'destroy');
+ this.disconnectRuntime();
+ }
+ 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() {
+ _updateInfo.call(this);
+ }, 999);
+
+
+ function _updateInfo(info) {
+ 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;
+ }
+ }
+
+
+ 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')),
+ 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, '>='));
+ }()),
+ 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, '>=');
+ },
+ 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, '>=')) ||
+ !!~Basic.inArray(Env.browser, ['Chrome', 'Safari'])
+ );
+ },
+ upload_filesize: 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/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
+ */
+
+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
+ @for Utils
+ @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;
+
+ 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 = _options.accept.mimes || Mime.extList2mimes(_options.accept, I.can('filter_by_extension'));
+
+ shimContainer = I.getShimContainer();
+
+ shimContainer.innerHTML = ' ';
+
+ 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);
+
+ // 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';
+ }
+
+ zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1;
+
+ browseButton.style.zIndex = zIndex;
+ shimContainer.style.zIndex = zIndex - 1;
+
+ 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);
+ }
+
+ /* 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);
+
+
+ input.onchange = function onChange(e) { // 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;
+ },
+
+
+ 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()
+ ;
+
+ Events.removeAllEvents(shimContainer, this.uid);
+ Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
+ Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid);
+
+ if (shimContainer) {
+ shimContainer.innerHTML = '';
+ }
+
+ shim.removeInstance(this.uid);
+
+ _options = shimContainer = shim = null;
+ }
+ });
+ }
+
+ return (extensions.FileInput = FileInput);
+});
+
+// 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));
+ };
+ }
+
+ return (extensions.Blob = HTML5Blob);
+});
+
+// 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;
+ }
+ });
+
+
+ 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;
+ }
+ });
+
+ 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
+ if (_xhr.status === 0) {
+ target.trigger('error');
+ } else {
+ target.trigger('load');
+ }
+ 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;
+ }
+ });
+
+
+ // 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
+ */
+
+/**
+@class moxie/runtime/html5/image/ImageInfo
+@private
+*/
+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) {
+ /**
+ 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 ImageInfo
+ @constructor
+ @param {String} data Image source as binary string
+ */
+ 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/MegaPixel.js
+
+/**
+(The MIT License)
+
+Copyright (c) 2012 Shinichi Tomita ;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/**
+ * Mega pixel image rendering library for iOS6 Safari
+ *
+ * Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel),
+ * which causes unexpected subsampling when drawing it in canvas.
+ * By using this library, you can safely render the image with proper stretching.
+ *
+ * Copyright (c) 2012 Shinichi Tomita
+ * Released under the MIT license
+ */
+
+/**
+@class moxie/runtime/html5/image/MegaPixel
+@private
+*/
+define("moxie/runtime/html5/image/MegaPixel", [], function() {
+
+ /**
+ * Rendering image element (with resizing) into the canvas element
+ */
+ function renderImageToCanvas(img, canvas, options) {
+ var iw = img.naturalWidth, ih = img.naturalHeight;
+ var width = options.width, height = options.height;
+ var x = options.x || 0, y = options.y || 0;
+ var ctx = canvas.getContext('2d');
+ if (detectSubsampling(img)) {
+ iw /= 2;
+ ih /= 2;
+ }
+ var d = 1024; // size of tiling canvas
+ var tmpCanvas = document.createElement('canvas');
+ tmpCanvas.width = tmpCanvas.height = d;
+ var tmpCtx = tmpCanvas.getContext('2d');
+ var vertSquashRatio = detectVerticalSquash(img, iw, ih);
+ var sy = 0;
+ while (sy < ih) {
+ var sh = sy + d > ih ? ih - sy : d;
+ var sx = 0;
+ while (sx < iw) {
+ var sw = sx + d > iw ? iw - sx : d;
+ tmpCtx.clearRect(0, 0, d, d);
+ tmpCtx.drawImage(img, -sx, -sy);
+ var dx = (sx * width / iw + x) << 0;
+ var dw = Math.ceil(sw * width / iw);
+ var dy = (sy * height / ih / vertSquashRatio + y) << 0;
+ var dh = Math.ceil(sh * height / ih / vertSquashRatio);
+ ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
+ sx += d;
+ }
+ sy += d;
+ }
+ tmpCanvas = tmpCtx = null;
+ }
+
+ /**
+ * Detect subsampling in loaded image.
+ * In iOS, larger images than 2M pixels may be subsampled in rendering.
+ */
+ function detectSubsampling(img) {
+ var iw = img.naturalWidth, ih = img.naturalHeight;
+ if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image
+ var canvas = document.createElement('canvas');
+ canvas.width = canvas.height = 1;
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(img, -iw + 1, 0);
+ // subsampled image becomes half smaller in rendering size.
+ // check alpha channel value to confirm image is covering edge pixel or not.
+ // if alpha value is 0 image is not covering, hence subsampled.
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Detecting vertical squash in loaded image.
+ * Fixes a bug which squash image vertically while drawing into canvas for some images.
+ */
+ function detectVerticalSquash(img, iw, ih) {
+ var canvas = document.createElement('canvas');
+ canvas.width = 1;
+ canvas.height = ih;
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0);
+ var data = ctx.getImageData(0, 0, 1, ih).data;
+ // search image edge pixel position in case it is squashed vertically.
+ var sy = 0;
+ var ey = ih;
+ var py = ih;
+ while (py > sy) {
+ var alpha = data[(py - 1) * 4 + 3];
+ if (alpha === 0) {
+ ey = py;
+ } else {
+ sy = py;
+ }
+ py = (ey + sy) >> 1;
+ }
+ canvas = null;
+ var ratio = (py / ih);
+ return (ratio === 0) ? 1 : ratio;
+ }
+
+ return {
+ isSubsampled: detectSubsampling,
+ renderTo: renderImageToCanvas
+ };
+});
+
+// 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/MegaPixel",
+ "moxie/core/utils/Mime",
+ "moxie/core/utils/Env"
+], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, MegaPixel, 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 comp = this, I = comp.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(comp, 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);
+ }
+
+ 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: _imgInfo && _imgInfo.meta || this.meta || {}
+ };
+
+ // store thumbnail data as 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;
+ },
+
+ downsize: function() {
+ _downsize.apply(this, arguments);
+ },
+
+ getAsCanvas: function() {
+ if (_canvas) {
+ _canvas.id = this.uid + '_canvas';
+ }
+ return _canvas;
+ },
+
+ getAsBlob: function(type, quality) {
+ if (type !== this.type) {
+ // if different mime type requested prepare image for conversion
+ _downsize.call(this, this.width, this.height, false);
+ }
+ return new File(null, {
+ name: _blob.name || '',
+ type: type,
+ data: me.getAsBinaryString.call(this, 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;
+ }
+
+ 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;
+ }
+
+ 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 _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(this.result);
+ };
+ fr.onerror = function() {
+ comp.trigger('error', x.ImageError.WRONG_FORMAT);
+ };
+ fr.readAsDataURL(file);
+ } else {
+ return callback(file.getAsDataURL());
+ }
+ }
+
+ function _downsize(width, height, crop, preserveHeaders) {
+ var self = this
+ , scale
+ , mathFn
+ , x = 0
+ , y = 0
+ , img
+ , destWidth
+ , destHeight
+ , orientation
+ ;
+
+ _preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString())
+
+ // take into account orientation tag
+ orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
+
+ if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation
+ // swap dimensions
+ var tmp = width;
+ width = height;
+ height = tmp;
+ }
+
+ img = _getImg();
+
+ // unify dimensions
+ if (!crop) {
+ scale = Math.min(width/img.width, height/img.height);
+ } else {
+ // one of the dimensions may exceed the actual image dimensions - we need to take the smallest value
+ width = Math.min(width, img.width);
+ height = Math.min(height, img.height);
+
+ scale = Math.max(width/img.width, height/img.height);
+ }
+
+ // we only downsize here
+ if (scale > 1 && !crop && preserveHeaders) {
+ this.trigger('Resize');
+ return;
+ }
+
+ // prepare canvas if necessary
+ if (!_canvas) {
+ _canvas = document.createElement("canvas");
+ }
+
+ // calculate dimensions of proportionally resized image
+ destWidth = Math.round(img.width * scale);
+ destHeight = Math.round(img.height * scale);
+
+ // scale image and canvas
+ if (crop) {
+ _canvas.width = width;
+ _canvas.height = height;
+
+ // if dimensions of the resulting image still larger than canvas, center it
+ if (destWidth > width) {
+ x = Math.round((destWidth - width) / 2);
+ }
+
+ if (destHeight > height) {
+ y = Math.round((destHeight - height) / 2);
+ }
+ } else {
+ _canvas.width = destWidth;
+ _canvas.height = destHeight;
+ }
+
+ // rotate if required, according to orientation tag
+ if (!_preserveHeaders) {
+ _rotateToOrientaion(_canvas.width, _canvas.height, orientation);
+ }
+
+ _drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight);
+
+ this.width = _canvas.width;
+ this.height = _canvas.height;
+
+ _modified = true;
+ self.trigger('Resize');
+ }
+
+
+ function _drawToCanvas(img, canvas, x, y, w, h) {
+ if (Env.OS === 'iOS') {
+ // avoid squish bug in iOS6
+ MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y });
+ } else {
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(img, x, y, w, h);
+ }
+ }
+
+
+ /**
+ * Transform canvas coordination according to specified frame size and orientation
+ * Orientation value is from EXIF tag
+ * @author Shinichi Tomita
+ */
+ function _rotateToOrientaion(width, height, orientation) {
+ switch (orientation) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ _canvas.width = height;
+ _canvas.height = width;
+ break;
+ default:
+ _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.
+ */
+
+ var ctx = _canvas.getContext('2d');
+ 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(Math.PI);
+ break;
+ case 4:
+ // vertical flip
+ ctx.translate(0, height);
+ ctx.scale(1, -1);
+ break;
+ case 5:
+ // vertical flip + 90 rotate right
+ ctx.rotate(0.5 * Math.PI);
+ ctx.scale(1, -1);
+ break;
+ case 6:
+ // 90 rotate right
+ ctx.rotate(0.5 * Math.PI);
+ ctx.translate(0, -height);
+ break;
+ case 7:
+ // horizontal flip + 90 rotate right
+ ctx.rotate(0.5 * Math.PI);
+ ctx.translate(width, -height);
+ ctx.scale(-1, 1);
+ break;
+ case 8:
+ // 90 rotate left
+ ctx.rotate(-0.5 * Math.PI);
+ ctx.translate(-width, 0);
+ break;
+ }
+ }
+
+
+ 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
+ */
+ 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
+
+ @class FlashRuntime
+ @extends 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.capTrue,
+ 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';
+ },
+ 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() < 10) {
+ if (MXI_DEBUG && Env.debug.runtime) {
+ Env.log("\tFlash didn't meet minimal version requirement (10).");
+ }
+
+ 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 = '' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ';
+
+ 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/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/Basic"
+], function(extensions, File, Basic) {
+
+ var FileInput = {
+ init: function(options) {
+ var comp = this, I = this.getRuntime();
+
+ 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', {
+ name: options.name,
+ accept: options.accept,
+ multiple: options.multiple
+ });
+
+ this.trigger('ready');
+ }
+ };
+
+ return (extensions.FileInput = FileInput);
+});
+
+// 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/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/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/xhr/FormData",
+ "moxie/runtime/Transporter"
+], function(extensions, Basic, Blob, File, FileReaderSync, FormData, Transporter) {
+
+ 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/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/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 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
+
+ @class SilverlightRuntime
+ @extends 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.capTrue,
+ 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 = '' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ';
+
+ // 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/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/Basic"
+], function(extensions, File, Basic) {
+
+ var FileInput = {
+ init: function(options) {
+ var comp = this, I = this.getRuntime();
+
+ 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;
+ }
+
+ 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', toFilters(options.accept), options.name, options.multiple);
+ this.trigger('ready');
+ }
+ };
+
+ return (extensions.FileInput = FileInput);
+});
+
+// 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/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/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"
+], function(extensions, Basic, XMLHttpRequest) {
+ return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest));
+});
+
+// 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/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 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;
+ }
+ }));
+});
+
+// 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(extensions.Image && (Env.can('create_canvas') || Env.can('use_data_uri_over32kb'))),
+ 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, '>='));
+ }()),
+ 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, '>=')) ||
+ !!~Basic.inArray(Env.browser, ['Chrome', 'Safari'])
+ );
+ },
+ 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;
+
+ 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 everytime 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%' });
+ }
+ }
+
+ // 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('name', _options.name || 'Filedata');
+ input.setAttribute('accept', _mimes.join(','));
+
+ 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];
+
+ // ignore empty files (IE10 for example hangs if you try to send them via XHR)
+ if (file.size === 0) {
+ form.parentNode.removeChild(form);
+ return;
+ }
+ } 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 = options.accept.mimes || Mime.extList2mimes(options.accept, I.can('filter_by_extension'));
+
+ shimContainer = I.getShimContainer();
+
+ (function() {
+ var browseButton, zIndex, top;
+
+ browseButton = Dom.get(options.browse_button);
+
+ // 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';
+ }
+
+ zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1;
+
+ browseButton.style.zIndex = zIndex;
+ shimContainer.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);
+
+ browseButton = null;
+ }());
+
+ addInput.call(this);
+
+ shimContainer = null;
+
+ // trigger ready event asynchronously
+ comp.trigger({
+ type: 'ready',
+ async: true
+ });
+ },
+
+
+ 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()
+ ;
+
+ Events.removeAllEvents(shimContainer, this.uid);
+ Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
+ Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid);
+
+ if (shimContainer) {
+ shimContainer.innerHTML = '';
+ }
+
+ shim.removeInstance(this.uid);
+
+ _uid = _mimes = _options = shimContainer = 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 = 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 .. tags that might be enclosing the response
+ if (Basic.typeOf(_response) === 'string' && !!window.JSON) {
+ try {
+ return JSON.parse(_response.replace(/^\s*]*>/, '').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');
+ });
+ }
+ });
+ }
+
+ 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/Env","moxie/core/I18n","moxie/core/utils/Mime","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/FileInput","moxie/core/utils/Encode","moxie/file/Blob","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events"]);
+})(this);
+/**
+ * o.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/*global moxie:true */
+
+/**
+Globally exposed namespace with the most frequently used public classes and handy methods.
+
+@class o
+@static
+@private
+*/
+(function(exports) {
+ "use strict";
+
+ var o = {}, inArray = exports.moxie.core.utils.Basic.inArray;
+
+ // directly add some public classes
+ // (we do it dynamically here, since for custom builds we cannot know beforehand what modules were included)
+ (function addAlias(ns) {
+ var name, itemType;
+ for (name in ns) {
+ itemType = typeof(ns[name]);
+ if (itemType === 'object' && !~inArray(name, ['Exceptions', 'Env', 'Mime'])) {
+ addAlias(ns[name]);
+ } else if (itemType === 'function') {
+ o[name] = ns[name];
+ }
+ }
+ })(exports.moxie);
+
+ // add some manually
+ o.Env = exports.moxie.core.utils.Env;
+ o.Mime = exports.moxie.core.utils.Mime;
+ o.Exceptions = exports.moxie.core.Exceptions;
+
+ // expose globally
+ exports.mOxie = o;
+ if (!exports.o) {
+ exports.o = o;
+ }
+ return o;
+})(this);
diff --git a/qiniu_fields/static/qiniu_fields/plupload/moxie.min.js b/qiniu_fields/static/qiniu_fields/plupload/moxie.min.js
new file mode 100644
index 0000000..dfd12b0
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/plupload/moxie.min.js
@@ -0,0 +1,16 @@
+/**
+ * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
+ * v1.3.4
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ *
+ * Date: 2015-07-18
+ */
+!function(e,t){"use strict";function n(e,t){for(var n,i=[],r=0;r0&&n(o,function(n,o){n!==r&&(e(i[o])===e(n)&&~a(e(n),["array","object"])?t(i[o],n):i[o]=n)})}),i},n=function(t,n){var i,r,o,a;if(t)if("number"===e(t.length)){for(o=0,i=t.length;i>o;o++)if(n(t[o],o)===!1)return}else if("object"===e(t))for(r in t)if(t.hasOwnProperty(r)&&n(t[r],r)===!1)return},i=function(t){var n;if(!t||"object"!==e(t))return!0;for(n in t)return!1;return!0},r=function(t,n){function i(r){"function"===e(t[r])&&t[r](function(e){++rn;n++)if(t[n]===e)return n}return-1},s=function(t,n){var i=[];"array"!==e(t)&&(t=[t]),"array"!==e(n)&&(n=[n]);for(var r in t)-1===a(t[r],n)&&i.push(t[r]);return i.length?i:!1},u=function(e,t){var i=[];return n(e,function(e){-1!==a(e,t)&&i.push(e)}),i.length?i:null},c=function(e){var t,n=[];for(t=0;ti;i++)n+=Math.floor(65535*Math.random()).toString(32);return(t||"o_")+n+(e++).toString(32)}}(),d=function(e){return e?String.prototype.trim?String.prototype.trim.call(e):e.toString().replace(/^\s*/,"").replace(/\s*$/,""):e},h=function(e){if("string"!=typeof e)return e;var t={t:1099511627776,g:1073741824,m:1048576,k:1024},n;return e=/^([0-9\.]+)([tmgk]?)$/.exec(e.toLowerCase().replace(/[^0-9\.tmkg]/g,"")),n=e[2],e=+e[1],t.hasOwnProperty(n)&&(e*=t[n]),Math.floor(e)},f=function(t){var n=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=n.shift();return"undefined"!==e(t)?t:""})};return{guid:l,typeOf:e,extend:t,each:n,isEmptyObj:i,inSeries:r,inParallel:o,inArray:a,arrayDiff:s,arrayIntersect:u,toArray:c,trim:d,sprintf:f,parseSizeStr:h}}),i(c,[u],function(e){function t(e,t,n){var i=0,r=0,o=0,a={dev:-6,alpha:-5,a:-5,beta:-4,b:-4,RC:-3,rc:-3,"#":-2,p:1,pl:1},s=function(e){return e=(""+e).replace(/[_\-+]/g,"."),e=e.replace(/([^.\d]+)/g,".$1.").replace(/\.{2,}/g,"."),e.length?e.split("."):[-8]},u=function(e){return e?isNaN(e)?a[e]||-7:parseInt(e,10):0};for(e=s(e),t=s(t),r=Math.max(e.length,t.length),i=0;r>i;i++)if(e[i]!=t[i]){if(e[i]=u(e[i]),t[i]=u(t[i]),e[i]t[i]){o=1;break}}if(!n)return o;switch(n){case">":case"gt":return o>0;case">=":case"ge":return o>=0;case"<=":case"le":return 0>=o;case"==":case"=":case"eq":return 0===o;case"<>":case"!=":case"ne":return 0!==o;case"":case"<":case"lt":return 0>o;default:return null}}var n=function(e){var t="",n="?",i="function",r="undefined",o="object",a="major",s="model",u="name",c="type",l="vendor",d="version",h="architecture",f="console",p="mobile",m="tablet",g={has:function(e,t){return-1!==t.toLowerCase().indexOf(e.toLowerCase())},lowerize:function(e){return e.toLowerCase()}},v={rgx:function(){for(var t,n=0,a,s,u,c,l,d,h=arguments;n0?2==c.length?typeof c[1]==i?t[c[0]]=c[1].call(this,d):t[c[0]]=c[1]:3==c.length?typeof c[1]!==i||c[1].exec&&c[1].test?t[c[0]]=d?d.replace(c[1],c[2]):e:t[c[0]]=d?c[1].call(this,d,c[2]):e:4==c.length&&(t[c[0]]=d?c[3].call(this,d.replace(c[1],c[2])):e):t[c]=d?d:e;break}if(l)break}return t},str:function(t,i){for(var r in i)if(typeof i[r]===o&&i[r].length>0){for(var a=0;a=9)},use_data_uri_of:function(e){return t.use_data_uri&&33e3>e||t.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!1;var e=document.createElement("input");return e.setAttribute("type","file"),!e.disabled}};return function(n){var i=[].slice.call(arguments);return i.shift(),"function"===e.typeOf(t[n])?t[n].apply(this,i):!!t[n]}}(),r=(new n).getResult(),o={can:i,uaParser:n,browser:r.browser.name,version:r.browser.version,os:r.os.name,osVersion:r.os.version,verComp:t,swf_url:"../flash/Moxie.swf",xap_url:"../silverlight/Moxie.xap",global_event_dispatcher:"moxie.core.EventTarget.instance.dispatchEvent"};return o.OS=o.os,o}),i(l,[u],function(e){var t={};return{addI18n:function(n){return e.extend(t,n)},translate:function(e){return t[e]||e},_:function(e){return this.translate(e)},sprintf:function(t){var n=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=n.shift();return"undefined"!==e.typeOf(t)?t:""})}}}),i(d,[u,l],function(e,t){var n="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,application/vnd.ms-powerpoint,ppt pps pot,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",i={mimes:{},extensions:{},addMimeType:function(e){var t=e.split(/,/),n,i,r;for(n=0;n=0;o--)if(r[o].fn===i){r.splice(o,1);break}}else r=[];r.length||(delete e[this.uid][t],n.isEmptyObj(e[this.uid])&&delete e[this.uid])}},removeAllEventListeners:function(){e[this.uid]&&delete e[this.uid]},dispatchEvent:function(i){var r,o,a,s,u={},c=!0,l;if("string"!==n.typeOf(i)){if(s=i,"string"!==n.typeOf(s.type))throw new t.EventException(t.EventException.UNSPECIFIED_EVENT_TYPE_ERR);i=s.type,s.total!==l&&s.loaded!==l&&(u.total=s.total,u.loaded=s.loaded),u.async=s.async||!1}if(-1!==i.indexOf("::")?!function(e){r=e[0],i=e[1]}(i.split("::")):r=this.uid,i=i.toLowerCase(),o=e[r]&&e[r][i]){o.sort(function(e,t){return t.priority-e.priority}),a=[].slice.call(arguments),a.shift(),u.type=i,a.unshift(u);var d=[];n.each(o,function(e){a[0].target=e.scope,d.push(u.async?function(t){setTimeout(function(){t(e.fn.apply(e.scope,a)===!1)},1)}:function(t){t(e.fn.apply(e.scope,a)===!1)})}),d.length&&n.inSeries(d,function(e){c=!e})}return c},bind:function(){this.addEventListener.apply(this,arguments)},unbind:function(){this.removeEventListener.apply(this,arguments)},unbindAll:function(){this.removeAllEventListeners.apply(this,arguments)},trigger:function(){return this.dispatchEvent.apply(this,arguments)},handleEventProps:function(e){var t=this;this.bind(e.join(" "),function(e){var t="on"+e.type.toLowerCase();"function"===n.typeOf(this[t])&&this[t].apply(this,arguments)}),n.each(e,function(e){e="on"+e.toLowerCase(e),"undefined"===n.typeOf(t[e])&&(t[e]=null)})}})}return i.instance=new i,i}),i(m,[c,u,h,p],function(e,t,n,i){function r(e,i,o,s,u){var c=this,l,d=t.guid(i+"_"),h=u||"browser";e=e||{},a[d]=this,o=t.extend({access_binary:!1,access_image_binary:!1,display_media:!1,do_cors:!1,drag_and_drop:!1,filter_by_extension:!0,resize_image:!1,report_upload_progress:!1,return_response_headers:!1,return_response_type:!1,return_status_code:!0,send_custom_headers:!1,select_file:!1,select_folder:!1,select_multiple:!0,send_binary_string:!1,send_browser_cookies:!0,send_multipart:!0,slice_blob:!1,stream_upload:!1,summon_file_dialog:!1,upload_filesize:!0,use_http_method:!0},o),e.preferred_caps&&(h=r.getMode(s,e.preferred_caps,h)),l=function(){var e={};return{exec:function(t,n,i,r){return l[n]&&(e[t]||(e[t]={context:this,instance:new l[n]}),e[t].instance[i])?e[t].instance[i].apply(this,r):void 0},removeInstance:function(t){delete e[t]},removeAllInstances:function(){var n=this;t.each(e,function(e,i){"function"===t.typeOf(e.instance.destroy)&&e.instance.destroy.call(e.context),n.removeInstance(i)})}}}(),t.extend(this,{initialized:!1,uid:d,type:i,mode:r.getMode(s,e.required_caps,h),shimid:d+"_container",clients:0,options:e,can:function(e,n){var i=arguments[2]||o;if("string"===t.typeOf(e)&&"undefined"===t.typeOf(n)&&(e=r.parseCaps(e)),"object"===t.typeOf(e)){for(var a in e)if(!this.can(a,e[a],i))return!1;return!0}return"function"===t.typeOf(i[e])?i[e].call(this,n):n===i[e]},getShimContainer:function(){var e,i=n.get(this.shimid);return i||(e=this.options.container?n.get(this.options.container):document.body,i=document.createElement("div"),i.id=this.shimid,i.className="moxie-shim moxie-shim-"+this.type,t.extend(i.style,{position:"absolute",top:"0px",left:"0px",width:"1px",height:"1px",overflow:"hidden"}),e.appendChild(i),e=null),i},getShim:function(){return l},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec.call(this,this.uid,e,t,n)},exec:function(e,t){var n=[].slice.call(arguments,2);return c[e]&&c[e][t]?c[e][t].apply(this,n):c.shimExec.apply(this,arguments)},destroy:function(){if(c){var e=n.get(this.shimid);e&&e.parentNode.removeChild(e),l&&l.removeAllInstances(),this.unbindAll(),delete a[this.uid],this.uid=null,d=c=l=e=null}}}),this.mode&&e.required_caps&&!this.can(e.required_caps)&&(this.mode=!1)}var o={},a={};return r.order="html5,flash,silverlight,html4",r.getRuntime=function(e){return a[e]?a[e]:!1},r.addConstructor=function(e,t){t.prototype=i.instance,o[e]=t},r.getConstructor=function(e){return o[e]||null},r.getInfo=function(e){var t=r.getRuntime(e);return t?{uid:t.uid,type:t.type,mode:t.mode,can:function(){return t.can.apply(t,arguments)}}:null},r.parseCaps=function(e){var n={};return"string"!==t.typeOf(e)?e||{}:(t.each(e.split(","),function(e){n[e]=!0}),n)},r.can=function(e,t){var n,i=r.getConstructor(e),o;return i?(n=new i({required_caps:t}),o=n.mode,n.destroy(),!!o):!1},r.thatCan=function(e,t){var n=(t||r.order).split(/\s*,\s*/);for(var i in n)if(r.can(n[i],e))return n[i];return null},r.getMode=function(e,n,i){var r=null;if("undefined"===t.typeOf(i)&&(i="browser"),n&&!t.isEmptyObj(e)){if(t.each(n,function(n,i){if(e.hasOwnProperty(i)){var o=e[i](n);if("string"==typeof o&&(o=[o]),r){if(!(r=t.arrayIntersect(r,o)))return r=!1}else r=o}}),r)return-1!==t.inArray(i,r)?i:r[0];if(r===!1)return!1}return i},r.capTrue=function(){return!0},r.capFalse=function(){return!1},r.capTest=function(e){return function(){return!!e}},r}),i(g,[c,f,u,m],function(e,t,n,i){return function r(){var e;n.extend(this,{connectRuntime:function(r){function o(n){var s,u;return n.length?(s=n.shift().toLowerCase(),(u=i.getConstructor(s))?(e=new u(r),e.bind("Init",function(){e.initialized=!0,setTimeout(function(){e.clients++,a.trigger("RuntimeInit",e)},1)}),e.bind("Error",function(){e.destroy(),o(n)}),e.mode?void e.init():void e.trigger("Error")):void o(n)):(a.trigger("RuntimeError",new t.RuntimeError(t.RuntimeError.NOT_INIT_ERR)),void(e=null))}var a=this,s;if("string"===n.typeOf(r)?s=r:"string"===n.typeOf(r.ruid)&&(s=r.ruid),s){if(e=i.getRuntime(s))return e.clients++,e;throw new t.RuntimeError(t.RuntimeError.NOT_INIT_ERR)}o((r.runtime_order||i.order).split(/\s*,\s*/))},disconnectRuntime:function(){e&&--e.clients<=0&&e.destroy(),e=null},getRuntime:function(){return e&&e.uid?e:e=null},exec:function(){return e?e.exec.apply(this,arguments):null}})}}),i(v,[u,c,d,h,f,p,l,m,g],function(e,t,n,i,r,o,a,s,u){function c(t){var o=this,c,d,h;if(-1!==e.inArray(e.typeOf(t),["string","node"])&&(t={browse_button:t}),d=i.get(t.browse_button),!d)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR);h={accept:[{title:a.translate("All Files"),extensions:"*"}],name:"file",multiple:!1,required_caps:!1,container:d.parentNode||document.body},t=e.extend({},h,t),"string"==typeof t.required_caps&&(t.required_caps=s.parseCaps(t.required_caps)),"string"==typeof t.accept&&(t.accept=n.mimes2extList(t.accept)),c=i.get(t.container),c||(c=document.body),"static"===i.getStyle(c,"position")&&(c.style.position="relative"),c=d=null,u.call(o),e.extend(o,{uid:e.guid("uid_"),ruid:null,shimid:null,files:null,init:function(){o.bind("RuntimeInit",function(n,r){o.ruid=r.uid,o.shimid=r.shimid,o.bind("Ready",function(){o.trigger("Refresh")},999),o.bind("Refresh",function(){var n,o,a,s;a=i.get(t.browse_button),s=i.get(r.shimid),a&&(n=i.getPos(a,i.get(t.container)),o=i.getSize(a),s&&e.extend(s.style,{top:n.y+"px",left:n.x+"px",width:o.w+"px",height:o.h+"px"})),s=a=null}),r.exec.call(o,"FileInput","init",t)}),o.connectRuntime(e.extend({},t,{required_caps:{select_file:!0}}))},disable:function(t){var n=this.getRuntime();n&&n.exec.call(this,"FileInput","disable","undefined"===e.typeOf(t)?!0:t)},refresh:function(){o.trigger("Refresh")},destroy:function(){var t=this.getRuntime();t&&(t.exec.call(this,"FileInput","destroy"),this.disconnectRuntime()),"array"===e.typeOf(this.files)&&e.each(this.files,function(e){e.destroy()}),this.files=null,this.unbindAll()}}),this.handleEventProps(l)}var l=["ready","change","cancel","mouseenter","mouseleave","mousedown","mouseup"];return c.prototype=o.instance,c}),i(w,[],function(){var e=function(e){return unescape(encodeURIComponent(e))},t=function(e){return decodeURIComponent(escape(e))},n=function(e,n){if("function"==typeof window.atob)return n?t(window.atob(e)):window.atob(e);var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",r,o,a,s,u,c,l,d,h=0,f=0,p="",m=[];if(!e)return e;e+="";do s=i.indexOf(e.charAt(h++)),u=i.indexOf(e.charAt(h++)),c=i.indexOf(e.charAt(h++)),l=i.indexOf(e.charAt(h++)),d=s<<18|u<<12|c<<6|l,r=d>>16&255,o=d>>8&255,a=255&d,64==c?m[f++]=String.fromCharCode(r):64==l?m[f++]=String.fromCharCode(r,o):m[f++]=String.fromCharCode(r,o,a);while(h>18&63,u=d>>12&63,c=d>>6&63,l=63&d,m[f++]=i.charAt(s)+i.charAt(u)+i.charAt(c)+i.charAt(l);while(ha;a++)o+=String.fromCharCode(r[a]);return o}}t.call(this),e.extend(this,{uid:e.guid("uid_"),readAsBinaryString:function(e){return i.call(this,"readAsBinaryString",e)},readAsDataURL:function(e){return i.call(this,"readAsDataURL",e)},readAsText:function(e){return i.call(this,"readAsText",e)}})}}),i(I,[f,u,y],function(e,t,n){function i(){var e,i=[];t.extend(this,{append:function(r,o){var a=this,s=t.typeOf(o);o instanceof n?e={name:r,value:o}:"array"===s?(r+="[]",t.each(o,function(e){a.append(r,e)})):"object"===s?t.each(o,function(e,t){a.append(r+"["+t+"]",e)}):"null"===s||"undefined"===s||"number"===s&&isNaN(o)?a.append(r,"false"):i.push({name:r,value:o.toString()})},hasBlob:function(){return!!this.getBlob()},getBlob:function(){return e&&e.value||null},getBlobName:function(){return e&&e.name||null},each:function(n){t.each(i,function(e){n(e.value,e.name)}),e&&n(e.value,e.name)},destroy:function(){e=null,i=[]}})}return i}),i(T,[u,f,p,w,x,m,R,y,A,I,c,d],function(e,t,n,i,r,o,a,s,u,c,l,d){function h(){this.uid=e.guid("uid_")}function f(){function n(e,t){return w.hasOwnProperty(e)?1===arguments.length?l.can("define_property")?w[e]:v[e]:void(l.can("define_property")?w[e]=t:v[e]=t):void 0}function u(t){function i(){B&&(B.destroy(),B=null),s.dispatchEvent("loadend"),s=null}function r(r){B.bind("LoadStart",function(e){n("readyState",f.LOADING),s.dispatchEvent("readystatechange"),s.dispatchEvent(e),O&&s.upload.dispatchEvent(e)}),B.bind("Progress",function(e){n("readyState")!==f.LOADING&&(n("readyState",f.LOADING),s.dispatchEvent("readystatechange")),s.dispatchEvent(e)}),B.bind("UploadProgress",function(e){O&&s.upload.dispatchEvent({type:"progress",lengthComputable:!1,total:e.total,loaded:e.loaded})}),B.bind("Load",function(t){n("readyState",f.DONE),n("status",Number(r.exec.call(B,"XMLHttpRequest","getStatus")||0)),n("statusText",p[n("status")]||""),n("response",r.exec.call(B,"XMLHttpRequest","getResponse",n("responseType"))),~e.inArray(n("responseType"),["text",""])?n("responseText",n("response")):"document"===n("responseType")&&n("responseXML",n("response")),k=r.exec.call(B,"XMLHttpRequest","getAllResponseHeaders"),s.dispatchEvent("readystatechange"),n("status")>0?(O&&s.upload.dispatchEvent(t),s.dispatchEvent(t)):(N=!0,s.dispatchEvent("error")),i()}),B.bind("Abort",function(e){s.dispatchEvent(e),i()}),B.bind("Error",function(e){N=!0,n("readyState",f.DONE),s.dispatchEvent("readystatechange"),D=!0,s.dispatchEvent(e),i()}),r.exec.call(B,"XMLHttpRequest","send",{url:E,method:_,async:y,user:x,password:R,headers:b,mimeType:I,encoding:A,responseType:s.responseType,withCredentials:s.withCredentials,options:H},t)}var s=this;C=(new Date).getTime(),B=new a,"string"==typeof H.required_caps&&(H.required_caps=o.parseCaps(H.required_caps)),H.required_caps=e.extend({},H.required_caps,{return_response_type:s.responseType}),t instanceof c&&(H.required_caps.send_multipart=!0),e.isEmptyObj(b)||(H.required_caps.send_custom_headers=!0),L||(H.required_caps.do_cors=!0),H.ruid?r(B.connectRuntime(H)):(B.bind("RuntimeInit",function(e,t){r(t)}),B.bind("RuntimeError",function(e,t){s.dispatchEvent("RuntimeError",t)}),B.connectRuntime(H))}function g(){n("responseText",""),n("responseXML",null),n("response",null),n("status",0),n("statusText",""),C=M=null}var v=this,w={timeout:0,readyState:f.UNSENT,withCredentials:!1,status:0,statusText:"",responseType:"",responseXML:null,responseText:null,response:null},y=!0,E,_,b={},x,R,A=null,I=null,T=!1,S=!1,O=!1,D=!1,N=!1,L=!1,C,M,F=null,P=null,H={},B,k="",U;e.extend(this,w,{uid:e.guid("uid_"),upload:new h,open:function(o,a,s,u,c){var l;if(!o||!a)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(/[\u0100-\uffff]/.test(o)||i.utf8_encode(o)!==o)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(~e.inArray(o.toUpperCase(),["CONNECT","DELETE","GET","HEAD","OPTIONS","POST","PUT","TRACE","TRACK"])&&(_=o.toUpperCase()),~e.inArray(_,["CONNECT","TRACE","TRACK"]))throw new t.DOMException(t.DOMException.SECURITY_ERR);if(a=i.utf8_encode(a),l=r.parseUrl(a),L=r.hasSameOrigin(l),E=r.resolveUrl(a),(u||c)&&!L)throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);if(x=u||l.user,R=c||l.pass,y=s||!0,y===!1&&(n("timeout")||n("withCredentials")||""!==n("responseType")))throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);T=!y,S=!1,b={},g.call(this),n("readyState",f.OPENED),this.dispatchEvent("readystatechange")},setRequestHeader:function(r,o){var a=["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"];if(n("readyState")!==f.OPENED||S)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(/[\u0100-\uffff]/.test(r)||i.utf8_encode(r)!==r)throw new t.DOMException(t.DOMException.SYNTAX_ERR);return r=e.trim(r).toLowerCase(),~e.inArray(r,a)||/^(proxy\-|sec\-)/.test(r)?!1:(b[r]?b[r]+=", "+o:b[r]=o,!0)},getAllResponseHeaders:function(){return k||""},getResponseHeader:function(t){return t=t.toLowerCase(),N||~e.inArray(t,["set-cookie","set-cookie2"])?null:k&&""!==k&&(U||(U={},e.each(k.split(/\r\n/),function(t){var n=t.split(/:\s+/);2===n.length&&(n[0]=e.trim(n[0]),U[n[0].toLowerCase()]={header:n[0],value:e.trim(n[1])})})),U.hasOwnProperty(t))?U[t].header+": "+U[t].value:null},overrideMimeType:function(i){var r,o;if(~e.inArray(n("readyState"),[f.LOADING,f.DONE]))throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(i=e.trim(i.toLowerCase()),/;/.test(i)&&(r=i.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))&&(i=r[1],r[2]&&(o=r[2])),!d.mimes[i])throw new t.DOMException(t.DOMException.SYNTAX_ERR);F=i,P=o},send:function(n,r){if(H="string"===e.typeOf(r)?{ruid:r}:r?r:{},this.readyState!==f.OPENED||S)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(n instanceof s)H.ruid=n.ruid,I=n.type||"application/octet-stream";else if(n instanceof c){if(n.hasBlob()){var o=n.getBlob();H.ruid=o.ruid,I=o.type||"application/octet-stream"}}else"string"==typeof n&&(A="UTF-8",I="text/plain;charset=UTF-8",n=i.utf8_encode(n));this.withCredentials||(this.withCredentials=H.required_caps&&H.required_caps.send_browser_cookies&&!L),O=!T&&this.upload.hasEventListener(),N=!1,D=!n,T||(S=!0),u.call(this,n)},abort:function(){if(N=!0,T=!1,~e.inArray(n("readyState"),[f.UNSENT,f.OPENED,f.DONE]))n("readyState",f.UNSENT);else{if(n("readyState",f.DONE),S=!1,!B)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);B.getRuntime().exec.call(B,"XMLHttpRequest","abort",D),D=!0}},destroy:function(){B&&("function"===e.typeOf(B.destroy)&&B.destroy(),B=null),this.unbindAll(),this.upload&&(this.upload.unbindAll(),this.upload=null)}}),this.handleEventProps(m.concat(["readystatechange"])),this.upload.handleEventProps(m)}var p={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"};h.prototype=n.instance;var m=["loadstart","progress","abort","error","load","timeout","loadend"],g=1,v=2;return f.UNSENT=0,f.OPENED=1,f.HEADERS_RECEIVED=2,f.LOADING=3,f.DONE=4,f.prototype=n.instance,f}),i(S,[u,w,g,p],function(e,t,n,i){function r(){function i(){l=d=0,c=this.result=null}function o(t,n){var i=this;u=n,i.bind("TransportingProgress",function(t){d=t.loaded,l>d&&-1===e.inArray(i.state,[r.IDLE,r.DONE])&&a.call(i)},999),i.bind("TransportingComplete",function(){d=l,i.state=r.DONE,c=null,i.result=u.exec.call(i,"Transporter","getAsBlob",t||"")},999),i.state=r.BUSY,i.trigger("TransportingStarted"),a.call(i)}function a(){var e=this,n,i=l-d;h>i&&(h=i),n=t.btoa(c.substr(d,h)),u.exec.call(e,"Transporter","receive",n,l)}var s,u,c,l,d,h;n.call(this),e.extend(this,{uid:e.guid("uid_"),state:r.IDLE,result:null,transport:function(t,n,r){var a=this;if(r=e.extend({chunk_size:204798},r),(s=r.chunk_size%3)&&(r.chunk_size+=3-s),h=r.chunk_size,i.call(this),c=t,l=t.length,"string"===e.typeOf(r)||r.ruid)o.call(a,n,this.connectRuntime(r));else{var u=function(e,t){a.unbind("RuntimeInit",u),o.call(a,n,t)};this.bind("RuntimeInit",u),this.connectRuntime(r)}},abort:function(){var e=this;e.state=r.IDLE,u&&(u.exec.call(e,"Transporter","clear"),e.trigger("TransportingAborted")),i.call(e)},destroy:function(){this.unbindAll(),u=null,this.disconnectRuntime(),i.call(this)}})}return r.IDLE=0,r.BUSY=1,r.DONE=2,r.prototype=i.instance,r}),i(O,[u,h,f,A,T,m,g,S,c,p,y,E,w],function(e,t,n,i,r,o,a,s,u,c,l,d,h){function f(){function i(e){e||(e=this.exec("Image","getInfo")),this.size=e.size,this.width=e.width,this.height=e.height,this.type=e.type,this.meta=e.meta,""===this.name&&(this.name=e.name)}function c(t){var i=e.typeOf(t);try{if(t instanceof f){if(!t.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);m.apply(this,arguments)}else if(t instanceof l){if(!~e.inArray(t.type,["image/jpeg","image/png"]))throw new n.ImageError(n.ImageError.WRONG_FORMAT);g.apply(this,arguments)}else if(-1!==e.inArray(i,["blob","file"]))c.call(this,new d(null,t),arguments[1]);else if("string"===i)"data:"===t.substr(0,5)?c.call(this,new l(null,{data:t}),arguments[1]):v.apply(this,arguments);else{if("node"!==i||"img"!==t.nodeName.toLowerCase())throw new n.DOMException(n.DOMException.TYPE_MISMATCH_ERR);c.call(this,t.src,arguments[1])}}catch(r){this.trigger("error",r.code)}}function m(t,n){var i=this.connectRuntime(t.ruid);this.ruid=i.uid,i.exec.call(this,"Image","loadFromImage",t,"undefined"===e.typeOf(n)?!0:n)}function g(t,n){function i(e){r.ruid=e.uid,e.exec.call(r,"Image","loadFromBlob",t)}var r=this;r.name=t.name||"",t.isDetached()?(this.bind("RuntimeInit",function(e,t){i(t)}),n&&"string"==typeof n.required_caps&&(n.required_caps=o.parseCaps(n.required_caps)),this.connectRuntime(e.extend({required_caps:{access_image_binary:!0,resize_image:!0}},n))):i(this.connectRuntime(t.ruid))}function v(e,t){var n=this,i;i=new r,i.open("get",e),i.responseType="blob",i.onprogress=function(e){n.trigger(e)},i.onload=function(){g.call(n,i.response,!0)},i.onerror=function(e){n.trigger(e)},i.onloadend=function(){i.destroy()},i.bind("RuntimeError",function(e,t){n.trigger("RuntimeError",t)}),i.send(null,t)}a.call(this),e.extend(this,{uid:e.guid("uid_"),ruid:null,name:"",size:0,width:0,height:0,type:"",meta:{},clone:function(){this.load.apply(this,arguments)},load:function(){c.apply(this,arguments)},downsize:function(t){var i={width:this.width,height:this.height,type:this.type||"image/jpeg",quality:90,crop:!1,preserveHeaders:!0,resample:!1};t="object"==typeof t?e.extend(i,t):e.extend(i,{width:arguments[0],height:arguments[1],crop:arguments[2],preserveHeaders:arguments[3]});try{if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);if(this.width>f.MAX_RESIZE_WIDTH||this.height>f.MAX_RESIZE_HEIGHT)throw new n.ImageError(n.ImageError.MAX_RESOLUTION_ERR);this.exec("Image","downsize",t.width,t.height,t.crop,t.preserveHeaders)}catch(r){this.trigger("error",r.code)}},crop:function(e,t,n){this.downsize(e,t,!0,n)},getAsCanvas:function(){if(!u.can("create_canvas"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);var e=this.connectRuntime(this.ruid);return e.exec.call(this,"Image","getAsCanvas")},getAsBlob:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return this.exec("Image","getAsBlob",e||"image/jpeg",t||90)},getAsDataURL:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return this.exec("Image","getAsDataURL",e||"image/jpeg",t||90)},getAsBinaryString:function(e,t){var n=this.getAsDataURL(e,t);return h.atob(n.substring(n.indexOf("base64,")+7))},embed:function(i,r){function o(t,r){var o=this;if(u.can("create_canvas")){var l=o.getAsCanvas();if(l)return i.appendChild(l),l=null,o.destroy(),void a.trigger("embedded")}var d=o.getAsDataURL(t,r);if(!d)throw new n.ImageError(n.ImageError.WRONG_FORMAT);if(u.can("use_data_uri_of",d.length))i.innerHTML=' ',o.destroy(),a.trigger("embedded");else{var f=new s;f.bind("TransportingComplete",function(){c=a.connectRuntime(this.result.ruid),a.bind("Embedded",function(){e.extend(c.getShimContainer().style,{top:"0px",left:"0px",width:o.width+"px",height:o.height+"px"}),c=null},999),c.exec.call(a,"ImageView","display",this.result.uid,width,height),o.destroy()}),f.transport(h.atob(d.substring(d.indexOf("base64,")+7)),t,{required_caps:{display_media:!0},runtime_order:"flash,silverlight",container:i})}}var a=this,c;r=e.extend({width:this.width,height:this.height,type:this.type||"image/jpeg",quality:90},r||{});try{if(!(i=t.get(i)))throw new n.DOMException(n.DOMException.INVALID_NODE_TYPE_ERR);if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);this.width>f.MAX_RESIZE_WIDTH||this.height>f.MAX_RESIZE_HEIGHT;var l=new f;return l.bind("Resize",function(){o.call(this,r.type,r.quality)}),l.bind("Load",function(){l.downsize(r)}),this.meta.thumb&&this.meta.thumb.width>=r.width&&this.meta.thumb.height>=r.height?l.load(this.meta.thumb.data):l.clone(this,!1),l}catch(d){this.trigger("error",d.code)}},destroy:function(){this.ruid&&(this.getRuntime().exec.call(this,"Image","destroy"),this.disconnectRuntime()),this.unbindAll()}}),this.handleEventProps(p),this.bind("Load Resize",function(){i.call(this)},999)}var p=["progress","load","error","resize","embedded"];return f.MAX_RESIZE_WIDTH=8192,f.MAX_RESIZE_HEIGHT=8192,f.prototype=c.instance,f}),i(D,[u,f,m,c],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue,c=e.extend({access_binary:s(window.FileReader||window.File&&window.File.getAsDataURL),access_image_binary:function(){return r.can("access_binary")&&!!a.Image},display_media:s(i.can("create_canvas")||i.can("use_data_uri_over32kb")),do_cors:s(window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest),drag_and_drop:s(function(){var e=document.createElement("div");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&("IE"!==i.browser||i.verComp(i.version,9,">"))}()),filter_by_extension:s(function(){return"Chrome"===i.browser&&i.verComp(i.version,28,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||"Safari"===i.browser&&i.verComp(i.version,7,">=")}()),return_response_headers:u,return_response_type:function(e){return"json"===e&&window.JSON?!0:i.can("return_response_type",e)},return_status_code:u,report_upload_progress:s(window.XMLHttpRequest&&(new XMLHttpRequest).upload),resize_image:function(){return r.can("access_binary")&&i.can("create_canvas")},select_file:function(){return i.can("use_fileinput")&&window.File},select_folder:function(){return r.can("select_file")&&"Chrome"===i.browser&&i.verComp(i.version,21,">=")},select_multiple:function(){return!(!r.can("select_file")||"Safari"===i.browser&&"Windows"===i.os||"iOS"===i.os&&i.verComp(i.osVersion,"7.0.0",">")&&i.verComp(i.osVersion,"8.0.0","<"))},send_binary_string:s(window.XMLHttpRequest&&((new XMLHttpRequest).sendAsBinary||window.Uint8Array&&window.ArrayBuffer)),send_custom_headers:s(window.XMLHttpRequest),send_multipart:function(){return!!(window.XMLHttpRequest&&(new XMLHttpRequest).upload&&window.FormData)||r.can("send_binary_string")},slice_blob:s(window.File&&(File.prototype.mozSlice||File.prototype.webkitSlice||File.prototype.slice)),stream_upload:function(){return r.can("slice_blob")&&r.can("send_multipart")},summon_file_dialog:function(){return r.can("select_file")&&("Firefox"===i.browser&&i.verComp(i.version,4,">=")||"Opera"===i.browser&&i.verComp(i.version,12,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||!!~e.inArray(i.browser,["Chrome","Safari"]))},upload_filesize:u},arguments[2]);n.call(this,t,arguments[1]||o,c),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html5",a={};return n.addConstructor(o,r),a}),i(N,[u],function(e){function t(){this.returnValue=!1}function n(){this.cancelBubble=!0}var i={},r="moxie_"+e.guid(),o=function(o,a,s,u){var c,l;a=a.toLowerCase(),o.addEventListener?(c=s,o.addEventListener(a,c,!1)):o.attachEvent&&(c=function(){var e=window.event;e.target||(e.target=e.srcElement),e.preventDefault=t,e.stopPropagation=n,s(e)},o.attachEvent("on"+a,c)),o[r]||(o[r]=e.guid()),i.hasOwnProperty(o[r])||(i[o[r]]={}),l=i[o[r]],l.hasOwnProperty(a)||(l[a]=[]),l[a].push({func:c,orig:s,key:u})},a=function(t,n,o){var a,s;if(n=n.toLowerCase(),t[r]&&i[t[r]]&&i[t[r]][n]){a=i[t[r]][n];for(var u=a.length-1;u>=0&&(a[u].orig!==o&&a[u].key!==o||(t.removeEventListener?t.removeEventListener(n,a[u].func,!1):t.detachEvent&&t.detachEvent("on"+n,a[u].func),a[u].orig=null,a[u].func=null,a.splice(u,1),o===s));u--);if(a.length||delete i[t[r]][n],e.isEmptyObj(i[t[r]])){delete i[t[r]];try{delete t[r]}catch(c){t[r]=s}}}},s=function(t,n){t&&t[r]&&e.each(i[t[r]],function(e,i){a(t,i,n)})};return{addEvent:o,removeEvent:a,removeAllEvents:s}}),i(L,[D,E,u,h,N,d,c],function(e,t,n,i,r,o,a){function s(){var e;n.extend(this,{init:function(s){var u=this,c=u.getRuntime(),l,d,h,f,p,m;e=s,h=e.accept.mimes||o.extList2mimes(e.accept,c.can("filter_by_extension")),d=c.getShimContainer(),d.innerHTML=' ",l=i.get(c.uid),n.extend(l.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),f=i.get(e.browse_button),c.can("summon_file_dialog")&&("static"===i.getStyle(f,"position")&&(f.style.position="relative"),p=parseInt(i.getStyle(f,"z-index"),10)||1,f.style.zIndex=p,d.style.zIndex=p-1,r.addEvent(f,"click",function(e){var t=i.get(c.uid);t&&!t.disabled&&t.click(),e.preventDefault()},u.uid)),m=c.can("summon_file_dialog")?f:d,r.addEvent(m,"mouseover",function(){u.trigger("mouseenter")},u.uid),r.addEvent(m,"mouseout",function(){u.trigger("mouseleave")},u.uid),r.addEvent(m,"mousedown",function(){u.trigger("mousedown")},u.uid),r.addEvent(i.get(e.container),"mouseup",function(){u.trigger("mouseup")},u.uid),l.onchange=function g(i){if(u.files=[],n.each(this.files,function(n){var i="";return e.directory&&"."==n.name?!0:(n.webkitRelativePath&&(i="/"+n.webkitRelativePath.replace(/^\//,"")),n=new t(c.uid,n),n.relativePath=i,void u.files.push(n))}),"IE"!==a.browser&&"IEMobile"!==a.browser)this.value="";else{var r=this.cloneNode(!0);this.parentNode.replaceChild(r,this),r.onchange=g}u.files.length&&u.trigger("change")},u.trigger({type:"ready",async:!0}),d=null},disable:function(e){var t=this.getRuntime(),n;(n=i.get(t.uid))&&(n.disabled=!!e)},destroy:function(){var t=this.getRuntime(),n=t.getShim(),o=t.getShimContainer();r.removeAllEvents(o,this.uid),r.removeAllEvents(e&&i.get(e.container),this.uid),r.removeAllEvents(e&&i.get(e.browse_button),this.uid),o&&(o.innerHTML=""),n.removeInstance(this.uid),e=o=n=null}})}return e.FileInput=s}),i(C,[D,y],function(e,t){function n(){function e(e,t,n){var i;if(!window.File.prototype.slice)return(i=window.File.prototype.webkitSlice||window.File.prototype.mozSlice)?i.call(e,t,n):null;try{return e.slice(),e.slice(t,n)}catch(r){return e.slice(t,n-t)}}this.slice=function(){return new t(this.getRuntime().uid,e.apply(this,arguments))}}return e.Blob=n}),i(M,[D,E,u,h,N,d],function(e,t,n,i,r,o){function a(){function e(e){if(!e.dataTransfer||!e.dataTransfer.types)return!1;var t=n.toArray(e.dataTransfer.types||[]);return-1!==n.inArray("Files",t)||-1!==n.inArray("public.file-url",t)||-1!==n.inArray("application/x-moz-file",t)}function a(e,n){if(u(e)){var i=new t(g,e);i.relativePath=n||"",f.push(i)}}function s(e){for(var t=[],i=0;i=")&&u.verComp(u.version,7,"<"),h="Android Browser"===u.browser,m=!1;if(p=n.url.replace(/^.+?\/([\w\-\.]+)$/,"$1").toLowerCase(),f=c(),f.open(n.method,n.url,n.async,n.user,n.password),r instanceof o)r.isDetached()&&(m=!0),r=r.getSource();else if(r instanceof a){if(r.hasBlob())if(r.getBlob().isDetached())r=d.call(s,r),m=!0;else if((l||h)&&"blob"===t.typeOf(r.getBlob().getSource())&&window.FileReader)return void e.call(s,n,r);if(r instanceof a){var g=new window.FormData;r.each(function(e,t){e instanceof o?g.append(t,e.getSource()):g.append(t,e)}),r=g}}f.upload?(n.withCredentials&&(f.withCredentials=!0),f.addEventListener("load",function(e){s.trigger(e)}),f.addEventListener("error",function(e){s.trigger(e)}),f.addEventListener("progress",function(e){s.trigger(e)}),f.upload.addEventListener("progress",function(e){s.trigger({type:"UploadProgress",loaded:e.loaded,total:e.total})})):f.onreadystatechange=function v(){switch(f.readyState){case 1:break;case 2:break;case 3:var e,t;try{i.hasSameOrigin(n.url)&&(e=f.getResponseHeader("Content-Length")||0),f.responseText&&(t=f.responseText.length)}catch(r){e=t=0}s.trigger({type:"progress",lengthComputable:!!e,total:parseInt(e,10),loaded:t});break;case 4:f.onreadystatechange=function(){},s.trigger(0===f.status?"error":"load")}},t.isEmptyObj(n.headers)||t.each(n.headers,function(e,t){f.setRequestHeader(t,e)}),""!==n.responseType&&"responseType"in f&&("json"!==n.responseType||u.can("return_response_type","json")?f.responseType=n.responseType:f.responseType="text"),m?f.sendAsBinary?f.sendAsBinary(r):!function(){for(var e=new Uint8Array(r.length),t=0;t0&&o.set(new Uint8Array(t.slice(0,e)),0),o.set(new Uint8Array(r),e),o.set(new Uint8Array(t.slice(e+i)),e+r.byteLength),this.clear(),t=o.buffer,n=new DataView(t);break}default:return t}},length:function(){return t?t.byteLength:0},clear:function(){n=t=null}})}function i(t){function n(e,n,i){i=3===arguments.length?i:t.length-n-1,t=t.substr(0,n)+e+t.substr(i+n)}e.extend(this,{readByteAt:function(e){return t.charCodeAt(e)},writeByteAt:function(e,t){n(String.fromCharCode(t),e,1)},SEGMENT:function(e,i,r){switch(arguments.length){case 1:return t.substr(e);case 2:return t.substr(e,i);case 3:n(null!==r?r:"",e,i);break;default:return t}},length:function(){return t?t.length:0},clear:function(){t=null}})}return e.extend(t.prototype,{littleEndian:!1,read:function(e,t){var n,i,r;if(e+t>this.length())throw new Error("You are trying to read outside the source boundaries.");for(i=this.littleEndian?0:-8*(t-1),r=0,n=0;t>r;r++)n|=this.readByteAt(e+r)<this.length())throw new Error("You are trying to write outside the source boundaries.");for(i=this.littleEndian?0:-8*(n-1),r=0;n>r;r++)this.writeByteAt(e+r,t>>Math.abs(i+8*r)&255)},BYTE:function(e){return this.read(e,1)},SHORT:function(e){return this.read(e,2)},LONG:function(e){return this.read(e,4)},SLONG:function(e){var t=this.read(e,4);return t>2147483647?t-4294967296:t},CHAR:function(e){return String.fromCharCode(this.read(e,1))},STRING:function(e,t){return this.asArray("CHAR",e,t).join("")},asArray:function(e,t,n){for(var i=[],r=0;n>r;r++)i[r]=this[e](t+r);return i}}),t}),i(B,[H,f],function(e,t){return function n(i){var r=[],o,a,s,u=0;if(o=new e(i),65496!==o.SHORT(0))throw o.clear(),new t.ImageError(t.ImageError.WRONG_FORMAT);for(a=2;a<=o.length();)if(s=o.SHORT(a),s>=65488&&65495>=s)a+=2;else{if(65498===s||65497===s)break;u=o.SHORT(a+2)+2,s>=65505&&65519>=s&&r.push({hex:s,name:"APP"+(15&s),start:a,length:u,segment:o.SEGMENT(a,u)}),a+=u}return o.clear(),{headers:r,restore:function(t){var n,i,o;for(o=new e(t),a=65504==o.SHORT(2)?4+o.SHORT(4):2,i=0,n=r.length;n>i;i++)o.SEGMENT(a,0,r[i].segment),a+=r[i].length;return t=o.SEGMENT(),o.clear(),t},strip:function(t){var i,r,o,a;for(o=new n(t),r=o.headers,o.purge(),i=new e(t),a=r.length;a--;)i.SEGMENT(r[a].start,r[a].length,"");return t=i.SEGMENT(),i.clear(),t},get:function(e){for(var t=[],n=0,i=r.length;i>n;n++)r[n].name===e.toUpperCase()&&t.push(r[n].segment);return t},
+set:function(e,t){var n=[],i,o,a;for("string"==typeof t?n.push(t):n=t,i=o=0,a=r.length;a>i&&(r[i].name===e.toUpperCase()&&(r[i].segment=n[o],r[i].length=n[o].length,o++),!(o>=n.length));i++);},purge:function(){this.headers=r=[]}}}}),i(k,[u,H,f],function(e,n,i){function r(o){function a(n,r){var o=this,a,s,u,c,h,f,p,m,g=[],v={},w={1:"BYTE",7:"UNDEFINED",2:"ASCII",3:"SHORT",4:"LONG",5:"RATIONAL",9:"SLONG",10:"SRATIONAL"},y={BYTE:1,UNDEFINED:1,ASCII:1,SHORT:2,LONG:4,RATIONAL:8,SLONG:4,SRATIONAL:8};for(a=o.SHORT(n),s=0;a>s;s++)if(g=[],p=n+2+12*s,u=r[o.SHORT(p)],u!==t){if(c=w[o.SHORT(p+=2)],h=o.LONG(p+=2),f=y[c],!f)throw new i.ImageError(i.ImageError.INVALID_META_ERR);if(p+=4,f*h>4&&(p=o.LONG(p)+d.tiffHeader),p+f*h>=this.length())throw new i.ImageError(i.ImageError.INVALID_META_ERR);"ASCII"!==c?(g=o.asArray(c,p,h),m=1==h?g[0]:g,l.hasOwnProperty(u)&&"object"!=typeof m?v[u]=l[u][m]:v[u]=m):v[u]=e.trim(o.STRING(p,h).replace(/\0$/,""))}return v}function s(e,t,n){var i,r,o,a=0;if("string"==typeof t){var s=c[e.toLowerCase()];for(var u in s)if(s[u]===t){t=u;break}}i=d[e.toLowerCase()+"IFD"],r=this.SHORT(i);for(var l=0;r>l;l++)if(o=i+12*l+2,this.SHORT(o)==t){a=o+8;break}if(!a)return!1;try{this.write(a,n,4)}catch(h){return!1}return!0}var u,c,l,d,h,f;if(n.call(this,o),c={tiff:{274:"Orientation",270:"ImageDescription",271:"Make",272:"Model",305:"Software",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer"},exif:{36864:"ExifVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",36867:"DateTimeOriginal",33434:"ExposureTime",33437:"FNumber",34855:"ISOSpeedRatings",37377:"ShutterSpeedValue",37378:"ApertureValue",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37386:"FocalLength",41986:"ExposureMode",41987:"WhiteBalance",41990:"SceneCaptureType",41988:"DigitalZoomRatio",41992:"Contrast",41993:"Saturation",41994:"Sharpness"},gps:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude"},thumb:{513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength"}},l={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:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"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"},GPSLatitudeRef:{N:"North latitude",S:"South latitude"},GPSLongitudeRef:{E:"East longitude",W:"West longitude"}},d={tiffHeader:10},h=d.tiffHeader,u={clear:this.clear},e.extend(this,{read:function(){try{return r.prototype.read.apply(this,arguments)}catch(e){throw new i.ImageError(i.ImageError.INVALID_META_ERR)}},write:function(){try{return r.prototype.write.apply(this,arguments)}catch(e){throw new i.ImageError(i.ImageError.INVALID_META_ERR)}},UNDEFINED:function(){return this.BYTE.apply(this,arguments)},RATIONAL:function(e){return this.LONG(e)/this.LONG(e+4)},SRATIONAL:function(e){return this.SLONG(e)/this.SLONG(e+4)},ASCII:function(e){return this.CHAR(e)},TIFF:function(){return f||null},EXIF:function(){var t=null;if(d.exifIFD){try{t=a.call(this,d.exifIFD,c.exif)}catch(n){return null}if(t.ExifVersion&&"array"===e.typeOf(t.ExifVersion)){for(var i=0,r="";i=65472&&65475>=n)return t+=5,{height:e.SHORT(t),width:e.SHORT(t+=2)};i=e.SHORT(t+=2),t+=i-2}return null}function s(){var e=d.thumb(),t,n;return e&&(t=new i(e),n=a(t),t.clear(),n)?(n.data=e,n):null}function u(){d&&l&&c&&(d.clear(),l.purge(),c.clear(),h=l=d=c=null)}var c,l,d,h;if(c=new i(o),65496!==c.SHORT(0))throw new t.ImageError(t.ImageError.WRONG_FORMAT);l=new n(o);try{d=new r(l.get("app1")[0])}catch(f){}h=a.call(this),e.extend(this,{type:"image/jpeg",size:c.length(),width:h&&h.width||0,height:h&&h.height||0,setExif:function(t,n){return d?("object"===e.typeOf(t)?e.each(t,function(e,t){d.setExif(t,e)}):d.setExif(t,n),void l.set("app1",d.SEGMENT())):!1},writeHeaders:function(){return l.restore(arguments.length?arguments[0]:o)},stripHeaders:function(e){return l.strip(e)},purge:function(){u.call(this)}}),d&&(this.meta={tiff:d.TIFF(),exif:d.EXIF(),gps:d.GPS(),thumb:s()})}return o}),i(G,[f,u,H],function(e,t,n){function i(i){function r(){var e,t;return e=a.call(this,8),"IHDR"==e.type?(t=e.start,{width:s.LONG(t),height:s.LONG(t+=4)}):null}function o(){s&&(s.clear(),i=l=u=c=s=null)}function a(e){var t,n,i,r;return t=s.LONG(e),n=s.STRING(e+=4,4),i=e+=4,r=s.LONG(e+t),{length:t,type:n,start:i,CRC:r}}var s,u,c,l;s=new n(i),function(){var t=0,n=0,i=[35152,20039,3338,6666];for(n=0;ng;){for(var v=g+h>a?a-g:h,w=0;o>w;){var y=w+h>o?o-w:h;p.clearRect(0,0,h,h),p.drawImage(e,-w,-g);var E=w*s/o+c<<0,_=Math.ceil(y*s/o),b=g*u/a/m+l<<0,x=Math.ceil(v*u/a/m);d.drawImage(f,0,0,y,v,E,b,_,x),w+=h}g+=h}f=p=null}function t(e){var t=e.naturalWidth,n=e.naturalHeight;if(t*n>1048576){var i=document.createElement("canvas");i.width=i.height=1;var r=i.getContext("2d");return r.drawImage(e,-t+1,0),0===r.getImageData(0,0,1,1).data[3]}return!1}function n(e,t,n){var i=document.createElement("canvas");i.width=1,i.height=n;var r=i.getContext("2d");r.drawImage(e,0,0);for(var o=r.getImageData(0,0,1,n).data,a=0,s=n,u=n;u>a;){var c=o[4*(u-1)+3];0===c?s=u:a=u,u=s+a>>1}i=null;var l=u/n;return 0===l?1:l}return{isSubsampled:t,renderTo:e}}),i(j,[D,u,f,w,y,E,z,q,d,c],function(e,t,n,i,r,o,a,s,u,c){function l(){function e(){if(!_&&!y)throw new n.ImageError(n.DOMException.INVALID_STATE_ERR);return _||y}function l(e){return i.atob(e.substring(e.indexOf("base64,")+7))}function d(e,t){return"data:"+(t||"")+";base64,"+i.btoa(e)}function h(e){var t=this;y=new Image,y.onerror=function(){v.call(this),t.trigger("error",n.ImageError.WRONG_FORMAT)},y.onload=function(){t.trigger("load")},y.src="data:"==e.substr(0,5)?e:d(e,x.type)}function f(e,t){var i=this,r;return window.FileReader?(r=new FileReader,r.onload=function(){t(this.result)},r.onerror=function(){i.trigger("error",n.ImageError.WRONG_FORMAT)},r.readAsDataURL(e),void 0):t(e.getAsDataURL())}function p(n,i,r,o){var a=this,s,u,c=0,l=0,d,h,f,p;if(A=o,p=this.meta&&this.meta.tiff&&this.meta.tiff.Orientation||1,-1!==t.inArray(p,[5,6,7,8])){var v=n;n=i,i=v}return d=e(),r?(n=Math.min(n,d.width),i=Math.min(i,d.height),s=Math.max(n/d.width,i/d.height)):s=Math.min(n/d.width,i/d.height),s>1&&!r&&o?void this.trigger("Resize"):(_||(_=document.createElement("canvas")),h=Math.round(d.width*s),f=Math.round(d.height*s),r?(_.width=n,_.height=i,h>n&&(c=Math.round((h-n)/2)),f>i&&(l=Math.round((f-i)/2))):(_.width=h,_.height=f),A||g(_.width,_.height,p),m.call(this,d,_,-c,-l,h,f),this.width=_.width,this.height=_.height,R=!0,void a.trigger("Resize"))}function m(e,t,n,i,r,o){if("iOS"===c.OS)s.renderTo(e,t,{width:r,height:o,x:n,y:i});else{var a=t.getContext("2d");a.drawImage(e,n,i,r,o)}}function g(e,t,n){switch(n){case 5:case 6:case 7:case 8:_.width=t,_.height=e;break;default:_.width=e,_.height=t}var i=_.getContext("2d");switch(n){case 2:i.translate(e,0),i.scale(-1,1);break;case 3:i.translate(e,t),i.rotate(Math.PI);break;case 4:i.translate(0,t),i.scale(1,-1);break;case 5:i.rotate(.5*Math.PI),i.scale(1,-1);break;case 6:i.rotate(.5*Math.PI),i.translate(0,-t);break;case 7:i.rotate(.5*Math.PI),i.translate(e,-t),i.scale(-1,1);break;case 8:i.rotate(-.5*Math.PI),i.translate(-e,0)}}function v(){E&&(E.purge(),E=null),b=y=_=x=null,R=!1}var w=this,y,E,_,b,x,R=!1,A=!0;t.extend(this,{loadFromBlob:function(e){var t=this,i=t.getRuntime(),r=arguments.length>1?arguments[1]:!0;if(!i.can("access_binary"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);return x=e,e.isDetached()?(b=e.getSource(),void h.call(this,b)):void f.call(this,e.getSource(),function(e){r&&(b=l(e)),h.call(t,e)})},loadFromImage:function(e,t){this.meta=e.meta,x=new o(null,{name:e.name,size:e.size,type:e.type}),h.call(this,t?b=e.getAsBinaryString():e.getAsDataURL())},getInfo:function(){var t=this.getRuntime(),n;return!E&&b&&t.can("access_image_binary")&&(E=new a(b)),n={width:e().width||0,height:e().height||0,type:x.type||u.getFileMime(x.name),size:b&&b.length||x.size||0,name:x.name||"",meta:E&&E.meta||this.meta||{}},!n.meta||!n.meta.thumb||n.meta.thumb.data instanceof r||(n.meta.thumb.data=new r(null,{type:"image/jpeg",data:n.meta.thumb.data})),n},downsize:function(){p.apply(this,arguments)},getAsCanvas:function(){return _&&(_.id=this.uid+"_canvas"),_},getAsBlob:function(e,t){return e!==this.type&&p.call(this,this.width,this.height,!1),new o(null,{name:x.name||"",type:e,data:w.getAsBinaryString.call(this,e,t)})},getAsDataURL:function(e){var t=arguments[1]||90;if(!R)return y.src;if("image/jpeg"!==e)return _.toDataURL("image/png");try{return _.toDataURL("image/jpeg",t/100)}catch(n){return _.toDataURL("image/jpeg")}},getAsBinaryString:function(e,t){if(!R)return b||(b=l(w.getAsDataURL(e,t))),b;if("image/jpeg"!==e)b=l(w.getAsDataURL(e,t));else{var n;t||(t=90);try{n=_.toDataURL("image/jpeg",t/100)}catch(i){n=_.toDataURL("image/jpeg")}b=l(n),E&&(b=E.stripHeaders(b),A&&(E.meta&&E.meta.exif&&E.setExif({PixelXDimension:this.width,PixelYDimension:this.height}),b=E.writeHeaders(b)),E.purge(),E=null)}return R=!1,b},destroy:function(){w=null,v.call(this),this.getRuntime().getShim().removeInstance(this.uid)}})}return e.Image=l}),i(X,[u,c,h,f,m],function(e,t,n,i,r){function o(){var e;try{e=navigator.plugins["Shockwave Flash"],e=e.description}catch(t){try{e=new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(n){e="0.0"}}return e=e.match(/\d+/g),parseFloat(e[0]+"."+e[1])}function a(e){var i=n.get(e);i&&"OBJECT"==i.nodeName&&("IE"===t.browser?(i.style.display="none",function r(){4==i.readyState?s(e):setTimeout(r,10)}()):i.parentNode.removeChild(i))}function s(e){var t=n.get(e);if(t){for(var i in t)"function"==typeof t[i]&&(t[i]=null);t.parentNode.removeChild(t)}}function u(s){var u=this,d;s=e.extend({swf_url:t.swf_url},s),r.call(this,s,c,{access_binary:function(e){return e&&"browser"===u.mode},access_image_binary:function(e){return e&&"browser"===u.mode},display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:function(){return"client"===u.mode},resize_image:r.capTrue,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!e.arrayDiff(t,["","text","document"])||"browser"===u.mode},return_status_code:function(t){return"browser"===u.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:function(e){return e&&"browser"===u.mode},send_browser_cookies:function(e){return e&&"browser"===u.mode},send_custom_headers:function(e){return e&&"browser"===u.mode},send_multipart:r.capTrue,slice_blob:function(e){return e&&"browser"===u.mode},stream_upload:function(e){return e&&"browser"===u.mode},summon_file_dialog:!1,upload_filesize:function(t){return e.parseSizeStr(t)<=2097152||"client"===u.mode},use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}},{access_binary:function(e){return e?"browser":"client"},access_image_binary:function(e){return e?"browser":"client"},report_upload_progress:function(e){return e?"browser":"client"},return_response_type:function(t){return e.arrayDiff(t,["","text","json","document"])?"browser":["client","browser"]},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"browser":["client","browser"]},send_binary_string:function(e){return e?"browser":"client"},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"browser":"client"},stream_upload:function(e){return e?"client":"browser"},upload_filesize:function(t){return e.parseSizeStr(t)>=2097152?"client":"browser"}},"client"),o()<10&&(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid)},shimExec:function(e,t){var n=[].slice.call(arguments,2);return u.getShim().exec(this.uid,e,t,n)},init:function(){var n,r,o;o=this.getShimContainer(),e.extend(o.style,{position:"absolute",top:"-8px",left:"-8px",width:"9px",height:"9px",overflow:"hidden"}),n=' ',"IE"===t.browser?(r=document.createElement("div"),o.appendChild(r),r.outerHTML=n,r=o=null):o.innerHTML=n,d=setTimeout(function(){u&&!u.initialized&&u.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},5e3)},destroy:function(e){return function(){a(u.uid),e.call(u),clearTimeout(d),s=d=e=u=null}}(this.destroy)},l)}var c="flash",l={};return r.addConstructor(c,u),l}),i(V,[X,E,u],function(e,t,n){var i={init:function(e){var i=this,r=this.getRuntime();this.bind("Change",function(){var e=r.shimExec.call(i,"FileInput","getFiles");i.files=[],n.each(e,function(e){i.files.push(new t(r.uid,e))})},999),this.getRuntime().shimExec.call(this,"FileInput","init",{name:e.name,accept:e.accept,multiple:e.multiple}),this.trigger("ready")}};return e.FileInput=i}),i(W,[X,y],function(e,t){var n={slice:function(e,n,i,r){var o=this.getRuntime();return 0>n?n=Math.max(e.size+n,0):n>0&&(n=Math.min(n,e.size)),0>i?i=Math.max(e.size+i,0):i>0&&(i=Math.min(i,e.size)),e=o.shimExec.call(this,"Blob","slice",n,i,r||""),e&&(e=new t(o.uid,e)),e}};return e.Blob=n}),i(Y,[X,w],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i={read:function(e,t){var i=this;return i.result="","readAsDataURL"===e&&(i.result="data:"+(t.type||"")+";base64,"),i.bind("Progress",function(t,r){r&&(i.result+=n(r,e))},999),i.getRuntime().shimExec.call(this,"FileReader","readAsBase64",t.uid)}};return e.FileReader=i}),i($,[X,w],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i={read:function(e,t){var i,r=this.getRuntime();return(i=r.shimExec.call(this,"FileReaderSync","readAsBase64",t.uid))?("readAsDataURL"===e&&(i="data:"+(t.type||"")+";base64,"+i),n(i,e,t.type)):null}};return e.FileReaderSync=i}),i(J,[X,u,y,E,A,I,S],function(e,t,n,i,r,o,a){var s={send:function(e,i){function r(){e.transport=l.mode,l.shimExec.call(c,"XMLHttpRequest","send",e,i)}function s(e,t){l.shimExec.call(c,"XMLHttpRequest","appendBlob",e,t.uid),i=null,r()}function u(e,t){var n=new a;n.bind("TransportingComplete",function(){t(this.result)}),n.transport(e.getSource(),e.type,{ruid:l.uid})}var c=this,l=c.getRuntime();if(t.isEmptyObj(e.headers)||t.each(e.headers,function(e,t){l.shimExec.call(c,"XMLHttpRequest","setRequestHeader",t,e.toString())}),i instanceof o){var d;if(i.each(function(e,t){e instanceof n?d=t:l.shimExec.call(c,"XMLHttpRequest","append",t,e)}),i.hasBlob()){var h=i.getBlob();h.isDetached()?u(h,function(e){h.destroy(),s(d,e)}):s(d,h)}else i=null,r()}else i instanceof n?i.isDetached()?u(i,function(e){i.destroy(),i=e.uid,r()}):(i=i.uid,r()):r()},getResponse:function(e){var n,o,a=this.getRuntime();if(o=a.shimExec.call(this,"XMLHttpRequest","getResponseAsBlob")){if(o=new i(a.uid,o),"blob"===e)return o;try{if(n=new r,~t.inArray(e,["","text"]))return n.readAsText(o);if("json"===e&&window.JSON)return JSON.parse(n.readAsText(o))}finally{o.destroy()}}return null},abort:function(e){var t=this.getRuntime();t.shimExec.call(this,"XMLHttpRequest","abort"),this.dispatchEvent("readystatechange"),this.dispatchEvent("abort")}};return e.XMLHttpRequest=s}),i(Z,[X,y],function(e,t){var n={getAsBlob:function(e){var n=this.getRuntime(),i=n.shimExec.call(this,"Transporter","getAsBlob",e);return i?new t(n.uid,i):null}};return e.Transporter=n}),i(K,[X,u,S,y,A],function(e,t,n,i,r){var o={loadFromBlob:function(e){function t(e){r.shimExec.call(i,"Image","loadFromBlob",e.uid),i=r=null}var i=this,r=i.getRuntime();if(e.isDetached()){var o=new n;o.bind("TransportingComplete",function(){t(o.result.getSource())}),o.transport(e.getSource(),e.type,{ruid:r.uid})}else t(e.getSource())},loadFromImage:function(e){var t=this.getRuntime();return t.shimExec.call(this,"Image","loadFromImage",e.uid)},getInfo:function(){var e=this.getRuntime(),t=e.shimExec.call(this,"Image","getInfo");return!t.meta||!t.meta.thumb||t.meta.thumb.data instanceof i||(t.meta.thumb.data=new i(e.uid,t.meta.thumb.data)),t},getAsBlob:function(e,t){var n=this.getRuntime(),r=n.shimExec.call(this,"Image","getAsBlob",e,t);return r?new i(n.uid,r):null},getAsDataURL:function(){var e=this.getRuntime(),t=e.Image.getAsBlob.apply(this,arguments),n;return t?(n=new r,n.readAsDataURL(t)):null}};return e.Image=o}),i(Q,[u,c,h,f,m],function(e,t,n,i,r){function o(e){var t=!1,n=null,i,r,o,a,s,u=0;try{try{n=new ActiveXObject("AgControl.AgControl"),n.IsVersionSupported(e)&&(t=!0),n=null}catch(c){var l=navigator.plugins["Silverlight Plug-In"];if(l){for(i=l.description,"1.0.30226.2"===i&&(i="2.0.30226.2"),r=i.split(".");r.length>3;)r.pop();for(;r.length<4;)r.push(0);for(o=e.split(".");o.length>4;)o.pop();do a=parseInt(o[u],10),s=parseInt(r[u],10),u++;while(u=a&&!isNaN(a)&&(t=!0)}}}catch(d){t=!1}return t}function a(a){var c=this,l;a=e.extend({xap_url:t.xap_url},a),r.call(this,a,s,{access_binary:r.capTrue,access_image_binary:r.capTrue,display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:r.capTrue,resize_image:r.capTrue,return_response_headers:function(e){return e&&"client"===c.mode},return_response_type:function(e){return"json"!==e?!0:!!window.JSON},return_status_code:function(t){return"client"===c.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:r.capTrue,send_browser_cookies:function(e){return e&&"browser"===c.mode},send_custom_headers:function(e){return e&&"client"===c.mode},send_multipart:r.capTrue,slice_blob:r.capTrue,stream_upload:!0,summon_file_dialog:!1,upload_filesize:r.capTrue,use_http_method:function(t){return"client"===c.mode||!e.arrayDiff(t,["GET","POST"])}},{return_response_headers:function(e){return e?"client":"browser"},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"client":["client","browser"]},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"client":"browser"},use_http_method:function(t){return e.arrayDiff(t,["GET","POST"])?"client":["client","browser"]}}),o("2.0.31005.0")&&"Opera"!==t.browser||(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid).content.Moxie},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec(this.uid,e,t,n)},init:function(){var e;e=this.getShimContainer(),e.innerHTML=' ',l=setTimeout(function(){c&&!c.initialized&&c.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},"Windows"!==t.OS?1e4:5e3)},destroy:function(e){return function(){e.call(c),clearTimeout(l),a=l=e=c=null}}(this.destroy)},u)}var s="silverlight",u={};return r.addConstructor(s,a),u}),i(ee,[Q,E,u],function(e,t,n){var i={init:function(e){function i(e){for(var t="",n=0;ni;i++)n=t.keys[i],s=t[n],s&&(/^(\d|[1-9]\d+)$/.test(s)?s=parseInt(s,10):/^\d*\.\d+$/.test(s)&&(s=parseFloat(s)),r.meta[e][n]=s)}),!r.meta||!r.meta.thumb||r.meta.thumb.data instanceof n||(r.meta.thumb.data=new n(e.uid,r.meta.thumb.data))),r.width=parseInt(o.width,10),r.height=parseInt(o.height,10),r.size=parseInt(o.size,10),r.type=o.type,r.name=o.name,r}})}),i(ue,[u,f,m,c],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue;n.call(this,t,o,{access_binary:s(window.FileReader||window.File&&File.getAsDataURL),access_image_binary:!1,display_media:s(a.Image&&(i.can("create_canvas")||i.can("use_data_uri_over32kb"))),do_cors:!1,drag_and_drop:!1,filter_by_extension:s(function(){return"Chrome"===i.browser&&i.verComp(i.version,28,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||"Safari"===i.browser&&i.verComp(i.version,7,">=")}()),resize_image:function(){return a.Image&&r.can("access_binary")&&i.can("create_canvas")},report_upload_progress:!1,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!!~e.inArray(t,["text","document",""])},return_status_code:function(t){return!e.arrayDiff(t,[200,404])},select_file:function(){return i.can("use_fileinput")},select_multiple:!1,send_binary_string:!1,send_custom_headers:!1,send_multipart:!0,slice_blob:!1,stream_upload:function(){return r.can("select_file")},summon_file_dialog:function(){return r.can("select_file")&&("Firefox"===i.browser&&i.verComp(i.version,4,">=")||"Opera"===i.browser&&i.verComp(i.version,12,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||!!~e.inArray(i.browser,["Chrome","Safari"]))},upload_filesize:u,use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}}),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html4",a={};return n.addConstructor(o,r),a}),i(ce,[ue,E,u,h,N,d,c],function(e,t,n,i,r,o,a){function s(){function e(){var o=this,l=o.getRuntime(),d,h,f,p,m,g;g=n.guid("uid_"),d=l.getShimContainer(),s&&(f=i.get(s+"_form"),f&&n.extend(f.style,{top:"100%"})),p=document.createElement("form"),p.setAttribute("id",g+"_form"),p.setAttribute("method","post"),p.setAttribute("enctype","multipart/form-data"),p.setAttribute("encoding","multipart/form-data"),n.extend(p.style,{overflow:"hidden",position:"absolute",top:0,left:0,width:"100%",height:"100%"}),m=document.createElement("input"),m.setAttribute("id",g),m.setAttribute("type","file"),m.setAttribute("name",c.name||"Filedata"),m.setAttribute("accept",u.join(",")),n.extend(m.style,{fontSize:"999px",opacity:0}),p.appendChild(m),d.appendChild(p),n.extend(m.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),"IE"===a.browser&&a.verComp(a.version,10,"<")&&n.extend(m.style,{filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=0)"}),m.onchange=function(){var n;if(this.value){if(this.files){if(n=this.files[0],0===n.size)return void p.parentNode.removeChild(p)}else n={name:this.value};n=new t(l.uid,n),this.onchange=function(){},e.call(o),o.files=[n],m.setAttribute("id",n.uid),p.setAttribute("id",n.uid+"_form"),o.trigger("change"),m=p=null}},l.can("summon_file_dialog")&&(h=i.get(c.browse_button),r.removeEvent(h,"click",o.uid),r.addEvent(h,"click",function(e){m&&!m.disabled&&m.click(),e.preventDefault()},o.uid)),s=g,d=f=h=null}var s,u=[],c;n.extend(this,{init:function(t){var n=this,a=n.getRuntime(),s;c=t,u=t.accept.mimes||o.extList2mimes(t.accept,a.can("filter_by_extension")),s=a.getShimContainer(),function(){var e,o,u;e=i.get(t.browse_button),a.can("summon_file_dialog")&&("static"===i.getStyle(e,"position")&&(e.style.position="relative"),o=parseInt(i.getStyle(e,"z-index"),10)||1,e.style.zIndex=o,s.style.zIndex=o-1),u=a.can("summon_file_dialog")?e:s,r.addEvent(u,"mouseover",function(){n.trigger("mouseenter")},n.uid),r.addEvent(u,"mouseout",function(){n.trigger("mouseleave")},n.uid),r.addEvent(u,"mousedown",function(){n.trigger("mousedown")},n.uid),r.addEvent(i.get(t.container),"mouseup",function(){n.trigger("mouseup")},n.uid),e=null}(),e.call(this),s=null,n.trigger({type:"ready",async:!0})},disable:function(e){var t;(t=i.get(s))&&(t.disabled=!!e)},destroy:function(){var e=this.getRuntime(),t=e.getShim(),n=e.getShimContainer();r.removeAllEvents(n,this.uid),r.removeAllEvents(c&&i.get(c.container),this.uid),r.removeAllEvents(c&&i.get(c.browse_button),this.uid),n&&(n.innerHTML=""),t.removeInstance(this.uid),s=u=c=n=t=null}})}return e.FileInput=s}),i(le,[ue,F],function(e,t){return e.FileReader=t}),i(de,[ue,u,h,x,f,N,y,I],function(e,t,n,i,r,o,a,s){function u(){function e(e){var t=this,i,r,a,s,u=!1;if(l){if(i=l.id.replace(/_iframe$/,""),r=n.get(i+"_form")){for(a=r.getElementsByTagName("input"),s=a.length;s--;)switch(a[s].getAttribute("type")){case"hidden":a[s].parentNode.removeChild(a[s]);break;case"file":u=!0}a=[],u||r.parentNode.removeChild(r),r=null}setTimeout(function(){o.removeEvent(l,"load",t.uid),l.parentNode&&l.parentNode.removeChild(l);var n=t.getRuntime().getShimContainer();n.children.length||n.parentNode.removeChild(n),n=l=null,e()},1)}}var u,c,l;t.extend(this,{send:function(d,h){function f(){var n=m.getShimContainer()||document.body,r=document.createElement("div");r.innerHTML='',l=r.firstChild,n.appendChild(l),o.addEvent(l,"load",function(){var n;try{n=l.contentWindow.document||l.contentDocument||window.frames[l.id].document,/^4(0[0-9]|1[0-7]|2[2346])\s/.test(n.title)?u=n.title.replace(/^(\d+).*$/,"$1"):(u=200,c=t.trim(n.body.innerHTML),p.trigger({type:"progress",loaded:c.length,total:c.length}),y&&p.trigger({type:"uploadprogress",loaded:y.size||1025,total:y.size||1025}))}catch(r){if(!i.hasSameOrigin(d.url))return void e.call(p,function(){p.trigger("error")});u=404}e.call(p,function(){p.trigger("load")})},p.uid)}var p=this,m=p.getRuntime(),g,v,w,y;if(u=c=null,h instanceof s&&h.hasBlob()){if(y=h.getBlob(),g=y.uid,w=n.get(g),v=n.get(g+"_form"),!v)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR)}else g=t.guid("uid_"),v=document.createElement("form"),v.setAttribute("id",g+"_form"),v.setAttribute("method",d.method),v.setAttribute("enctype","multipart/form-data"),v.setAttribute("encoding","multipart/form-data"),m.getShimContainer().appendChild(v);v.setAttribute("target",g+"_iframe"),h instanceof s&&h.each(function(e,n){if(e instanceof a)w&&w.setAttribute("name",n);else{var i=document.createElement("input");t.extend(i,{type:"hidden",name:n,value:e}),w?v.insertBefore(i,w):v.appendChild(i)}}),v.setAttribute("action",d.url),f(),v.submit(),p.trigger("loadstart")},getStatus:function(){return u},getResponse:function(e){if("json"===e&&"string"===t.typeOf(c)&&window.JSON)try{
+return JSON.parse(c.replace(/^\s*]*>/,"").replace(/<\/pre>\s*$/,""))}catch(n){return null}return c},abort:function(){var t=this;l&&l.contentWindow&&(l.contentWindow.stop?l.contentWindow.stop():l.contentWindow.document.execCommand?l.contentWindow.document.execCommand("Stop"):l.src="about:blank"),e.call(this,function(){t.dispatchEvent("abort")})}})}return e.XMLHttpRequest=u}),i(he,[ue,j],function(e,t){return e.Image=t}),a([u,c,l,d,h,f,p,m,g,v,w,y,E,_,b,x,R,A,I,T,S,O,N])}(this);;(function(e){"use strict";var t={},n=e.moxie.core.utils.Basic.inArray;return function r(e){var i,s;for(i in e)s=typeof e[i],s==="object"&&!~n(i,["Exceptions","Env","Mime"])?r(e[i]):s==="function"&&(t[i]=e[i])}(e.moxie),t.Env=e.moxie.core.utils.Env,t.Mime=e.moxie.core.utils.Mime,t.Exceptions=e.moxie.core.Exceptions,e.mOxie=t,e.o||(e.o=t),t})(this);
\ No newline at end of file
diff --git a/qiniu_fields/static/qiniu_fields/plupload/plupload.dev.js b/qiniu_fields/static/qiniu_fields/plupload/plupload.dev.js
new file mode 100644
index 0000000..606cf7f
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/plupload/plupload.dev.js
@@ -0,0 +1,2347 @@
+/**
+ * Plupload - multi-runtime File Uploader
+ * v2.1.8
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ *
+ * Date: 2015-07-21
+ */
+/**
+ * Plupload.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/*global mOxie:true */
+
+;(function(window, o, undef) {
+
+var delay = window.setTimeout
+, fileFilters = {}
+;
+
+// convert plupload features to caps acceptable by mOxie
+function normalizeCaps(settings) {
+ var features = settings.required_features, caps = {};
+
+ function resolve(feature, value, strict) {
+ // Feature notation is deprecated, use caps (this thing here is required for backward compatibility)
+ var map = {
+ chunks: 'slice_blob',
+ jpgresize: 'send_binary_string',
+ pngresize: 'send_binary_string',
+ progress: 'report_upload_progress',
+ multi_selection: 'select_multiple',
+ dragdrop: 'drag_and_drop',
+ drop_element: 'drag_and_drop',
+ headers: 'send_custom_headers',
+ urlstream_upload: 'send_binary_string',
+ canSendBinary: 'send_binary',
+ triggerDialog: 'summon_file_dialog'
+ };
+
+ if (map[feature]) {
+ caps[map[feature]] = value;
+ } else if (!strict) {
+ caps[feature] = value;
+ }
+ }
+
+ if (typeof(features) === 'string') {
+ plupload.each(features.split(/\s*,\s*/), function(feature) {
+ resolve(feature, true);
+ });
+ } else if (typeof(features) === 'object') {
+ plupload.each(features, function(value, feature) {
+ resolve(feature, value);
+ });
+ } else if (features === true) {
+ // check settings for required features
+ if (settings.chunk_size > 0) {
+ caps.slice_blob = true;
+ }
+
+ if (settings.resize.enabled || !settings.multipart) {
+ caps.send_binary_string = true;
+ }
+
+ plupload.each(settings, function(value, feature) {
+ resolve(feature, !!value, true); // strict check
+ });
+ }
+
+ return caps;
+}
+
+/**
+ * @module plupload
+ * @static
+ */
+var plupload = {
+ /**
+ * Plupload version will be replaced on build.
+ *
+ * @property VERSION
+ * @for Plupload
+ * @static
+ * @final
+ */
+ VERSION : '2.1.8',
+
+ /**
+ * The state of the queue before it has started and after it has finished
+ *
+ * @property STOPPED
+ * @static
+ * @final
+ */
+ STOPPED : 1,
+
+ /**
+ * Upload process is running
+ *
+ * @property STARTED
+ * @static
+ * @final
+ */
+ STARTED : 2,
+
+ /**
+ * File is queued for upload
+ *
+ * @property QUEUED
+ * @static
+ * @final
+ */
+ QUEUED : 1,
+
+ /**
+ * File is being uploaded
+ *
+ * @property UPLOADING
+ * @static
+ * @final
+ */
+ UPLOADING : 2,
+
+ /**
+ * File has failed to be uploaded
+ *
+ * @property FAILED
+ * @static
+ * @final
+ */
+ FAILED : 4,
+
+ /**
+ * File has been uploaded successfully
+ *
+ * @property DONE
+ * @static
+ * @final
+ */
+ DONE : 5,
+
+ // Error constants used by the Error event
+
+ /**
+ * Generic error for example if an exception is thrown inside Silverlight.
+ *
+ * @property GENERIC_ERROR
+ * @static
+ * @final
+ */
+ GENERIC_ERROR : -100,
+
+ /**
+ * HTTP transport error. For example if the server produces a HTTP status other than 200.
+ *
+ * @property HTTP_ERROR
+ * @static
+ * @final
+ */
+ HTTP_ERROR : -200,
+
+ /**
+ * Generic I/O error. For example if it wasn't possible to open the file stream on local machine.
+ *
+ * @property IO_ERROR
+ * @static
+ * @final
+ */
+ IO_ERROR : -300,
+
+ /**
+ * @property SECURITY_ERROR
+ * @static
+ * @final
+ */
+ SECURITY_ERROR : -400,
+
+ /**
+ * Initialization error. Will be triggered if no runtime was initialized.
+ *
+ * @property INIT_ERROR
+ * @static
+ * @final
+ */
+ INIT_ERROR : -500,
+
+ /**
+ * File size error. If the user selects a file that is too large it will be blocked and an error of this type will be triggered.
+ *
+ * @property FILE_SIZE_ERROR
+ * @static
+ * @final
+ */
+ FILE_SIZE_ERROR : -600,
+
+ /**
+ * File extension error. If the user selects a file that isn't valid according to the filters setting.
+ *
+ * @property FILE_EXTENSION_ERROR
+ * @static
+ * @final
+ */
+ FILE_EXTENSION_ERROR : -601,
+
+ /**
+ * Duplicate file error. If prevent_duplicates is set to true and user selects the same file again.
+ *
+ * @property FILE_DUPLICATE_ERROR
+ * @static
+ * @final
+ */
+ FILE_DUPLICATE_ERROR : -602,
+
+ /**
+ * Runtime will try to detect if image is proper one. Otherwise will throw this error.
+ *
+ * @property IMAGE_FORMAT_ERROR
+ * @static
+ * @final
+ */
+ IMAGE_FORMAT_ERROR : -700,
+
+ /**
+ * While working on files runtime may run out of memory and will throw this error.
+ *
+ * @since 2.1.2
+ * @property MEMORY_ERROR
+ * @static
+ * @final
+ */
+ MEMORY_ERROR : -701,
+
+ /**
+ * Each runtime has an upper limit on a dimension of the image it can handle. If bigger, will throw this error.
+ *
+ * @property IMAGE_DIMENSIONS_ERROR
+ * @static
+ * @final
+ */
+ IMAGE_DIMENSIONS_ERROR : -702,
+
+ /**
+ * Mime type lookup table.
+ *
+ * @property mimeTypes
+ * @type Object
+ * @final
+ */
+ mimeTypes : o.mimes,
+
+ /**
+ * In some cases sniffing is the only way around :(
+ */
+ ua: o.ua,
+
+ /**
+ * Gets the true type of the built-in object (better version of typeof).
+ * @credits Angus Croll (http://javascriptweblog.wordpress.com/)
+ *
+ * @method typeOf
+ * @static
+ * @param {Object} o Object to check.
+ * @return {String} Object [[Class]]
+ */
+ typeOf: o.typeOf,
+
+ /**
+ * Extends the specified object with another object.
+ *
+ * @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.
+ */
+ extend : o.extend,
+
+ /**
+ * Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers.
+ * The only way a user would be able to get the same ID is if the two persons at the same exact millisecond manages
+ * to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique.
+ * It's more probable for the earth to be hit with an asteriod. You can also if you want to be 100% sure set the plupload.guidPrefix property
+ * to an user unique key.
+ *
+ * @method guid
+ * @static
+ * @return {String} Virtually unique id.
+ */
+ guid : o.guid,
+
+ /**
+ * Get array of DOM Elements by their ids.
+ *
+ * @method get
+ * @for Utils
+ * @param {String} id Identifier of the DOM Element
+ * @return {Array}
+ */
+ get : function get(ids) {
+ var els = [], el;
+
+ if (o.typeOf(ids) !== 'array') {
+ ids = [ids];
+ }
+
+ var i = ids.length;
+ while (i--) {
+ el = o.get(ids[i]);
+ if (el) {
+ els.push(el);
+ }
+ }
+
+ return els.length ? els : null;
+ },
+
+ /**
+ * 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.
+ */
+ each : o.each,
+
+ /**
+ * 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.
+ */
+ getPos : o.getPos,
+
+ /**
+ * 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.
+ */
+ getSize : o.getSize,
+
+ /**
+ * Encodes the specified string.
+ *
+ * @method xmlEncode
+ * @static
+ * @param {String} s String to encode.
+ * @return {String} Encoded string.
+ */
+ xmlEncode : function(str) {
+ var xmlEncodeChars = {'<' : 'lt', '>' : 'gt', '&' : 'amp', '"' : 'quot', '\'' : '#39'}, xmlEncodeRegExp = /[<>&\"\']/g;
+
+ return str ? ('' + str).replace(xmlEncodeRegExp, function(chr) {
+ return xmlEncodeChars[chr] ? '&' + xmlEncodeChars[chr] + ';' : chr;
+ }) : str;
+ },
+
+ /**
+ * Forces anything into an array.
+ *
+ * @method toArray
+ * @static
+ * @param {Object} obj Object with length field.
+ * @return {Array} Array object containing all items.
+ */
+ toArray : o.toArray,
+
+ /**
+ * Find an element in array and return its 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
+ */
+ inArray : o.inArray,
+
+ /**
+ * Extends the language pack object with new items.
+ *
+ * @method addI18n
+ * @static
+ * @param {Object} pack Language pack items to add.
+ * @return {Object} Extended language pack object.
+ */
+ addI18n : o.addI18n,
+
+ /**
+ * Translates the specified string by checking for the english string in the language pack lookup.
+ *
+ * @method translate
+ * @static
+ * @param {String} str String to look for.
+ * @return {String} Translated string or the input string if it wasn't found.
+ */
+ translate : o.translate,
+
+ /**
+ * Checks if object is empty.
+ *
+ * @method isEmptyObj
+ * @static
+ * @param {Object} obj Object to check.
+ * @return {Boolean}
+ */
+ isEmptyObj : o.isEmptyObj,
+
+ /**
+ * 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
+ */
+ hasClass : o.hasClass,
+
+ /**
+ * 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
+ */
+ addClass : o.addClass,
+
+ /**
+ * 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
+ */
+ removeClass : o.removeClass,
+
+ /**
+ * 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
+ */
+ getStyle : o.getStyle,
+
+ /**
+ * 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} (optional) key that might be used to add specifity to the event record.
+ */
+ addEvent : o.addEvent,
+
+ /**
+ * 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} (optional) might be a callback or unique key to match.
+ */
+ removeEvent: o.removeEvent,
+
+ /**
+ * Remove all kind of events from the specified object
+ *
+ * @method removeAllEvents
+ * @static
+ * @param {Object} obj DOM element to remove event listeners from.
+ * @param {String} (optional) unique key to match, when removing events.
+ */
+ removeAllEvents: o.removeAllEvents,
+
+ /**
+ * Cleans the specified name from national characters (diacritics). The result will be a name with only a-z, 0-9 and _.
+ *
+ * @method cleanName
+ * @static
+ * @param {String} s String to clean up.
+ * @return {String} Cleaned string.
+ */
+ cleanName : function(name) {
+ var i, lookup;
+
+ // Replace diacritics
+ lookup = [
+ /[\300-\306]/g, 'A', /[\340-\346]/g, 'a',
+ /\307/g, 'C', /\347/g, 'c',
+ /[\310-\313]/g, 'E', /[\350-\353]/g, 'e',
+ /[\314-\317]/g, 'I', /[\354-\357]/g, 'i',
+ /\321/g, 'N', /\361/g, 'n',
+ /[\322-\330]/g, 'O', /[\362-\370]/g, 'o',
+ /[\331-\334]/g, 'U', /[\371-\374]/g, 'u'
+ ];
+
+ for (i = 0; i < lookup.length; i += 2) {
+ name = name.replace(lookup[i], lookup[i + 1]);
+ }
+
+ // Replace whitespace
+ name = name.replace(/\s+/g, '_');
+
+ // Remove anything else
+ name = name.replace(/[^a-z0-9_\-\.]+/gi, '');
+
+ return name;
+ },
+
+ /**
+ * Builds a full url out of a base URL and an object with items to append as query string items.
+ *
+ * @method buildUrl
+ * @static
+ * @param {String} url Base URL to append query string items to.
+ * @param {Object} items Name/value object to serialize as a querystring.
+ * @return {String} String with url + serialized query string items.
+ */
+ buildUrl : function(url, items) {
+ var query = '';
+
+ plupload.each(items, function(value, name) {
+ query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value);
+ });
+
+ if (query) {
+ url += (url.indexOf('?') > 0 ? '&' : '?') + query;
+ }
+
+ return url;
+ },
+
+ /**
+ * Formats the specified number as a size string for example 1024 becomes 1 KB.
+ *
+ * @method formatSize
+ * @static
+ * @param {Number} size Size to format as string.
+ * @return {String} Formatted size string.
+ */
+ formatSize : function(size) {
+
+ if (size === undef || /\D/.test(size)) {
+ return plupload.translate('N/A');
+ }
+
+ function round(num, precision) {
+ return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
+ }
+
+ var boundary = Math.pow(1024, 4);
+
+ // TB
+ if (size > boundary) {
+ return round(size / boundary, 1) + " " + plupload.translate('tb');
+ }
+
+ // GB
+ if (size > (boundary/=1024)) {
+ return round(size / boundary, 1) + " " + plupload.translate('gb');
+ }
+
+ // MB
+ if (size > (boundary/=1024)) {
+ return round(size / boundary, 1) + " " + plupload.translate('mb');
+ }
+
+ // KB
+ if (size > 1024) {
+ return Math.round(size / 1024) + " " + plupload.translate('kb');
+ }
+
+ return size + " " + plupload.translate('b');
+ },
+
+
+ /**
+ * Parses the specified size string into a byte value. For example 10kb becomes 10240.
+ *
+ * @method parseSize
+ * @static
+ * @param {String|Number} size String to parse or number to just pass through.
+ * @return {Number} Size in bytes.
+ */
+ parseSize : o.parseSizeStr,
+
+
+ /**
+ * A way to predict what runtime will be choosen in the current environment with the
+ * specified settings.
+ *
+ * @method predictRuntime
+ * @static
+ * @param {Object|String} config Plupload settings to check
+ * @param {String} [runtimes] Comma-separated list of runtimes to check against
+ * @return {String} Type of compatible runtime
+ */
+ predictRuntime : function(config, runtimes) {
+ var up, runtime;
+
+ up = new plupload.Uploader(config);
+ runtime = o.Runtime.thatCan(up.getOption().required_features, runtimes || config.runtimes);
+ up.destroy();
+ return runtime;
+ },
+
+ /**
+ * Registers a filter that will be executed for each file added to the queue.
+ * If callback returns false, file will not be added.
+ *
+ * Callback receives two arguments: a value for the filter as it was specified in settings.filters
+ * and a file to be filtered. Callback is executed in the context of uploader instance.
+ *
+ * @method addFileFilter
+ * @static
+ * @param {String} name Name of the filter by which it can be referenced in settings.filters
+ * @param {String} cb Callback - the actual routine that every added file must pass
+ */
+ addFileFilter: function(name, cb) {
+ fileFilters[name] = cb;
+ }
+};
+
+
+plupload.addFileFilter('mime_types', function(filters, file, cb) {
+ if (filters.length && !filters.regexp.test(file.name)) {
+ this.trigger('Error', {
+ code : plupload.FILE_EXTENSION_ERROR,
+ message : plupload.translate('File extension error.'),
+ file : file
+ });
+ cb(false);
+ } else {
+ cb(true);
+ }
+});
+
+
+plupload.addFileFilter('max_file_size', function(maxSize, file, cb) {
+ var undef;
+
+ maxSize = plupload.parseSize(maxSize);
+
+ // Invalid file size
+ if (file.size !== undef && maxSize && file.size > maxSize) {
+ this.trigger('Error', {
+ code : plupload.FILE_SIZE_ERROR,
+ message : plupload.translate('File size error.'),
+ file : file
+ });
+ cb(false);
+ } else {
+ cb(true);
+ }
+});
+
+
+plupload.addFileFilter('prevent_duplicates', function(value, file, cb) {
+ if (value) {
+ var ii = this.files.length;
+ while (ii--) {
+ // Compare by name and size (size might be 0 or undefined, but still equivalent for both)
+ if (file.name === this.files[ii].name && file.size === this.files[ii].size) {
+ this.trigger('Error', {
+ code : plupload.FILE_DUPLICATE_ERROR,
+ message : plupload.translate('Duplicate file error.'),
+ file : file
+ });
+ cb(false);
+ return;
+ }
+ }
+ }
+ cb(true);
+});
+
+
+/**
+@class Uploader
+@constructor
+
+@param {Object} settings For detailed information about each option check documentation.
+ @param {String|DOMElement} settings.browse_button id of the DOM element or DOM element itself to use as file dialog trigger.
+ @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 {Boolean} [settings.send_chunk_number=true] Whether to send chunks and chunk numbers, or total and offset bytes.
+ @param {String|DOMElement} [settings.container] id of the DOM element or DOM element itself that will be used to wrap uploader structures. Defaults to immediate parent of the `browse_button` element.
+ @param {String|DOMElement} [settings.drop_element] id of the DOM element or DOM element itself to use as a drop zone for Drag-n-Drop.
+ @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 {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} [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 {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.send_file_name=true] Whether to send file name as additional argument - 'name' (required for chunked uploads and some other cases where file name cannot be sent via normal ways).
+*/
+plupload.Uploader = function(options) {
+ /**
+ Fires when the current RunTime has been initialized.
+
+ @event Init
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ Fires after the init event incase you need to perform actions there.
+
+ @event PostInit
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ Fires when the option is changed in via uploader.setOption().
+
+ @event OptionChanged
+ @since 2.1
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {String} name Name of the option that was changed
+ @param {Mixed} value New value for the specified option
+ @param {Mixed} oldValue Previous value of the option
+ */
+
+ /**
+ Fires when the silverlight/flash or other shim needs to move.
+
+ @event Refresh
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ Fires when the overall state is being changed for the upload queue.
+
+ @event StateChanged
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ Fires when browse_button is clicked and browse dialog shows.
+
+ @event Browse
+ @since 2.1.2
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ Fires for every filtered file before it is added to the queue.
+
+ @event FileFiltered
+ @since 2.1
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {plupload.File} file Another file that has to be added to the queue.
+ */
+
+ /**
+ Fires when the file queue is changed. In other words when files are added/removed to the files array of the uploader instance.
+
+ @event QueueChanged
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ Fires after files were filtered and added to the queue.
+
+ @event FilesAdded
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {Array} files Array of file objects that were added to queue by the user.
+ */
+
+ /**
+ Fires when file is removed from the queue.
+
+ @event FilesRemoved
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {Array} files Array of files that got removed.
+ */
+
+ /**
+ Fires just before a file is uploaded. Can be used to cancel the upload for the specified file
+ by returning false from the handler.
+
+ @event BeforeUpload
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {plupload.File} file File to be uploaded.
+ */
+
+ /**
+ Fires when a file is to be uploaded by the runtime.
+
+ @event UploadFile
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {plupload.File} file File to be uploaded.
+ */
+
+ /**
+ Fires while a file is being uploaded. Use this event to update the current file upload progress.
+
+ @event UploadProgress
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {plupload.File} file File that is currently being uploaded.
+ */
+
+ /**
+ Fires when file chunk is uploaded.
+
+ @event ChunkUploaded
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {plupload.File} file File that the chunk was uploaded for.
+ @param {Object} result Object with response properties.
+ @param {Number} result.offset The amount of bytes the server has received so far, including this chunk.
+ @param {Number} result.total The size of the file.
+ @param {String} result.response The response body sent by the server.
+ @param {Number} result.status The HTTP status code sent by the server.
+ @param {String} result.responseHeaders All the response headers as a single string.
+ */
+
+ /**
+ Fires when a file is successfully uploaded.
+
+ @event FileUploaded
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {plupload.File} file File that was uploaded.
+ @param {Object} result Object with response properties.
+ @param {String} result.response The response body sent by the server.
+ @param {Number} result.status The HTTP status code sent by the server.
+ @param {String} result.responseHeaders All the response headers as a single string.
+ */
+
+ /**
+ Fires when all files in a queue are uploaded.
+
+ @event UploadComplete
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {Array} files Array of file objects that was added to queue/selected by the user.
+ */
+
+ /**
+ Fires when a error occurs.
+
+ @event Error
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ @param {Object} error Contains code, message and sometimes file and other details.
+ @param {Number} error.code The plupload error code.
+ @param {String} error.message Description of the error (uses i18n).
+ */
+
+ /**
+ Fires when destroy method is called.
+
+ @event Destroy
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+ var uid = plupload.guid()
+ , settings
+ , files = []
+ , preferred_caps = {}
+ , fileInputs = []
+ , fileDrops = []
+ , startTime
+ , total
+ , disabled = false
+ , xhr
+ ;
+
+
+ // Private methods
+ function uploadNext() {
+ var file, count = 0, i;
+
+ if (this.state == plupload.STARTED) {
+ // Find first QUEUED file
+ for (i = 0; i < files.length; i++) {
+ if (!file && files[i].status == plupload.QUEUED) {
+ file = files[i];
+ if (this.trigger("BeforeUpload", file)) {
+ file.status = plupload.UPLOADING;
+ this.trigger("UploadFile", file);
+ }
+ } else {
+ count++;
+ }
+ }
+
+ // All files are DONE or FAILED
+ if (count == files.length) {
+ if (this.state !== plupload.STOPPED) {
+ this.state = plupload.STOPPED;
+ this.trigger("StateChanged");
+ }
+ this.trigger("UploadComplete", files);
+ }
+ }
+ }
+
+
+ function calcFile(file) {
+ file.percent = file.size > 0 ? Math.ceil(file.loaded / file.size * 100) : 100;
+ calc();
+ }
+
+
+ function calc() {
+ var i, file;
+
+ // Reset stats
+ total.reset();
+
+ // Check status, size, loaded etc on all files
+ for (i = 0; i < files.length; i++) {
+ file = files[i];
+
+ if (file.size !== undef) {
+ // We calculate totals based on original file size
+ total.size += file.origSize;
+
+ // Since we cannot predict file size after resize, we do opposite and
+ // interpolate loaded amount to match magnitude of total
+ total.loaded += file.loaded * file.origSize / file.size;
+ } else {
+ total.size = undef;
+ }
+
+ if (file.status == plupload.DONE) {
+ total.uploaded++;
+ } else if (file.status == plupload.FAILED) {
+ total.failed++;
+ } else {
+ total.queued++;
+ }
+ }
+
+ // If we couldn't calculate a total file size then use the number of files to calc percent
+ if (total.size === undef) {
+ total.percent = files.length > 0 ? Math.ceil(total.uploaded / files.length * 100) : 0;
+ } else {
+ total.bytesPerSec = Math.ceil(total.loaded / ((+new Date() - startTime || 1) / 1000.0));
+ total.percent = total.size > 0 ? Math.ceil(total.loaded / total.size * 100) : 0;
+ }
+ }
+
+
+ function getRUID() {
+ var ctrl = fileInputs[0] || fileDrops[0];
+ if (ctrl) {
+ return ctrl.getRuntime().uid;
+ }
+ return false;
+ }
+
+
+ function runtimeCan(file, cap) {
+ if (file.ruid) {
+ var info = o.Runtime.getInfo(file.ruid);
+ if (info) {
+ return info.can(cap);
+ }
+ }
+ return false;
+ }
+
+
+ function bindEventListeners() {
+ this.bind('FilesAdded FilesRemoved', function(up) {
+ up.trigger('QueueChanged');
+ up.refresh();
+ });
+
+ this.bind('CancelUpload', onCancelUpload);
+
+ this.bind('BeforeUpload', onBeforeUpload);
+
+ this.bind('UploadFile', onUploadFile);
+
+ this.bind('UploadProgress', onUploadProgress);
+
+ this.bind('StateChanged', onStateChanged);
+
+ this.bind('QueueChanged', calc);
+
+ this.bind('Error', onError);
+
+ this.bind('FileUploaded', onFileUploaded);
+
+ this.bind('Destroy', onDestroy);
+ }
+
+
+ function initControls(settings, cb) {
+ var self = this, inited = 0, queue = [];
+
+ // common settings
+ var options = {
+ runtime_order: settings.runtimes,
+ required_caps: settings.required_features,
+ preferred_caps: preferred_caps,
+ swf_url: settings.flash_swf_url,
+ xap_url: settings.silverlight_xap_url
+ };
+
+ // add runtime specific options if any
+ plupload.each(settings.runtimes.split(/\s*,\s*/), function(runtime) {
+ if (settings[runtime]) {
+ options[runtime] = settings[runtime];
+ }
+ });
+
+ // initialize file pickers - there can be many
+ if (settings.browse_button) {
+ plupload.each(settings.browse_button, function(el) {
+ queue.push(function(cb) {
+ var fileInput = new o.FileInput(plupload.extend({}, options, {
+ accept: settings.filters.mime_types,
+ name: settings.file_data_name,
+ multiple: settings.multi_selection,
+ container: settings.container,
+ browse_button: el
+ }));
+
+ fileInput.onready = function() {
+ var info = o.Runtime.getInfo(this.ruid);
+
+ // for backward compatibility
+ o.extend(self.features, {
+ chunks: info.can('slice_blob'),
+ multipart: info.can('send_multipart'),
+ multi_selection: info.can('select_multiple')
+ });
+
+ inited++;
+ fileInputs.push(this);
+ cb();
+ };
+
+ fileInput.onchange = function() {
+ self.addFile(this.files);
+ };
+
+ fileInput.bind('mouseenter mouseleave mousedown mouseup', function(e) {
+ if (!disabled) {
+ if (settings.browse_button_hover) {
+ if ('mouseenter' === e.type) {
+ o.addClass(el, settings.browse_button_hover);
+ } else if ('mouseleave' === e.type) {
+ o.removeClass(el, settings.browse_button_hover);
+ }
+ }
+
+ if (settings.browse_button_active) {
+ if ('mousedown' === e.type) {
+ o.addClass(el, settings.browse_button_active);
+ } else if ('mouseup' === e.type) {
+ o.removeClass(el, settings.browse_button_active);
+ }
+ }
+ }
+ });
+
+ fileInput.bind('mousedown', function() {
+ self.trigger('Browse');
+ });
+
+ fileInput.bind('error runtimeerror', function() {
+ fileInput = null;
+ cb();
+ });
+
+ fileInput.init();
+ });
+ });
+ }
+
+ // initialize drop zones
+ if (settings.drop_element) {
+ plupload.each(settings.drop_element, function(el) {
+ queue.push(function(cb) {
+ var fileDrop = new o.FileDrop(plupload.extend({}, options, {
+ drop_zone: el
+ }));
+
+ fileDrop.onready = function() {
+ var info = o.Runtime.getInfo(this.ruid);
+
+ self.features.dragdrop = info.can('drag_and_drop'); // for backward compatibility
+
+ inited++;
+ fileDrops.push(this);
+ cb();
+ };
+
+ fileDrop.ondrop = function() {
+ self.addFile(this.files);
+ };
+
+ fileDrop.bind('error runtimeerror', function() {
+ fileDrop = null;
+ cb();
+ });
+
+ fileDrop.init();
+ });
+ });
+ }
+
+
+ o.inSeries(queue, function() {
+ if (typeof(cb) === 'function') {
+ cb(inited);
+ }
+ });
+ }
+
+
+ function resizeImage(blob, params, cb) {
+ var img = new o.Image();
+
+ try {
+ img.onload = function() {
+ // no manipulation required if...
+ if (params.width > this.width &&
+ params.height > this.height &&
+ params.quality === undef &&
+ params.preserve_headers &&
+ !params.crop
+ ) {
+ this.destroy();
+ return cb(blob);
+ }
+ // otherwise downsize
+ img.downsize(params.width, params.height, params.crop, params.preserve_headers);
+ };
+
+ img.onresize = function() {
+ cb(this.getAsBlob(blob.type, params.quality));
+ this.destroy();
+ };
+
+ img.onerror = function() {
+ cb(blob);
+ };
+
+ img.load(blob);
+ } catch(ex) {
+ cb(blob);
+ }
+ }
+
+
+ function setOption(option, value, init) {
+ var self = this, reinitRequired = false;
+
+ function _setOption(option, value, init) {
+ var oldValue = settings[option];
+
+ switch (option) {
+ case 'max_file_size':
+ if (option === 'max_file_size') {
+ settings.max_file_size = settings.filters.max_file_size = value;
+ }
+ break;
+
+ case 'chunk_size':
+ if (value = plupload.parseSize(value)) {
+ settings[option] = value;
+ settings.send_file_name = true;
+ }
+ break;
+
+ case 'multipart':
+ settings[option] = value;
+ if (!value) {
+ settings.send_file_name = true;
+ }
+ break;
+
+ case 'unique_names':
+ settings[option] = value;
+ if (value) {
+ settings.send_file_name = true;
+ }
+ break;
+
+ case 'filters':
+ // for sake of backward compatibility
+ if (plupload.typeOf(value) === 'array') {
+ value = {
+ mime_types: value
+ };
+ }
+
+ if (init) {
+ plupload.extend(settings.filters, value);
+ } else {
+ settings.filters = value;
+ }
+
+ // if file format filters are being updated, regenerate the matching expressions
+ if (value.mime_types) {
+ settings.filters.mime_types.regexp = (function(filters) {
+ var extensionsRegExp = [];
+
+ plupload.each(filters, function(filter) {
+ plupload.each(filter.extensions.split(/,/), function(ext) {
+ if (/^\s*\*\s*$/.test(ext)) {
+ extensionsRegExp.push('\\.*');
+ } else {
+ extensionsRegExp.push('\\.' + ext.replace(new RegExp('[' + ('/^$.*+?|()[]{}\\'.replace(/./g, '\\$&')) + ']', 'g'), '\\$&'));
+ }
+ });
+ });
+
+ return new RegExp('(' + extensionsRegExp.join('|') + ')$', 'i');
+ }(settings.filters.mime_types));
+ }
+ break;
+
+ case 'resize':
+ if (init) {
+ plupload.extend(settings.resize, value, {
+ enabled: true
+ });
+ } else {
+ settings.resize = value;
+ }
+ break;
+
+ case 'prevent_duplicates':
+ settings.prevent_duplicates = settings.filters.prevent_duplicates = !!value;
+ break;
+
+ case 'browse_button':
+ case 'drop_element':
+ value = plupload.get(value);
+
+ case 'container':
+ case 'runtimes':
+ case 'multi_selection':
+ case 'flash_swf_url':
+ case 'silverlight_xap_url':
+ settings[option] = value;
+ if (!init) {
+ reinitRequired = true;
+ }
+ break;
+
+ default:
+ settings[option] = value;
+ }
+
+ if (!init) {
+ self.trigger('OptionChanged', option, value, oldValue);
+ }
+ }
+
+ if (typeof(option) === 'object') {
+ plupload.each(option, function(value, option) {
+ _setOption(option, value, init);
+ });
+ } else {
+ _setOption(option, value, init);
+ }
+
+ if (init) {
+ // Normalize the list of required capabilities
+ settings.required_features = normalizeCaps(plupload.extend({}, settings));
+
+ // Come up with the list of capabilities that can affect default mode in a multi-mode runtimes
+ preferred_caps = normalizeCaps(plupload.extend({}, settings, {
+ required_features: true
+ }));
+ } else if (reinitRequired) {
+ self.trigger('Destroy');
+
+ initControls.call(self, settings, function(inited) {
+ if (inited) {
+ self.runtime = o.Runtime.getInfo(getRUID()).type;
+ self.trigger('Init', { runtime: self.runtime });
+ self.trigger('PostInit');
+ } else {
+ self.trigger('Error', {
+ code : plupload.INIT_ERROR,
+ message : plupload.translate('Init error.')
+ });
+ }
+ });
+ }
+ }
+
+
+ // Internal event handlers
+ function onBeforeUpload(up, file) {
+ // Generate unique target filenames
+ if (up.settings.unique_names) {
+ var matches = file.name.match(/\.([^.]+)$/), ext = "part";
+ if (matches) {
+ ext = matches[1];
+ }
+ file.target_name = file.id + '.' + ext;
+ }
+ }
+
+
+ function onUploadFile(up, file) {
+ var url = up.settings.url
+ , chunkSize = up.settings.chunk_size
+ , retries = up.settings.max_retries
+ , features = up.features
+ , offset = 0
+ , blob
+ ;
+
+ // make sure we start at a predictable offset
+ if (file.loaded) {
+ offset = file.loaded = chunkSize ? chunkSize * Math.floor(file.loaded / chunkSize) : 0;
+ }
+
+ function handleError() {
+ if (retries-- > 0) {
+ delay(uploadNextChunk, 1000);
+ } else {
+ file.loaded = offset; // reset all progress
+
+ up.trigger('Error', {
+ code : plupload.HTTP_ERROR,
+ message : plupload.translate('HTTP Error.'),
+ file : file,
+ response : xhr.responseText,
+ status : xhr.status,
+ responseHeaders: xhr.getAllResponseHeaders()
+ });
+ }
+ }
+
+ function uploadNextChunk() {
+ var chunkBlob, formData, args = {}, curChunkSize;
+
+ // make sure that file wasn't cancelled and upload is not stopped in general
+ if (file.status !== plupload.UPLOADING || up.state === plupload.STOPPED) {
+ return;
+ }
+
+ // send additional 'name' parameter only if required
+ if (up.settings.send_file_name) {
+ args.name = file.target_name || file.name;
+ }
+
+ if (chunkSize && features.chunks && blob.size > chunkSize) { // blob will be of type string if it was loaded in memory
+ curChunkSize = Math.min(chunkSize, blob.size - offset);
+ chunkBlob = blob.slice(offset, offset + curChunkSize);
+ } else {
+ curChunkSize = blob.size;
+ chunkBlob = blob;
+ }
+
+ // If chunking is enabled add corresponding args, no matter if file is bigger than chunk or smaller
+ if (chunkSize && features.chunks) {
+ // Setup query string arguments
+ if (up.settings.send_chunk_number) {
+ args.chunk = Math.ceil(offset / chunkSize);
+ args.chunks = Math.ceil(blob.size / chunkSize);
+ } else { // keep support for experimental chunk format, just in case
+ args.offset = offset;
+ args.total = blob.size;
+ }
+ }
+
+ xhr = new o.XMLHttpRequest();
+
+ // Do we have upload progress support
+ if (xhr.upload) {
+ xhr.upload.onprogress = function(e) {
+ file.loaded = Math.min(file.size, offset + e.loaded);
+ up.trigger('UploadProgress', file);
+ };
+ }
+
+ xhr.onload = function() {
+ // check if upload made itself through
+ if (xhr.status >= 400) {
+ handleError();
+ return;
+ }
+
+ retries = up.settings.max_retries; // reset the counter
+
+ // Handle chunk response
+ if (curChunkSize < blob.size) {
+ chunkBlob.destroy();
+
+ offset += curChunkSize;
+ file.loaded = Math.min(offset, blob.size);
+
+ up.trigger('ChunkUploaded', file, {
+ offset : file.loaded,
+ total : blob.size,
+ response : xhr.responseText,
+ status : xhr.status,
+ responseHeaders: xhr.getAllResponseHeaders()
+ });
+
+ // stock Android browser doesn't fire upload progress events, but in chunking mode we can fake them
+ if (o.Env.browser === 'Android Browser') {
+ // doesn't harm in general, but is not required anywhere else
+ up.trigger('UploadProgress', file);
+ }
+ } else {
+ file.loaded = file.size;
+ }
+
+ chunkBlob = formData = null; // Free memory
+
+ // Check if file is uploaded
+ if (!offset || offset >= blob.size) {
+ // If file was modified, destory the copy
+ if (file.size != file.origSize) {
+ blob.destroy();
+ blob = null;
+ }
+
+ up.trigger('UploadProgress', file);
+
+ file.status = plupload.DONE;
+
+ up.trigger('FileUploaded', file, {
+ response : xhr.responseText,
+ status : xhr.status,
+ responseHeaders: xhr.getAllResponseHeaders()
+ });
+ } else {
+ // Still chunks left
+ delay(uploadNextChunk, 1); // run detached, otherwise event handlers interfere
+ }
+ };
+
+ xhr.onerror = function() {
+ handleError();
+ };
+
+ xhr.onloadend = function() {
+ this.destroy();
+ xhr = null;
+ };
+
+ // Build multipart request
+ if (up.settings.multipart && features.multipart) {
+ xhr.open("post", url, true);
+
+ // Set custom headers
+ plupload.each(up.settings.headers, function(value, name) {
+ xhr.setRequestHeader(name, value);
+ });
+
+ formData = new o.FormData();
+
+ // Add multipart params
+ plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
+ formData.append(name, value);
+ });
+
+ // Add file and send it
+ formData.append(up.settings.file_data_name, chunkBlob);
+ xhr.send(formData, {
+ runtime_order: up.settings.runtimes,
+ required_caps: up.settings.required_features,
+ preferred_caps: preferred_caps,
+ swf_url: up.settings.flash_swf_url,
+ xap_url: up.settings.silverlight_xap_url
+ });
+ } else {
+ // if no multipart, send as binary stream
+ url = plupload.buildUrl(up.settings.url, plupload.extend(args, up.settings.multipart_params));
+
+ xhr.open("post", url, true);
+
+ xhr.setRequestHeader('Content-Type', 'application/octet-stream'); // Binary stream header
+
+ // Set custom headers
+ plupload.each(up.settings.headers, function(value, name) {
+ xhr.setRequestHeader(name, value);
+ });
+
+ xhr.send(chunkBlob, {
+ runtime_order: up.settings.runtimes,
+ required_caps: up.settings.required_features,
+ preferred_caps: preferred_caps,
+ swf_url: up.settings.flash_swf_url,
+ xap_url: up.settings.silverlight_xap_url
+ });
+ }
+ }
+
+ blob = file.getSource();
+
+ // Start uploading chunks
+ if (up.settings.resize.enabled && runtimeCan(blob, 'send_binary_string') && !!~o.inArray(blob.type, ['image/jpeg', 'image/png'])) {
+ // Resize if required
+ resizeImage.call(this, blob, up.settings.resize, function(resizedBlob) {
+ blob = resizedBlob;
+ file.size = resizedBlob.size;
+ uploadNextChunk();
+ });
+ } else {
+ uploadNextChunk();
+ }
+ }
+
+
+ function onUploadProgress(up, file) {
+ calcFile(file);
+ }
+
+
+ function onStateChanged(up) {
+ if (up.state == plupload.STARTED) {
+ // Get start time to calculate bps
+ startTime = (+new Date());
+ } else if (up.state == plupload.STOPPED) {
+ // Reset currently uploading files
+ for (var i = up.files.length - 1; i >= 0; i--) {
+ if (up.files[i].status == plupload.UPLOADING) {
+ up.files[i].status = plupload.QUEUED;
+ calc();
+ }
+ }
+ }
+ }
+
+
+ function onCancelUpload() {
+ if (xhr) {
+ xhr.abort();
+ }
+ }
+
+
+ function onFileUploaded(up) {
+ calc();
+
+ // Upload next file but detach it from the error event
+ // since other custom listeners might want to stop the queue
+ delay(function() {
+ uploadNext.call(up);
+ }, 1);
+ }
+
+
+ function onError(up, err) {
+ if (err.code === plupload.INIT_ERROR) {
+ up.destroy();
+ }
+ // Set failed status if an error occured on a file
+ else if (err.code === plupload.HTTP_ERROR) {
+ err.file.status = plupload.FAILED;
+ calcFile(err.file);
+
+ // Upload next file but detach it from the error event
+ // since other custom listeners might want to stop the queue
+ if (up.state == plupload.STARTED) { // upload in progress
+ up.trigger('CancelUpload');
+ delay(function() {
+ uploadNext.call(up);
+ }, 1);
+ }
+ }
+ }
+
+
+ function onDestroy(up) {
+ up.stop();
+
+ // Purge the queue
+ plupload.each(files, function(file) {
+ file.destroy();
+ });
+ files = [];
+
+ if (fileInputs.length) {
+ plupload.each(fileInputs, function(fileInput) {
+ fileInput.destroy();
+ });
+ fileInputs = [];
+ }
+
+ if (fileDrops.length) {
+ plupload.each(fileDrops, function(fileDrop) {
+ fileDrop.destroy();
+ });
+ fileDrops = [];
+ }
+
+ preferred_caps = {};
+ disabled = false;
+ startTime = xhr = null;
+ total.reset();
+ }
+
+
+ // Default settings
+ settings = {
+ runtimes: o.Runtime.order,
+ max_retries: 0,
+ chunk_size: 0,
+ multipart: true,
+ multi_selection: true,
+ file_data_name: 'file',
+ flash_swf_url: 'js/Moxie.swf',
+ silverlight_xap_url: 'js/Moxie.xap',
+ filters: {
+ mime_types: [],
+ prevent_duplicates: false,
+ max_file_size: 0
+ },
+ resize: {
+ enabled: false,
+ preserve_headers: true,
+ crop: false
+ },
+ send_file_name: true,
+ send_chunk_number: true
+ };
+
+
+ setOption.call(this, options, null, true);
+
+ // Inital total state
+ total = new plupload.QueueProgress();
+
+ // Add public methods
+ plupload.extend(this, {
+
+ /**
+ * Unique id for the Uploader instance.
+ *
+ * @property id
+ * @type String
+ */
+ id : uid,
+ uid : uid, // mOxie uses this to differentiate between event targets
+
+ /**
+ * Current state of the total uploading progress. This one can either be plupload.STARTED or plupload.STOPPED.
+ * These states are controlled by the stop/start methods. The default value is STOPPED.
+ *
+ * @property state
+ * @type Number
+ */
+ state : plupload.STOPPED,
+
+ /**
+ * Map of features that are available for the uploader runtime. Features will be filled
+ * before the init event is called, these features can then be used to alter the UI for the end user.
+ * Some of the current features that might be in this map is: dragdrop, chunks, jpgresize, pngresize.
+ *
+ * @property features
+ * @type Object
+ */
+ features : {},
+
+ /**
+ * Current runtime name.
+ *
+ * @property runtime
+ * @type String
+ */
+ runtime : null,
+
+ /**
+ * Current upload queue, an array of File instances.
+ *
+ * @property files
+ * @type Array
+ * @see plupload.File
+ */
+ files : files,
+
+ /**
+ * Object with name/value settings.
+ *
+ * @property settings
+ * @type Object
+ */
+ settings : settings,
+
+ /**
+ * Total progess information. How many files has been uploaded, total percent etc.
+ *
+ * @property total
+ * @type plupload.QueueProgress
+ */
+ total : total,
+
+
+ /**
+ * Initializes the Uploader instance and adds internal event listeners.
+ *
+ * @method init
+ */
+ init : function() {
+ var self = this;
+
+ if (typeof(settings.preinit) == "function") {
+ settings.preinit(self);
+ } else {
+ plupload.each(settings.preinit, function(func, name) {
+ self.bind(name, func);
+ });
+ }
+
+ bindEventListeners.call(this);
+
+ // Check for required options
+ if (!settings.browse_button || !settings.url) {
+ this.trigger('Error', {
+ code : plupload.INIT_ERROR,
+ message : plupload.translate('Init error.')
+ });
+ return;
+ }
+
+ initControls.call(this, settings, function(inited) {
+ if (typeof(settings.init) == "function") {
+ settings.init(self);
+ } else {
+ plupload.each(settings.init, function(func, name) {
+ self.bind(name, func);
+ });
+ }
+
+ if (inited) {
+ self.runtime = o.Runtime.getInfo(getRUID()).type;
+ self.trigger('Init', { runtime: self.runtime });
+ self.trigger('PostInit');
+ } else {
+ self.trigger('Error', {
+ code : plupload.INIT_ERROR,
+ message : plupload.translate('Init error.')
+ });
+ }
+ });
+ },
+
+ /**
+ * Set the value for the specified option(s).
+ *
+ * @method setOption
+ * @since 2.1
+ * @param {String|Object} option Name of the option to change or the set of key/value pairs
+ * @param {Mixed} [value] Value for the option (is ignored, if first argument is object)
+ */
+ setOption: function(option, value) {
+ setOption.call(this, option, value, !this.runtime); // until runtime not set we do not need to reinitialize
+ },
+
+ /**
+ * Get the value for the specified option or the whole configuration, if not specified.
+ *
+ * @method getOption
+ * @since 2.1
+ * @param {String} [option] Name of the option to get
+ * @return {Mixed} Value for the option or the whole set
+ */
+ getOption: function(option) {
+ if (!option) {
+ return settings;
+ }
+ return settings[option];
+ },
+
+ /**
+ * Refreshes the upload instance by dispatching out a refresh event to all runtimes.
+ * This would for example reposition flash/silverlight shims on the page.
+ *
+ * @method refresh
+ */
+ refresh : function() {
+ if (fileInputs.length) {
+ plupload.each(fileInputs, function(fileInput) {
+ fileInput.trigger('Refresh');
+ });
+ }
+ this.trigger('Refresh');
+ },
+
+ /**
+ * Starts uploading the queued files.
+ *
+ * @method start
+ */
+ start : function() {
+ if (this.state != plupload.STARTED) {
+ this.state = plupload.STARTED;
+ this.trigger('StateChanged');
+
+ uploadNext.call(this);
+ }
+ },
+
+ /**
+ * Stops the upload of the queued files.
+ *
+ * @method stop
+ */
+ stop : function() {
+ if (this.state != plupload.STOPPED) {
+ this.state = plupload.STOPPED;
+ this.trigger('StateChanged');
+ this.trigger('CancelUpload');
+ }
+ },
+
+
+ /**
+ * Disables/enables browse button on request.
+ *
+ * @method disableBrowse
+ * @param {Boolean} disable Whether to disable or enable (default: true)
+ */
+ disableBrowse : function() {
+ disabled = arguments[0] !== undef ? arguments[0] : true;
+
+ if (fileInputs.length) {
+ plupload.each(fileInputs, function(fileInput) {
+ fileInput.disable(disabled);
+ });
+ }
+
+ this.trigger('DisableBrowse', disabled);
+ },
+
+ /**
+ * Returns the specified file object by id.
+ *
+ * @method getFile
+ * @param {String} id File id to look for.
+ * @return {plupload.File} File object or undefined if it wasn't found;
+ */
+ getFile : function(id) {
+ var i;
+ for (i = files.length - 1; i >= 0; i--) {
+ if (files[i].id === id) {
+ return files[i];
+ }
+ }
+ },
+
+ /**
+ * Adds file to the queue programmatically. Can be native file, instance of Plupload.File,
+ * instance of mOxie.File, input[type="file"] element, or array of these. Fires FilesAdded,
+ * if any files were added to the queue. Otherwise nothing happens.
+ *
+ * @method addFile
+ * @since 2.0
+ * @param {plupload.File|mOxie.File|File|Node|Array} file File or files to add to the queue.
+ * @param {String} [fileName] If specified, will be used as a name for the file
+ */
+ addFile : function(file, fileName) {
+ var self = this
+ , queue = []
+ , filesAdded = []
+ , ruid
+ ;
+
+ function filterFile(file, cb) {
+ var queue = [];
+ o.each(self.settings.filters, function(rule, name) {
+ if (fileFilters[name]) {
+ queue.push(function(cb) {
+ fileFilters[name].call(self, rule, file, function(res) {
+ cb(!res);
+ });
+ });
+ }
+ });
+ o.inSeries(queue, cb);
+ }
+
+ /**
+ * @method resolveFile
+ * @private
+ * @param {o.File|o.Blob|plupload.File|File|Blob|input[type="file"]} file
+ */
+ function resolveFile(file) {
+ var type = o.typeOf(file);
+
+ // o.File
+ if (file instanceof o.File) {
+ if (!file.ruid && !file.isDetached()) {
+ if (!ruid) { // weird case
+ return false;
+ }
+ file.ruid = ruid;
+ file.connectRuntime(ruid);
+ }
+ resolveFile(new plupload.File(file));
+ }
+ // o.Blob
+ else if (file instanceof o.Blob) {
+ resolveFile(file.getSource());
+ file.destroy();
+ }
+ // plupload.File - final step for other branches
+ else if (file instanceof plupload.File) {
+ if (fileName) {
+ file.name = fileName;
+ }
+
+ queue.push(function(cb) {
+ // run through the internal and user-defined filters, if any
+ filterFile(file, function(err) {
+ if (!err) {
+ // make files available for the filters by updating the main queue directly
+ files.push(file);
+ // collect the files that will be passed to FilesAdded event
+ filesAdded.push(file);
+
+ self.trigger("FileFiltered", file);
+ }
+ delay(cb, 1); // do not build up recursions or eventually we might hit the limits
+ });
+ });
+ }
+ // native File or blob
+ else if (o.inArray(type, ['file', 'blob']) !== -1) {
+ resolveFile(new o.File(null, file));
+ }
+ // input[type="file"]
+ else if (type === 'node' && o.typeOf(file.files) === 'filelist') {
+ // if we are dealing with input[type="file"]
+ o.each(file.files, resolveFile);
+ }
+ // mixed array of any supported types (see above)
+ else if (type === 'array') {
+ fileName = null; // should never happen, but unset anyway to avoid funny situations
+ o.each(file, resolveFile);
+ }
+ }
+
+ ruid = getRUID();
+
+ resolveFile(file);
+
+ if (queue.length) {
+ o.inSeries(queue, function() {
+ // if any files left after filtration, trigger FilesAdded
+ if (filesAdded.length) {
+ self.trigger("FilesAdded", filesAdded);
+ }
+ });
+ }
+ },
+
+ /**
+ * Removes a specific file.
+ *
+ * @method removeFile
+ * @param {plupload.File|String} file File to remove from queue.
+ */
+ removeFile : function(file) {
+ var id = typeof(file) === 'string' ? file : file.id;
+
+ for (var i = files.length - 1; i >= 0; i--) {
+ if (files[i].id === id) {
+ return this.splice(i, 1)[0];
+ }
+ }
+ },
+
+ /**
+ * Removes part of the queue and returns the files removed. This will also trigger the FilesRemoved and QueueChanged events.
+ *
+ * @method splice
+ * @param {Number} start (Optional) Start index to remove from.
+ * @param {Number} length (Optional) Lengh of items to remove.
+ * @return {Array} Array of files that was removed.
+ */
+ splice : function(start, length) {
+ // Splice and trigger events
+ var removed = files.splice(start === undef ? 0 : start, length === undef ? files.length : length);
+
+ // if upload is in progress we need to stop it and restart after files are removed
+ var restartRequired = false;
+ if (this.state == plupload.STARTED) { // upload in progress
+ plupload.each(removed, function(file) {
+ if (file.status === plupload.UPLOADING) {
+ restartRequired = true; // do not restart, unless file that is being removed is uploading
+ return false;
+ }
+ });
+
+ if (restartRequired) {
+ this.stop();
+ }
+ }
+
+ this.trigger("FilesRemoved", removed);
+
+ // Dispose any resources allocated by those files
+ plupload.each(removed, function(file) {
+ file.destroy();
+ });
+
+ if (restartRequired) {
+ this.start();
+ }
+
+ return removed;
+ },
+
+ /**
+ Dispatches the specified event name and its arguments to all listeners.
+
+ @method trigger
+ @param {String} name Event name to fire.
+ @param {Object..} Multiple arguments to pass along to the listener functions.
+ */
+
+ // override the parent method to match Plupload-like event logic
+ dispatchEvent: function(type) {
+ var list, args, result;
+
+ type = type.toLowerCase();
+
+ list = this.hasEventListener(type);
+
+ if (list) {
+ // sort event list by prority
+ list.sort(function(a, b) { return b.priority - a.priority; });
+
+ // first argument should be current plupload.Uploader instance
+ args = [].slice.call(arguments);
+ args.shift();
+ args.unshift(this);
+
+ for (var i = 0; i < list.length; i++) {
+ // Fire event, break chain if false is returned
+ if (list[i].fn.apply(list[i].scope, args) === false) {
+ return false;
+ }
+ }
+ }
+ return true;
+ },
+
+ /**
+ Check whether uploader has any listeners to the specified event.
+
+ @method hasEventListener
+ @param {String} name Event name to check for.
+ */
+
+
+ /**
+ Adds an event listener by name.
+
+ @method bind
+ @param {String} name Event name to listen for.
+ @param {function} fn Function to call ones the event gets fired.
+ @param {Object} [scope] Optional scope to execute the specified function in.
+ @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
+ */
+ bind: function(name, fn, scope, priority) {
+ // adapt moxie EventTarget style to Plupload-like
+ plupload.Uploader.prototype.bind.call(this, name, fn, priority, scope);
+ },
+
+ /**
+ Removes the specified event listener.
+
+ @method unbind
+ @param {String} name Name of event to remove.
+ @param {function} fn Function to remove from listener.
+ */
+
+ /**
+ Removes all event listeners.
+
+ @method unbindAll
+ */
+
+
+ /**
+ * Destroys Plupload instance and cleans after itself.
+ *
+ * @method destroy
+ */
+ destroy : function() {
+ this.trigger('Destroy');
+ settings = total = null; // purge these exclusively
+ this.unbindAll();
+ }
+ });
+};
+
+plupload.Uploader.prototype = o.EventTarget.instance;
+
+/**
+ * Constructs a new file instance.
+ *
+ * @class File
+ * @constructor
+ *
+ * @param {Object} file Object containing file properties
+ * @param {String} file.name Name of the file.
+ * @param {Number} file.size File size.
+ */
+plupload.File = (function() {
+ var filepool = {};
+
+ function PluploadFile(file) {
+
+ plupload.extend(this, {
+
+ /**
+ * File id this is a globally unique id for the specific file.
+ *
+ * @property id
+ * @type String
+ */
+ id: plupload.guid(),
+
+ /**
+ * File name for example "myfile.gif".
+ *
+ * @property name
+ * @type String
+ */
+ name: file.name || file.fileName,
+
+ /**
+ * File type, `e.g image/jpeg`
+ *
+ * @property type
+ * @type String
+ */
+ type: file.type || '',
+
+ /**
+ * File size in bytes (may change after client-side manupilation).
+ *
+ * @property size
+ * @type Number
+ */
+ size: file.size || file.fileSize,
+
+ /**
+ * Original file size in bytes.
+ *
+ * @property origSize
+ * @type Number
+ */
+ origSize: file.size || file.fileSize,
+
+ /**
+ * Number of bytes uploaded of the files total size.
+ *
+ * @property loaded
+ * @type Number
+ */
+ loaded: 0,
+
+ /**
+ * Number of percentage uploaded of the file.
+ *
+ * @property percent
+ * @type Number
+ */
+ percent: 0,
+
+ /**
+ * Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
+ *
+ * @property status
+ * @type Number
+ * @see plupload
+ */
+ status: plupload.QUEUED,
+
+ /**
+ * Date of last modification.
+ *
+ * @property lastModifiedDate
+ * @type {String}
+ */
+ lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString(), // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
+
+ /**
+ * Returns native window.File object, when it's available.
+ *
+ * @method getNative
+ * @return {window.File} or null, if plupload.File is of different origin
+ */
+ getNative: function() {
+ var file = this.getSource().getSource();
+ return o.inArray(o.typeOf(file), ['blob', 'file']) !== -1 ? file : null;
+ },
+
+ /**
+ * Returns mOxie.File - unified wrapper object that can be used across runtimes.
+ *
+ * @method getSource
+ * @return {mOxie.File} or null
+ */
+ getSource: function() {
+ if (!filepool[this.id]) {
+ return null;
+ }
+ return filepool[this.id];
+ },
+
+ /**
+ * Destroys plupload.File object.
+ *
+ * @method destroy
+ */
+ destroy: function() {
+ var src = this.getSource();
+ if (src) {
+ src.destroy();
+ delete filepool[this.id];
+ }
+ }
+ });
+
+ filepool[this.id] = file;
+ }
+
+ return PluploadFile;
+}());
+
+
+/**
+ * Constructs a queue progress.
+ *
+ * @class QueueProgress
+ * @constructor
+ */
+ plupload.QueueProgress = function() {
+ var self = this; // Setup alias for self to reduce code size when it's compressed
+
+ /**
+ * Total queue file size.
+ *
+ * @property size
+ * @type Number
+ */
+ self.size = 0;
+
+ /**
+ * Total bytes uploaded.
+ *
+ * @property loaded
+ * @type Number
+ */
+ self.loaded = 0;
+
+ /**
+ * Number of files uploaded.
+ *
+ * @property uploaded
+ * @type Number
+ */
+ self.uploaded = 0;
+
+ /**
+ * Number of files failed to upload.
+ *
+ * @property failed
+ * @type Number
+ */
+ self.failed = 0;
+
+ /**
+ * Number of files yet to be uploaded.
+ *
+ * @property queued
+ * @type Number
+ */
+ self.queued = 0;
+
+ /**
+ * Total percent of the uploaded bytes.
+ *
+ * @property percent
+ * @type Number
+ */
+ self.percent = 0;
+
+ /**
+ * Bytes uploaded per second.
+ *
+ * @property bytesPerSec
+ * @type Number
+ */
+ self.bytesPerSec = 0;
+
+ /**
+ * Resets the progress to its initial values.
+ *
+ * @method reset
+ */
+ self.reset = function() {
+ self.size = self.loaded = self.uploaded = self.failed = self.queued = self.percent = self.bytesPerSec = 0;
+ };
+};
+
+window.plupload = plupload;
+
+}(window, mOxie));
diff --git a/qiniu_fields/static/qiniu_fields/plupload/plupload.full.min.js b/qiniu_fields/static/qiniu_fields/plupload/plupload.full.min.js
new file mode 100644
index 0000000..2af434d
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/plupload/plupload.full.min.js
@@ -0,0 +1,29 @@
+/**
+ * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
+ * v1.3.4
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ *
+ * Date: 2015-07-18
+ */
+!function(e,t){"use strict";function n(e,t){for(var n,i=[],r=0;r0&&n(o,function(n,o){n!==r&&(e(i[o])===e(n)&&~a(e(n),["array","object"])?t(i[o],n):i[o]=n)})}),i},n=function(t,n){var i,r,o,a;if(t)if("number"===e(t.length)){for(o=0,i=t.length;i>o;o++)if(n(t[o],o)===!1)return}else if("object"===e(t))for(r in t)if(t.hasOwnProperty(r)&&n(t[r],r)===!1)return},i=function(t){var n;if(!t||"object"!==e(t))return!0;for(n in t)return!1;return!0},r=function(t,n){function i(r){"function"===e(t[r])&&t[r](function(e){++rn;n++)if(t[n]===e)return n}return-1},s=function(t,n){var i=[];"array"!==e(t)&&(t=[t]),"array"!==e(n)&&(n=[n]);for(var r in t)-1===a(t[r],n)&&i.push(t[r]);return i.length?i:!1},u=function(e,t){var i=[];return n(e,function(e){-1!==a(e,t)&&i.push(e)}),i.length?i:null},c=function(e){var t,n=[];for(t=0;ti;i++)n+=Math.floor(65535*Math.random()).toString(32);return(t||"o_")+n+(e++).toString(32)}}(),d=function(e){return e?String.prototype.trim?String.prototype.trim.call(e):e.toString().replace(/^\s*/,"").replace(/\s*$/,""):e},h=function(e){if("string"!=typeof e)return e;var t={t:1099511627776,g:1073741824,m:1048576,k:1024},n;return e=/^([0-9\.]+)([tmgk]?)$/.exec(e.toLowerCase().replace(/[^0-9\.tmkg]/g,"")),n=e[2],e=+e[1],t.hasOwnProperty(n)&&(e*=t[n]),Math.floor(e)},f=function(t){var n=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=n.shift();return"undefined"!==e(t)?t:""})};return{guid:l,typeOf:e,extend:t,each:n,isEmptyObj:i,inSeries:r,inParallel:o,inArray:a,arrayDiff:s,arrayIntersect:u,toArray:c,trim:d,sprintf:f,parseSizeStr:h}}),i(c,[u],function(e){function t(e,t,n){var i=0,r=0,o=0,a={dev:-6,alpha:-5,a:-5,beta:-4,b:-4,RC:-3,rc:-3,"#":-2,p:1,pl:1},s=function(e){return e=(""+e).replace(/[_\-+]/g,"."),e=e.replace(/([^.\d]+)/g,".$1.").replace(/\.{2,}/g,"."),e.length?e.split("."):[-8]},u=function(e){return e?isNaN(e)?a[e]||-7:parseInt(e,10):0};for(e=s(e),t=s(t),r=Math.max(e.length,t.length),i=0;r>i;i++)if(e[i]!=t[i]){if(e[i]=u(e[i]),t[i]=u(t[i]),e[i]t[i]){o=1;break}}if(!n)return o;switch(n){case">":case"gt":return o>0;case">=":case"ge":return o>=0;case"<=":case"le":return 0>=o;case"==":case"=":case"eq":return 0===o;case"<>":case"!=":case"ne":return 0!==o;case"":case"<":case"lt":return 0>o;default:return null}}var n=function(e){var t="",n="?",i="function",r="undefined",o="object",a="major",s="model",u="name",c="type",l="vendor",d="version",h="architecture",f="console",p="mobile",m="tablet",g={has:function(e,t){return-1!==t.toLowerCase().indexOf(e.toLowerCase())},lowerize:function(e){return e.toLowerCase()}},v={rgx:function(){for(var t,n=0,a,s,u,c,l,d,h=arguments;n0?2==c.length?typeof c[1]==i?t[c[0]]=c[1].call(this,d):t[c[0]]=c[1]:3==c.length?typeof c[1]!==i||c[1].exec&&c[1].test?t[c[0]]=d?d.replace(c[1],c[2]):e:t[c[0]]=d?c[1].call(this,d,c[2]):e:4==c.length&&(t[c[0]]=d?c[3].call(this,d.replace(c[1],c[2])):e):t[c]=d?d:e;break}if(l)break}return t},str:function(t,i){for(var r in i)if(typeof i[r]===o&&i[r].length>0){for(var a=0;a=9)},use_data_uri_of:function(e){return t.use_data_uri&&33e3>e||t.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!1;var e=document.createElement("input");return e.setAttribute("type","file"),!e.disabled}};return function(n){var i=[].slice.call(arguments);return i.shift(),"function"===e.typeOf(t[n])?t[n].apply(this,i):!!t[n]}}(),r=(new n).getResult(),o={can:i,uaParser:n,browser:r.browser.name,version:r.browser.version,os:r.os.name,osVersion:r.os.version,verComp:t,swf_url:"../flash/Moxie.swf",xap_url:"../silverlight/Moxie.xap",global_event_dispatcher:"moxie.core.EventTarget.instance.dispatchEvent"};return o.OS=o.os,o}),i(l,[u],function(e){var t={};return{addI18n:function(n){return e.extend(t,n)},translate:function(e){return t[e]||e},_:function(e){return this.translate(e)},sprintf:function(t){var n=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=n.shift();return"undefined"!==e.typeOf(t)?t:""})}}}),i(d,[u,l],function(e,t){var n="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,application/vnd.ms-powerpoint,ppt pps pot,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",i={mimes:{},extensions:{},addMimeType:function(e){var t=e.split(/,/),n,i,r;for(n=0;n=0;o--)if(r[o].fn===i){r.splice(o,1);break}}else r=[];r.length||(delete e[this.uid][t],n.isEmptyObj(e[this.uid])&&delete e[this.uid])}},removeAllEventListeners:function(){e[this.uid]&&delete e[this.uid]},dispatchEvent:function(i){var r,o,a,s,u={},c=!0,l;if("string"!==n.typeOf(i)){if(s=i,"string"!==n.typeOf(s.type))throw new t.EventException(t.EventException.UNSPECIFIED_EVENT_TYPE_ERR);i=s.type,s.total!==l&&s.loaded!==l&&(u.total=s.total,u.loaded=s.loaded),u.async=s.async||!1}if(-1!==i.indexOf("::")?!function(e){r=e[0],i=e[1]}(i.split("::")):r=this.uid,i=i.toLowerCase(),o=e[r]&&e[r][i]){o.sort(function(e,t){return t.priority-e.priority}),a=[].slice.call(arguments),a.shift(),u.type=i,a.unshift(u);var d=[];n.each(o,function(e){a[0].target=e.scope,d.push(u.async?function(t){setTimeout(function(){t(e.fn.apply(e.scope,a)===!1)},1)}:function(t){t(e.fn.apply(e.scope,a)===!1)})}),d.length&&n.inSeries(d,function(e){c=!e})}return c},bind:function(){this.addEventListener.apply(this,arguments)},unbind:function(){this.removeEventListener.apply(this,arguments)},unbindAll:function(){this.removeAllEventListeners.apply(this,arguments)},trigger:function(){return this.dispatchEvent.apply(this,arguments)},handleEventProps:function(e){var t=this;this.bind(e.join(" "),function(e){var t="on"+e.type.toLowerCase();"function"===n.typeOf(this[t])&&this[t].apply(this,arguments)}),n.each(e,function(e){e="on"+e.toLowerCase(e),"undefined"===n.typeOf(t[e])&&(t[e]=null)})}})}return i.instance=new i,i}),i(m,[c,u,h,p],function(e,t,n,i){function r(e,i,o,s,u){var c=this,l,d=t.guid(i+"_"),h=u||"browser";e=e||{},a[d]=this,o=t.extend({access_binary:!1,access_image_binary:!1,display_media:!1,do_cors:!1,drag_and_drop:!1,filter_by_extension:!0,resize_image:!1,report_upload_progress:!1,return_response_headers:!1,return_response_type:!1,return_status_code:!0,send_custom_headers:!1,select_file:!1,select_folder:!1,select_multiple:!0,send_binary_string:!1,send_browser_cookies:!0,send_multipart:!0,slice_blob:!1,stream_upload:!1,summon_file_dialog:!1,upload_filesize:!0,use_http_method:!0},o),e.preferred_caps&&(h=r.getMode(s,e.preferred_caps,h)),l=function(){var e={};return{exec:function(t,n,i,r){return l[n]&&(e[t]||(e[t]={context:this,instance:new l[n]}),e[t].instance[i])?e[t].instance[i].apply(this,r):void 0},removeInstance:function(t){delete e[t]},removeAllInstances:function(){var n=this;t.each(e,function(e,i){"function"===t.typeOf(e.instance.destroy)&&e.instance.destroy.call(e.context),n.removeInstance(i)})}}}(),t.extend(this,{initialized:!1,uid:d,type:i,mode:r.getMode(s,e.required_caps,h),shimid:d+"_container",clients:0,options:e,can:function(e,n){var i=arguments[2]||o;if("string"===t.typeOf(e)&&"undefined"===t.typeOf(n)&&(e=r.parseCaps(e)),"object"===t.typeOf(e)){for(var a in e)if(!this.can(a,e[a],i))return!1;return!0}return"function"===t.typeOf(i[e])?i[e].call(this,n):n===i[e]},getShimContainer:function(){var e,i=n.get(this.shimid);return i||(e=this.options.container?n.get(this.options.container):document.body,i=document.createElement("div"),i.id=this.shimid,i.className="moxie-shim moxie-shim-"+this.type,t.extend(i.style,{position:"absolute",top:"0px",left:"0px",width:"1px",height:"1px",overflow:"hidden"}),e.appendChild(i),e=null),i},getShim:function(){return l},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec.call(this,this.uid,e,t,n)},exec:function(e,t){var n=[].slice.call(arguments,2);return c[e]&&c[e][t]?c[e][t].apply(this,n):c.shimExec.apply(this,arguments)},destroy:function(){if(c){var e=n.get(this.shimid);e&&e.parentNode.removeChild(e),l&&l.removeAllInstances(),this.unbindAll(),delete a[this.uid],this.uid=null,d=c=l=e=null}}}),this.mode&&e.required_caps&&!this.can(e.required_caps)&&(this.mode=!1)}var o={},a={};return r.order="html5,flash,silverlight,html4",r.getRuntime=function(e){return a[e]?a[e]:!1},r.addConstructor=function(e,t){t.prototype=i.instance,o[e]=t},r.getConstructor=function(e){return o[e]||null},r.getInfo=function(e){var t=r.getRuntime(e);return t?{uid:t.uid,type:t.type,mode:t.mode,can:function(){return t.can.apply(t,arguments)}}:null},r.parseCaps=function(e){var n={};return"string"!==t.typeOf(e)?e||{}:(t.each(e.split(","),function(e){n[e]=!0}),n)},r.can=function(e,t){var n,i=r.getConstructor(e),o;return i?(n=new i({required_caps:t}),o=n.mode,n.destroy(),!!o):!1},r.thatCan=function(e,t){var n=(t||r.order).split(/\s*,\s*/);for(var i in n)if(r.can(n[i],e))return n[i];return null},r.getMode=function(e,n,i){var r=null;if("undefined"===t.typeOf(i)&&(i="browser"),n&&!t.isEmptyObj(e)){if(t.each(n,function(n,i){if(e.hasOwnProperty(i)){var o=e[i](n);if("string"==typeof o&&(o=[o]),r){if(!(r=t.arrayIntersect(r,o)))return r=!1}else r=o}}),r)return-1!==t.inArray(i,r)?i:r[0];if(r===!1)return!1}return i},r.capTrue=function(){return!0},r.capFalse=function(){return!1},r.capTest=function(e){return function(){return!!e}},r}),i(g,[c,f,u,m],function(e,t,n,i){return function r(){var e;n.extend(this,{connectRuntime:function(r){function o(n){var s,u;return n.length?(s=n.shift().toLowerCase(),(u=i.getConstructor(s))?(e=new u(r),e.bind("Init",function(){e.initialized=!0,setTimeout(function(){e.clients++,a.trigger("RuntimeInit",e)},1)}),e.bind("Error",function(){e.destroy(),o(n)}),e.mode?void e.init():void e.trigger("Error")):void o(n)):(a.trigger("RuntimeError",new t.RuntimeError(t.RuntimeError.NOT_INIT_ERR)),void(e=null))}var a=this,s;if("string"===n.typeOf(r)?s=r:"string"===n.typeOf(r.ruid)&&(s=r.ruid),s){if(e=i.getRuntime(s))return e.clients++,e;throw new t.RuntimeError(t.RuntimeError.NOT_INIT_ERR)}o((r.runtime_order||i.order).split(/\s*,\s*/))},disconnectRuntime:function(){e&&--e.clients<=0&&e.destroy(),e=null},getRuntime:function(){return e&&e.uid?e:e=null},exec:function(){return e?e.exec.apply(this,arguments):null}})}}),i(v,[u,c,d,h,f,p,l,m,g],function(e,t,n,i,r,o,a,s,u){function c(t){var o=this,c,d,h;if(-1!==e.inArray(e.typeOf(t),["string","node"])&&(t={browse_button:t}),d=i.get(t.browse_button),!d)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR);h={accept:[{title:a.translate("All Files"),extensions:"*"}],name:"file",multiple:!1,required_caps:!1,container:d.parentNode||document.body},t=e.extend({},h,t),"string"==typeof t.required_caps&&(t.required_caps=s.parseCaps(t.required_caps)),"string"==typeof t.accept&&(t.accept=n.mimes2extList(t.accept)),c=i.get(t.container),c||(c=document.body),"static"===i.getStyle(c,"position")&&(c.style.position="relative"),c=d=null,u.call(o),e.extend(o,{uid:e.guid("uid_"),ruid:null,shimid:null,files:null,init:function(){o.bind("RuntimeInit",function(n,r){o.ruid=r.uid,o.shimid=r.shimid,o.bind("Ready",function(){o.trigger("Refresh")},999),o.bind("Refresh",function(){var n,o,a,s;a=i.get(t.browse_button),s=i.get(r.shimid),a&&(n=i.getPos(a,i.get(t.container)),o=i.getSize(a),s&&e.extend(s.style,{top:n.y+"px",left:n.x+"px",width:o.w+"px",height:o.h+"px"})),s=a=null}),r.exec.call(o,"FileInput","init",t)}),o.connectRuntime(e.extend({},t,{required_caps:{select_file:!0}}))},disable:function(t){var n=this.getRuntime();n&&n.exec.call(this,"FileInput","disable","undefined"===e.typeOf(t)?!0:t)},refresh:function(){o.trigger("Refresh")},destroy:function(){var t=this.getRuntime();t&&(t.exec.call(this,"FileInput","destroy"),this.disconnectRuntime()),"array"===e.typeOf(this.files)&&e.each(this.files,function(e){e.destroy()}),this.files=null,this.unbindAll()}}),this.handleEventProps(l)}var l=["ready","change","cancel","mouseenter","mouseleave","mousedown","mouseup"];return c.prototype=o.instance,c}),i(w,[],function(){var e=function(e){return unescape(encodeURIComponent(e))},t=function(e){return decodeURIComponent(escape(e))},n=function(e,n){if("function"==typeof window.atob)return n?t(window.atob(e)):window.atob(e);var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",r,o,a,s,u,c,l,d,h=0,f=0,p="",m=[];if(!e)return e;e+="";do s=i.indexOf(e.charAt(h++)),u=i.indexOf(e.charAt(h++)),c=i.indexOf(e.charAt(h++)),l=i.indexOf(e.charAt(h++)),d=s<<18|u<<12|c<<6|l,r=d>>16&255,o=d>>8&255,a=255&d,64==c?m[f++]=String.fromCharCode(r):64==l?m[f++]=String.fromCharCode(r,o):m[f++]=String.fromCharCode(r,o,a);while(h>18&63,u=d>>12&63,c=d>>6&63,l=63&d,m[f++]=i.charAt(s)+i.charAt(u)+i.charAt(c)+i.charAt(l);while(ha;a++)o+=String.fromCharCode(r[a]);return o}}t.call(this),e.extend(this,{uid:e.guid("uid_"),readAsBinaryString:function(e){return i.call(this,"readAsBinaryString",e)},readAsDataURL:function(e){return i.call(this,"readAsDataURL",e)},readAsText:function(e){return i.call(this,"readAsText",e)}})}}),i(I,[f,u,y],function(e,t,n){function i(){var e,i=[];t.extend(this,{append:function(r,o){var a=this,s=t.typeOf(o);o instanceof n?e={name:r,value:o}:"array"===s?(r+="[]",t.each(o,function(e){a.append(r,e)})):"object"===s?t.each(o,function(e,t){a.append(r+"["+t+"]",e)}):"null"===s||"undefined"===s||"number"===s&&isNaN(o)?a.append(r,"false"):i.push({name:r,value:o.toString()})},hasBlob:function(){return!!this.getBlob()},getBlob:function(){return e&&e.value||null},getBlobName:function(){return e&&e.name||null},each:function(n){t.each(i,function(e){n(e.value,e.name)}),e&&n(e.value,e.name)},destroy:function(){e=null,i=[]}})}return i}),i(T,[u,f,p,w,x,m,R,y,A,I,c,d],function(e,t,n,i,r,o,a,s,u,c,l,d){function h(){this.uid=e.guid("uid_")}function f(){function n(e,t){return w.hasOwnProperty(e)?1===arguments.length?l.can("define_property")?w[e]:v[e]:void(l.can("define_property")?w[e]=t:v[e]=t):void 0}function u(t){function i(){B&&(B.destroy(),B=null),s.dispatchEvent("loadend"),s=null}function r(r){B.bind("LoadStart",function(e){n("readyState",f.LOADING),s.dispatchEvent("readystatechange"),s.dispatchEvent(e),O&&s.upload.dispatchEvent(e)}),B.bind("Progress",function(e){n("readyState")!==f.LOADING&&(n("readyState",f.LOADING),s.dispatchEvent("readystatechange")),s.dispatchEvent(e)}),B.bind("UploadProgress",function(e){O&&s.upload.dispatchEvent({type:"progress",lengthComputable:!1,total:e.total,loaded:e.loaded})}),B.bind("Load",function(t){n("readyState",f.DONE),n("status",Number(r.exec.call(B,"XMLHttpRequest","getStatus")||0)),n("statusText",p[n("status")]||""),n("response",r.exec.call(B,"XMLHttpRequest","getResponse",n("responseType"))),~e.inArray(n("responseType"),["text",""])?n("responseText",n("response")):"document"===n("responseType")&&n("responseXML",n("response")),k=r.exec.call(B,"XMLHttpRequest","getAllResponseHeaders"),s.dispatchEvent("readystatechange"),n("status")>0?(O&&s.upload.dispatchEvent(t),s.dispatchEvent(t)):(N=!0,s.dispatchEvent("error")),i()}),B.bind("Abort",function(e){s.dispatchEvent(e),i()}),B.bind("Error",function(e){N=!0,n("readyState",f.DONE),s.dispatchEvent("readystatechange"),D=!0,s.dispatchEvent(e),i()}),r.exec.call(B,"XMLHttpRequest","send",{url:E,method:_,async:y,user:x,password:R,headers:b,mimeType:I,encoding:A,responseType:s.responseType,withCredentials:s.withCredentials,options:H},t)}var s=this;C=(new Date).getTime(),B=new a,"string"==typeof H.required_caps&&(H.required_caps=o.parseCaps(H.required_caps)),H.required_caps=e.extend({},H.required_caps,{return_response_type:s.responseType}),t instanceof c&&(H.required_caps.send_multipart=!0),e.isEmptyObj(b)||(H.required_caps.send_custom_headers=!0),L||(H.required_caps.do_cors=!0),H.ruid?r(B.connectRuntime(H)):(B.bind("RuntimeInit",function(e,t){r(t)}),B.bind("RuntimeError",function(e,t){s.dispatchEvent("RuntimeError",t)}),B.connectRuntime(H))}function g(){n("responseText",""),n("responseXML",null),n("response",null),n("status",0),n("statusText",""),C=M=null}var v=this,w={timeout:0,readyState:f.UNSENT,withCredentials:!1,status:0,statusText:"",responseType:"",responseXML:null,responseText:null,response:null},y=!0,E,_,b={},x,R,A=null,I=null,T=!1,S=!1,O=!1,D=!1,N=!1,L=!1,C,M,F=null,P=null,H={},B,k="",U;e.extend(this,w,{uid:e.guid("uid_"),upload:new h,open:function(o,a,s,u,c){var l;if(!o||!a)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(/[\u0100-\uffff]/.test(o)||i.utf8_encode(o)!==o)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(~e.inArray(o.toUpperCase(),["CONNECT","DELETE","GET","HEAD","OPTIONS","POST","PUT","TRACE","TRACK"])&&(_=o.toUpperCase()),~e.inArray(_,["CONNECT","TRACE","TRACK"]))throw new t.DOMException(t.DOMException.SECURITY_ERR);if(a=i.utf8_encode(a),l=r.parseUrl(a),L=r.hasSameOrigin(l),E=r.resolveUrl(a),(u||c)&&!L)throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);if(x=u||l.user,R=c||l.pass,y=s||!0,y===!1&&(n("timeout")||n("withCredentials")||""!==n("responseType")))throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);T=!y,S=!1,b={},g.call(this),n("readyState",f.OPENED),this.dispatchEvent("readystatechange")},setRequestHeader:function(r,o){var a=["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"];if(n("readyState")!==f.OPENED||S)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(/[\u0100-\uffff]/.test(r)||i.utf8_encode(r)!==r)throw new t.DOMException(t.DOMException.SYNTAX_ERR);return r=e.trim(r).toLowerCase(),~e.inArray(r,a)||/^(proxy\-|sec\-)/.test(r)?!1:(b[r]?b[r]+=", "+o:b[r]=o,!0)},getAllResponseHeaders:function(){return k||""},getResponseHeader:function(t){return t=t.toLowerCase(),N||~e.inArray(t,["set-cookie","set-cookie2"])?null:k&&""!==k&&(U||(U={},e.each(k.split(/\r\n/),function(t){var n=t.split(/:\s+/);2===n.length&&(n[0]=e.trim(n[0]),U[n[0].toLowerCase()]={header:n[0],value:e.trim(n[1])})})),U.hasOwnProperty(t))?U[t].header+": "+U[t].value:null},overrideMimeType:function(i){var r,o;if(~e.inArray(n("readyState"),[f.LOADING,f.DONE]))throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(i=e.trim(i.toLowerCase()),/;/.test(i)&&(r=i.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))&&(i=r[1],r[2]&&(o=r[2])),!d.mimes[i])throw new t.DOMException(t.DOMException.SYNTAX_ERR);F=i,P=o},send:function(n,r){if(H="string"===e.typeOf(r)?{ruid:r}:r?r:{},this.readyState!==f.OPENED||S)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(n instanceof s)H.ruid=n.ruid,I=n.type||"application/octet-stream";else if(n instanceof c){if(n.hasBlob()){var o=n.getBlob();H.ruid=o.ruid,I=o.type||"application/octet-stream"}}else"string"==typeof n&&(A="UTF-8",I="text/plain;charset=UTF-8",n=i.utf8_encode(n));this.withCredentials||(this.withCredentials=H.required_caps&&H.required_caps.send_browser_cookies&&!L),O=!T&&this.upload.hasEventListener(),N=!1,D=!n,T||(S=!0),u.call(this,n)},abort:function(){if(N=!0,T=!1,~e.inArray(n("readyState"),[f.UNSENT,f.OPENED,f.DONE]))n("readyState",f.UNSENT);else{if(n("readyState",f.DONE),S=!1,!B)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);B.getRuntime().exec.call(B,"XMLHttpRequest","abort",D),D=!0}},destroy:function(){B&&("function"===e.typeOf(B.destroy)&&B.destroy(),B=null),this.unbindAll(),this.upload&&(this.upload.unbindAll(),this.upload=null)}}),this.handleEventProps(m.concat(["readystatechange"])),this.upload.handleEventProps(m)}var p={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"};h.prototype=n.instance;var m=["loadstart","progress","abort","error","load","timeout","loadend"],g=1,v=2;return f.UNSENT=0,f.OPENED=1,f.HEADERS_RECEIVED=2,f.LOADING=3,f.DONE=4,f.prototype=n.instance,f}),i(S,[u,w,g,p],function(e,t,n,i){function r(){function i(){l=d=0,c=this.result=null}function o(t,n){var i=this;u=n,i.bind("TransportingProgress",function(t){d=t.loaded,l>d&&-1===e.inArray(i.state,[r.IDLE,r.DONE])&&a.call(i)},999),i.bind("TransportingComplete",function(){d=l,i.state=r.DONE,c=null,i.result=u.exec.call(i,"Transporter","getAsBlob",t||"")},999),i.state=r.BUSY,i.trigger("TransportingStarted"),a.call(i)}function a(){var e=this,n,i=l-d;h>i&&(h=i),n=t.btoa(c.substr(d,h)),u.exec.call(e,"Transporter","receive",n,l)}var s,u,c,l,d,h;n.call(this),e.extend(this,{uid:e.guid("uid_"),state:r.IDLE,result:null,transport:function(t,n,r){var a=this;if(r=e.extend({chunk_size:204798},r),(s=r.chunk_size%3)&&(r.chunk_size+=3-s),h=r.chunk_size,i.call(this),c=t,l=t.length,"string"===e.typeOf(r)||r.ruid)o.call(a,n,this.connectRuntime(r));else{var u=function(e,t){a.unbind("RuntimeInit",u),o.call(a,n,t)};this.bind("RuntimeInit",u),this.connectRuntime(r)}},abort:function(){var e=this;e.state=r.IDLE,u&&(u.exec.call(e,"Transporter","clear"),e.trigger("TransportingAborted")),i.call(e)},destroy:function(){this.unbindAll(),u=null,this.disconnectRuntime(),i.call(this)}})}return r.IDLE=0,r.BUSY=1,r.DONE=2,r.prototype=i.instance,r}),i(O,[u,h,f,A,T,m,g,S,c,p,y,E,w],function(e,t,n,i,r,o,a,s,u,c,l,d,h){function f(){function i(e){e||(e=this.exec("Image","getInfo")),this.size=e.size,this.width=e.width,this.height=e.height,this.type=e.type,this.meta=e.meta,""===this.name&&(this.name=e.name)}function c(t){var i=e.typeOf(t);try{if(t instanceof f){if(!t.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);m.apply(this,arguments)}else if(t instanceof l){if(!~e.inArray(t.type,["image/jpeg","image/png"]))throw new n.ImageError(n.ImageError.WRONG_FORMAT);g.apply(this,arguments)}else if(-1!==e.inArray(i,["blob","file"]))c.call(this,new d(null,t),arguments[1]);else if("string"===i)"data:"===t.substr(0,5)?c.call(this,new l(null,{data:t}),arguments[1]):v.apply(this,arguments);else{if("node"!==i||"img"!==t.nodeName.toLowerCase())throw new n.DOMException(n.DOMException.TYPE_MISMATCH_ERR);c.call(this,t.src,arguments[1])}}catch(r){this.trigger("error",r.code)}}function m(t,n){var i=this.connectRuntime(t.ruid);this.ruid=i.uid,i.exec.call(this,"Image","loadFromImage",t,"undefined"===e.typeOf(n)?!0:n)}function g(t,n){function i(e){r.ruid=e.uid,e.exec.call(r,"Image","loadFromBlob",t)}var r=this;r.name=t.name||"",t.isDetached()?(this.bind("RuntimeInit",function(e,t){i(t)}),n&&"string"==typeof n.required_caps&&(n.required_caps=o.parseCaps(n.required_caps)),this.connectRuntime(e.extend({required_caps:{access_image_binary:!0,resize_image:!0}},n))):i(this.connectRuntime(t.ruid))}function v(e,t){var n=this,i;i=new r,i.open("get",e),i.responseType="blob",i.onprogress=function(e){n.trigger(e)},i.onload=function(){g.call(n,i.response,!0)},i.onerror=function(e){n.trigger(e)},i.onloadend=function(){i.destroy()},i.bind("RuntimeError",function(e,t){n.trigger("RuntimeError",t)}),i.send(null,t)}a.call(this),e.extend(this,{uid:e.guid("uid_"),ruid:null,name:"",size:0,width:0,height:0,type:"",meta:{},clone:function(){this.load.apply(this,arguments)},load:function(){c.apply(this,arguments)},downsize:function(t){var i={width:this.width,height:this.height,type:this.type||"image/jpeg",quality:90,crop:!1,preserveHeaders:!0,resample:!1};t="object"==typeof t?e.extend(i,t):e.extend(i,{width:arguments[0],height:arguments[1],crop:arguments[2],preserveHeaders:arguments[3]});try{if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);if(this.width>f.MAX_RESIZE_WIDTH||this.height>f.MAX_RESIZE_HEIGHT)throw new n.ImageError(n.ImageError.MAX_RESOLUTION_ERR);this.exec("Image","downsize",t.width,t.height,t.crop,t.preserveHeaders)}catch(r){this.trigger("error",r.code)}},crop:function(e,t,n){this.downsize(e,t,!0,n)},getAsCanvas:function(){if(!u.can("create_canvas"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);var e=this.connectRuntime(this.ruid);return e.exec.call(this,"Image","getAsCanvas")},getAsBlob:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return this.exec("Image","getAsBlob",e||"image/jpeg",t||90)},getAsDataURL:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return this.exec("Image","getAsDataURL",e||"image/jpeg",t||90)},getAsBinaryString:function(e,t){var n=this.getAsDataURL(e,t);return h.atob(n.substring(n.indexOf("base64,")+7))},embed:function(i,r){function o(t,r){var o=this;if(u.can("create_canvas")){var l=o.getAsCanvas();if(l)return i.appendChild(l),l=null,o.destroy(),void a.trigger("embedded")}var d=o.getAsDataURL(t,r);if(!d)throw new n.ImageError(n.ImageError.WRONG_FORMAT);if(u.can("use_data_uri_of",d.length))i.innerHTML=' ',o.destroy(),a.trigger("embedded");else{var f=new s;f.bind("TransportingComplete",function(){c=a.connectRuntime(this.result.ruid),a.bind("Embedded",function(){e.extend(c.getShimContainer().style,{top:"0px",left:"0px",width:o.width+"px",height:o.height+"px"}),c=null},999),c.exec.call(a,"ImageView","display",this.result.uid,width,height),o.destroy()}),f.transport(h.atob(d.substring(d.indexOf("base64,")+7)),t,{required_caps:{display_media:!0},runtime_order:"flash,silverlight",container:i})}}var a=this,c;r=e.extend({width:this.width,height:this.height,type:this.type||"image/jpeg",quality:90},r||{});try{if(!(i=t.get(i)))throw new n.DOMException(n.DOMException.INVALID_NODE_TYPE_ERR);if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);this.width>f.MAX_RESIZE_WIDTH||this.height>f.MAX_RESIZE_HEIGHT;var l=new f;return l.bind("Resize",function(){o.call(this,r.type,r.quality)}),l.bind("Load",function(){l.downsize(r)}),this.meta.thumb&&this.meta.thumb.width>=r.width&&this.meta.thumb.height>=r.height?l.load(this.meta.thumb.data):l.clone(this,!1),l}catch(d){this.trigger("error",d.code)}},destroy:function(){this.ruid&&(this.getRuntime().exec.call(this,"Image","destroy"),this.disconnectRuntime()),this.unbindAll()}}),this.handleEventProps(p),this.bind("Load Resize",function(){i.call(this)},999)}var p=["progress","load","error","resize","embedded"];return f.MAX_RESIZE_WIDTH=8192,f.MAX_RESIZE_HEIGHT=8192,f.prototype=c.instance,f}),i(D,[u,f,m,c],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue,c=e.extend({access_binary:s(window.FileReader||window.File&&window.File.getAsDataURL),access_image_binary:function(){return r.can("access_binary")&&!!a.Image},display_media:s(i.can("create_canvas")||i.can("use_data_uri_over32kb")),do_cors:s(window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest),drag_and_drop:s(function(){var e=document.createElement("div");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&("IE"!==i.browser||i.verComp(i.version,9,">"))}()),filter_by_extension:s(function(){return"Chrome"===i.browser&&i.verComp(i.version,28,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||"Safari"===i.browser&&i.verComp(i.version,7,">=")}()),return_response_headers:u,return_response_type:function(e){return"json"===e&&window.JSON?!0:i.can("return_response_type",e)},return_status_code:u,report_upload_progress:s(window.XMLHttpRequest&&(new XMLHttpRequest).upload),resize_image:function(){return r.can("access_binary")&&i.can("create_canvas")},select_file:function(){return i.can("use_fileinput")&&window.File},select_folder:function(){return r.can("select_file")&&"Chrome"===i.browser&&i.verComp(i.version,21,">=")},select_multiple:function(){return!(!r.can("select_file")||"Safari"===i.browser&&"Windows"===i.os||"iOS"===i.os&&i.verComp(i.osVersion,"7.0.0",">")&&i.verComp(i.osVersion,"8.0.0","<"))},send_binary_string:s(window.XMLHttpRequest&&((new XMLHttpRequest).sendAsBinary||window.Uint8Array&&window.ArrayBuffer)),send_custom_headers:s(window.XMLHttpRequest),send_multipart:function(){return!!(window.XMLHttpRequest&&(new XMLHttpRequest).upload&&window.FormData)||r.can("send_binary_string")},slice_blob:s(window.File&&(File.prototype.mozSlice||File.prototype.webkitSlice||File.prototype.slice)),stream_upload:function(){return r.can("slice_blob")&&r.can("send_multipart")},summon_file_dialog:function(){return r.can("select_file")&&("Firefox"===i.browser&&i.verComp(i.version,4,">=")||"Opera"===i.browser&&i.verComp(i.version,12,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||!!~e.inArray(i.browser,["Chrome","Safari"]))},upload_filesize:u},arguments[2]);n.call(this,t,arguments[1]||o,c),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html5",a={};return n.addConstructor(o,r),a}),i(N,[u],function(e){function t(){this.returnValue=!1}function n(){this.cancelBubble=!0}var i={},r="moxie_"+e.guid(),o=function(o,a,s,u){var c,l;a=a.toLowerCase(),o.addEventListener?(c=s,o.addEventListener(a,c,!1)):o.attachEvent&&(c=function(){var e=window.event;e.target||(e.target=e.srcElement),e.preventDefault=t,e.stopPropagation=n,s(e)},o.attachEvent("on"+a,c)),o[r]||(o[r]=e.guid()),i.hasOwnProperty(o[r])||(i[o[r]]={}),l=i[o[r]],l.hasOwnProperty(a)||(l[a]=[]),l[a].push({func:c,orig:s,key:u})},a=function(t,n,o){var a,s;if(n=n.toLowerCase(),t[r]&&i[t[r]]&&i[t[r]][n]){a=i[t[r]][n];for(var u=a.length-1;u>=0&&(a[u].orig!==o&&a[u].key!==o||(t.removeEventListener?t.removeEventListener(n,a[u].func,!1):t.detachEvent&&t.detachEvent("on"+n,a[u].func),a[u].orig=null,a[u].func=null,a.splice(u,1),o===s));u--);if(a.length||delete i[t[r]][n],e.isEmptyObj(i[t[r]])){delete i[t[r]];try{delete t[r]}catch(c){t[r]=s}}}},s=function(t,n){t&&t[r]&&e.each(i[t[r]],function(e,i){a(t,i,n)})};return{addEvent:o,removeEvent:a,removeAllEvents:s}}),i(L,[D,E,u,h,N,d,c],function(e,t,n,i,r,o,a){function s(){var e;n.extend(this,{init:function(s){var u=this,c=u.getRuntime(),l,d,h,f,p,m;e=s,h=e.accept.mimes||o.extList2mimes(e.accept,c.can("filter_by_extension")),d=c.getShimContainer(),d.innerHTML=' ",l=i.get(c.uid),n.extend(l.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),f=i.get(e.browse_button),c.can("summon_file_dialog")&&("static"===i.getStyle(f,"position")&&(f.style.position="relative"),p=parseInt(i.getStyle(f,"z-index"),10)||1,f.style.zIndex=p,d.style.zIndex=p-1,r.addEvent(f,"click",function(e){var t=i.get(c.uid);t&&!t.disabled&&t.click(),e.preventDefault()},u.uid)),m=c.can("summon_file_dialog")?f:d,r.addEvent(m,"mouseover",function(){u.trigger("mouseenter")},u.uid),r.addEvent(m,"mouseout",function(){u.trigger("mouseleave")},u.uid),r.addEvent(m,"mousedown",function(){u.trigger("mousedown")},u.uid),r.addEvent(i.get(e.container),"mouseup",function(){u.trigger("mouseup")},u.uid),l.onchange=function g(i){if(u.files=[],n.each(this.files,function(n){var i="";return e.directory&&"."==n.name?!0:(n.webkitRelativePath&&(i="/"+n.webkitRelativePath.replace(/^\//,"")),n=new t(c.uid,n),n.relativePath=i,void u.files.push(n))}),"IE"!==a.browser&&"IEMobile"!==a.browser)this.value="";else{var r=this.cloneNode(!0);this.parentNode.replaceChild(r,this),r.onchange=g}u.files.length&&u.trigger("change")},u.trigger({type:"ready",async:!0}),d=null},disable:function(e){var t=this.getRuntime(),n;(n=i.get(t.uid))&&(n.disabled=!!e)},destroy:function(){var t=this.getRuntime(),n=t.getShim(),o=t.getShimContainer();r.removeAllEvents(o,this.uid),r.removeAllEvents(e&&i.get(e.container),this.uid),r.removeAllEvents(e&&i.get(e.browse_button),this.uid),o&&(o.innerHTML=""),n.removeInstance(this.uid),e=o=n=null}})}return e.FileInput=s}),i(C,[D,y],function(e,t){function n(){function e(e,t,n){var i;if(!window.File.prototype.slice)return(i=window.File.prototype.webkitSlice||window.File.prototype.mozSlice)?i.call(e,t,n):null;try{return e.slice(),e.slice(t,n)}catch(r){return e.slice(t,n-t)}}this.slice=function(){return new t(this.getRuntime().uid,e.apply(this,arguments))}}return e.Blob=n}),i(M,[D,E,u,h,N,d],function(e,t,n,i,r,o){function a(){function e(e){if(!e.dataTransfer||!e.dataTransfer.types)return!1;var t=n.toArray(e.dataTransfer.types||[]);return-1!==n.inArray("Files",t)||-1!==n.inArray("public.file-url",t)||-1!==n.inArray("application/x-moz-file",t)}function a(e,n){if(u(e)){var i=new t(g,e);i.relativePath=n||"",f.push(i)}}function s(e){for(var t=[],i=0;i=")&&u.verComp(u.version,7,"<"),h="Android Browser"===u.browser,m=!1;if(p=n.url.replace(/^.+?\/([\w\-\.]+)$/,"$1").toLowerCase(),f=c(),f.open(n.method,n.url,n.async,n.user,n.password),r instanceof o)r.isDetached()&&(m=!0),r=r.getSource();else if(r instanceof a){if(r.hasBlob())if(r.getBlob().isDetached())r=d.call(s,r),m=!0;else if((l||h)&&"blob"===t.typeOf(r.getBlob().getSource())&&window.FileReader)return void e.call(s,n,r);if(r instanceof a){var g=new window.FormData;r.each(function(e,t){e instanceof o?g.append(t,e.getSource()):g.append(t,e)}),r=g}}f.upload?(n.withCredentials&&(f.withCredentials=!0),f.addEventListener("load",function(e){s.trigger(e)}),f.addEventListener("error",function(e){s.trigger(e)}),f.addEventListener("progress",function(e){s.trigger(e)}),f.upload.addEventListener("progress",function(e){s.trigger({type:"UploadProgress",loaded:e.loaded,total:e.total})})):f.onreadystatechange=function v(){switch(f.readyState){case 1:break;case 2:break;case 3:var e,t;try{i.hasSameOrigin(n.url)&&(e=f.getResponseHeader("Content-Length")||0),f.responseText&&(t=f.responseText.length)}catch(r){e=t=0}s.trigger({type:"progress",lengthComputable:!!e,total:parseInt(e,10),loaded:t});break;case 4:f.onreadystatechange=function(){},s.trigger(0===f.status?"error":"load")}},t.isEmptyObj(n.headers)||t.each(n.headers,function(e,t){f.setRequestHeader(t,e)}),""!==n.responseType&&"responseType"in f&&("json"!==n.responseType||u.can("return_response_type","json")?f.responseType=n.responseType:f.responseType="text"),m?f.sendAsBinary?f.sendAsBinary(r):!function(){for(var e=new Uint8Array(r.length),t=0;t0&&o.set(new Uint8Array(t.slice(0,e)),0),o.set(new Uint8Array(r),e),o.set(new Uint8Array(t.slice(e+i)),e+r.byteLength),this.clear(),t=o.buffer,n=new DataView(t);break}default:return t}},length:function(){return t?t.byteLength:0},clear:function(){n=t=null}})}function i(t){function n(e,n,i){i=3===arguments.length?i:t.length-n-1,t=t.substr(0,n)+e+t.substr(i+n)}e.extend(this,{readByteAt:function(e){return t.charCodeAt(e)},writeByteAt:function(e,t){n(String.fromCharCode(t),e,1)},SEGMENT:function(e,i,r){switch(arguments.length){case 1:return t.substr(e);case 2:return t.substr(e,i);case 3:n(null!==r?r:"",e,i);break;default:return t}},length:function(){return t?t.length:0},clear:function(){t=null}})}return e.extend(t.prototype,{littleEndian:!1,read:function(e,t){var n,i,r;if(e+t>this.length())throw new Error("You are trying to read outside the source boundaries.");for(i=this.littleEndian?0:-8*(t-1),r=0,n=0;t>r;r++)n|=this.readByteAt(e+r)<this.length())throw new Error("You are trying to write outside the source boundaries.");for(i=this.littleEndian?0:-8*(n-1),r=0;n>r;r++)this.writeByteAt(e+r,t>>Math.abs(i+8*r)&255)},BYTE:function(e){return this.read(e,1)},SHORT:function(e){return this.read(e,2)},LONG:function(e){return this.read(e,4)},SLONG:function(e){var t=this.read(e,4);return t>2147483647?t-4294967296:t},CHAR:function(e){return String.fromCharCode(this.read(e,1))},STRING:function(e,t){return this.asArray("CHAR",e,t).join("")},asArray:function(e,t,n){for(var i=[],r=0;n>r;r++)i[r]=this[e](t+r);return i}}),t}),i(B,[H,f],function(e,t){return function n(i){var r=[],o,a,s,u=0;if(o=new e(i),65496!==o.SHORT(0))throw o.clear(),new t.ImageError(t.ImageError.WRONG_FORMAT);for(a=2;a<=o.length();)if(s=o.SHORT(a),s>=65488&&65495>=s)a+=2;else{if(65498===s||65497===s)break;u=o.SHORT(a+2)+2,s>=65505&&65519>=s&&r.push({hex:s,name:"APP"+(15&s),start:a,length:u,segment:o.SEGMENT(a,u)}),a+=u}return o.clear(),{headers:r,restore:function(t){var n,i,o;for(o=new e(t),a=65504==o.SHORT(2)?4+o.SHORT(4):2,i=0,n=r.length;n>i;i++)o.SEGMENT(a,0,r[i].segment),a+=r[i].length;return t=o.SEGMENT(),o.clear(),t},strip:function(t){var i,r,o,a;for(o=new n(t),r=o.headers,o.purge(),i=new e(t),a=r.length;a--;)i.SEGMENT(r[a].start,r[a].length,"");return t=i.SEGMENT(),i.clear(),t},get:function(e){for(var t=[],n=0,i=r.length;i>n;n++)r[n].name===e.toUpperCase()&&t.push(r[n].segment);return t},
+set:function(e,t){var n=[],i,o,a;for("string"==typeof t?n.push(t):n=t,i=o=0,a=r.length;a>i&&(r[i].name===e.toUpperCase()&&(r[i].segment=n[o],r[i].length=n[o].length,o++),!(o>=n.length));i++);},purge:function(){this.headers=r=[]}}}}),i(k,[u,H,f],function(e,n,i){function r(o){function a(n,r){var o=this,a,s,u,c,h,f,p,m,g=[],v={},w={1:"BYTE",7:"UNDEFINED",2:"ASCII",3:"SHORT",4:"LONG",5:"RATIONAL",9:"SLONG",10:"SRATIONAL"},y={BYTE:1,UNDEFINED:1,ASCII:1,SHORT:2,LONG:4,RATIONAL:8,SLONG:4,SRATIONAL:8};for(a=o.SHORT(n),s=0;a>s;s++)if(g=[],p=n+2+12*s,u=r[o.SHORT(p)],u!==t){if(c=w[o.SHORT(p+=2)],h=o.LONG(p+=2),f=y[c],!f)throw new i.ImageError(i.ImageError.INVALID_META_ERR);if(p+=4,f*h>4&&(p=o.LONG(p)+d.tiffHeader),p+f*h>=this.length())throw new i.ImageError(i.ImageError.INVALID_META_ERR);"ASCII"!==c?(g=o.asArray(c,p,h),m=1==h?g[0]:g,l.hasOwnProperty(u)&&"object"!=typeof m?v[u]=l[u][m]:v[u]=m):v[u]=e.trim(o.STRING(p,h).replace(/\0$/,""))}return v}function s(e,t,n){var i,r,o,a=0;if("string"==typeof t){var s=c[e.toLowerCase()];for(var u in s)if(s[u]===t){t=u;break}}i=d[e.toLowerCase()+"IFD"],r=this.SHORT(i);for(var l=0;r>l;l++)if(o=i+12*l+2,this.SHORT(o)==t){a=o+8;break}if(!a)return!1;try{this.write(a,n,4)}catch(h){return!1}return!0}var u,c,l,d,h,f;if(n.call(this,o),c={tiff:{274:"Orientation",270:"ImageDescription",271:"Make",272:"Model",305:"Software",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer"},exif:{36864:"ExifVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",36867:"DateTimeOriginal",33434:"ExposureTime",33437:"FNumber",34855:"ISOSpeedRatings",37377:"ShutterSpeedValue",37378:"ApertureValue",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37386:"FocalLength",41986:"ExposureMode",41987:"WhiteBalance",41990:"SceneCaptureType",41988:"DigitalZoomRatio",41992:"Contrast",41993:"Saturation",41994:"Sharpness"},gps:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude"},thumb:{513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength"}},l={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:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"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"},GPSLatitudeRef:{N:"North latitude",S:"South latitude"},GPSLongitudeRef:{E:"East longitude",W:"West longitude"}},d={tiffHeader:10},h=d.tiffHeader,u={clear:this.clear},e.extend(this,{read:function(){try{return r.prototype.read.apply(this,arguments)}catch(e){throw new i.ImageError(i.ImageError.INVALID_META_ERR)}},write:function(){try{return r.prototype.write.apply(this,arguments)}catch(e){throw new i.ImageError(i.ImageError.INVALID_META_ERR)}},UNDEFINED:function(){return this.BYTE.apply(this,arguments)},RATIONAL:function(e){return this.LONG(e)/this.LONG(e+4)},SRATIONAL:function(e){return this.SLONG(e)/this.SLONG(e+4)},ASCII:function(e){return this.CHAR(e)},TIFF:function(){return f||null},EXIF:function(){var t=null;if(d.exifIFD){try{t=a.call(this,d.exifIFD,c.exif)}catch(n){return null}if(t.ExifVersion&&"array"===e.typeOf(t.ExifVersion)){for(var i=0,r="";i=65472&&65475>=n)return t+=5,{height:e.SHORT(t),width:e.SHORT(t+=2)};i=e.SHORT(t+=2),t+=i-2}return null}function s(){var e=d.thumb(),t,n;return e&&(t=new i(e),n=a(t),t.clear(),n)?(n.data=e,n):null}function u(){d&&l&&c&&(d.clear(),l.purge(),c.clear(),h=l=d=c=null)}var c,l,d,h;if(c=new i(o),65496!==c.SHORT(0))throw new t.ImageError(t.ImageError.WRONG_FORMAT);l=new n(o);try{d=new r(l.get("app1")[0])}catch(f){}h=a.call(this),e.extend(this,{type:"image/jpeg",size:c.length(),width:h&&h.width||0,height:h&&h.height||0,setExif:function(t,n){return d?("object"===e.typeOf(t)?e.each(t,function(e,t){d.setExif(t,e)}):d.setExif(t,n),void l.set("app1",d.SEGMENT())):!1},writeHeaders:function(){return l.restore(arguments.length?arguments[0]:o)},stripHeaders:function(e){return l.strip(e)},purge:function(){u.call(this)}}),d&&(this.meta={tiff:d.TIFF(),exif:d.EXIF(),gps:d.GPS(),thumb:s()})}return o}),i(G,[f,u,H],function(e,t,n){function i(i){function r(){var e,t;return e=a.call(this,8),"IHDR"==e.type?(t=e.start,{width:s.LONG(t),height:s.LONG(t+=4)}):null}function o(){s&&(s.clear(),i=l=u=c=s=null)}function a(e){var t,n,i,r;return t=s.LONG(e),n=s.STRING(e+=4,4),i=e+=4,r=s.LONG(e+t),{length:t,type:n,start:i,CRC:r}}var s,u,c,l;s=new n(i),function(){var t=0,n=0,i=[35152,20039,3338,6666];for(n=0;ng;){for(var v=g+h>a?a-g:h,w=0;o>w;){var y=w+h>o?o-w:h;p.clearRect(0,0,h,h),p.drawImage(e,-w,-g);var E=w*s/o+c<<0,_=Math.ceil(y*s/o),b=g*u/a/m+l<<0,x=Math.ceil(v*u/a/m);d.drawImage(f,0,0,y,v,E,b,_,x),w+=h}g+=h}f=p=null}function t(e){var t=e.naturalWidth,n=e.naturalHeight;if(t*n>1048576){var i=document.createElement("canvas");i.width=i.height=1;var r=i.getContext("2d");return r.drawImage(e,-t+1,0),0===r.getImageData(0,0,1,1).data[3]}return!1}function n(e,t,n){var i=document.createElement("canvas");i.width=1,i.height=n;var r=i.getContext("2d");r.drawImage(e,0,0);for(var o=r.getImageData(0,0,1,n).data,a=0,s=n,u=n;u>a;){var c=o[4*(u-1)+3];0===c?s=u:a=u,u=s+a>>1}i=null;var l=u/n;return 0===l?1:l}return{isSubsampled:t,renderTo:e}}),i(j,[D,u,f,w,y,E,z,q,d,c],function(e,t,n,i,r,o,a,s,u,c){function l(){function e(){if(!_&&!y)throw new n.ImageError(n.DOMException.INVALID_STATE_ERR);return _||y}function l(e){return i.atob(e.substring(e.indexOf("base64,")+7))}function d(e,t){return"data:"+(t||"")+";base64,"+i.btoa(e)}function h(e){var t=this;y=new Image,y.onerror=function(){v.call(this),t.trigger("error",n.ImageError.WRONG_FORMAT)},y.onload=function(){t.trigger("load")},y.src="data:"==e.substr(0,5)?e:d(e,x.type)}function f(e,t){var i=this,r;return window.FileReader?(r=new FileReader,r.onload=function(){t(this.result)},r.onerror=function(){i.trigger("error",n.ImageError.WRONG_FORMAT)},r.readAsDataURL(e),void 0):t(e.getAsDataURL())}function p(n,i,r,o){var a=this,s,u,c=0,l=0,d,h,f,p;if(A=o,p=this.meta&&this.meta.tiff&&this.meta.tiff.Orientation||1,-1!==t.inArray(p,[5,6,7,8])){var v=n;n=i,i=v}return d=e(),r?(n=Math.min(n,d.width),i=Math.min(i,d.height),s=Math.max(n/d.width,i/d.height)):s=Math.min(n/d.width,i/d.height),s>1&&!r&&o?void this.trigger("Resize"):(_||(_=document.createElement("canvas")),h=Math.round(d.width*s),f=Math.round(d.height*s),r?(_.width=n,_.height=i,h>n&&(c=Math.round((h-n)/2)),f>i&&(l=Math.round((f-i)/2))):(_.width=h,_.height=f),A||g(_.width,_.height,p),m.call(this,d,_,-c,-l,h,f),this.width=_.width,this.height=_.height,R=!0,void a.trigger("Resize"))}function m(e,t,n,i,r,o){if("iOS"===c.OS)s.renderTo(e,t,{width:r,height:o,x:n,y:i});else{var a=t.getContext("2d");a.drawImage(e,n,i,r,o)}}function g(e,t,n){switch(n){case 5:case 6:case 7:case 8:_.width=t,_.height=e;break;default:_.width=e,_.height=t}var i=_.getContext("2d");switch(n){case 2:i.translate(e,0),i.scale(-1,1);break;case 3:i.translate(e,t),i.rotate(Math.PI);break;case 4:i.translate(0,t),i.scale(1,-1);break;case 5:i.rotate(.5*Math.PI),i.scale(1,-1);break;case 6:i.rotate(.5*Math.PI),i.translate(0,-t);break;case 7:i.rotate(.5*Math.PI),i.translate(e,-t),i.scale(-1,1);break;case 8:i.rotate(-.5*Math.PI),i.translate(-e,0)}}function v(){E&&(E.purge(),E=null),b=y=_=x=null,R=!1}var w=this,y,E,_,b,x,R=!1,A=!0;t.extend(this,{loadFromBlob:function(e){var t=this,i=t.getRuntime(),r=arguments.length>1?arguments[1]:!0;if(!i.can("access_binary"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);return x=e,e.isDetached()?(b=e.getSource(),void h.call(this,b)):void f.call(this,e.getSource(),function(e){r&&(b=l(e)),h.call(t,e)})},loadFromImage:function(e,t){this.meta=e.meta,x=new o(null,{name:e.name,size:e.size,type:e.type}),h.call(this,t?b=e.getAsBinaryString():e.getAsDataURL())},getInfo:function(){var t=this.getRuntime(),n;return!E&&b&&t.can("access_image_binary")&&(E=new a(b)),n={width:e().width||0,height:e().height||0,type:x.type||u.getFileMime(x.name),size:b&&b.length||x.size||0,name:x.name||"",meta:E&&E.meta||this.meta||{}},!n.meta||!n.meta.thumb||n.meta.thumb.data instanceof r||(n.meta.thumb.data=new r(null,{type:"image/jpeg",data:n.meta.thumb.data})),n},downsize:function(){p.apply(this,arguments)},getAsCanvas:function(){return _&&(_.id=this.uid+"_canvas"),_},getAsBlob:function(e,t){return e!==this.type&&p.call(this,this.width,this.height,!1),new o(null,{name:x.name||"",type:e,data:w.getAsBinaryString.call(this,e,t)})},getAsDataURL:function(e){var t=arguments[1]||90;if(!R)return y.src;if("image/jpeg"!==e)return _.toDataURL("image/png");try{return _.toDataURL("image/jpeg",t/100)}catch(n){return _.toDataURL("image/jpeg")}},getAsBinaryString:function(e,t){if(!R)return b||(b=l(w.getAsDataURL(e,t))),b;if("image/jpeg"!==e)b=l(w.getAsDataURL(e,t));else{var n;t||(t=90);try{n=_.toDataURL("image/jpeg",t/100)}catch(i){n=_.toDataURL("image/jpeg")}b=l(n),E&&(b=E.stripHeaders(b),A&&(E.meta&&E.meta.exif&&E.setExif({PixelXDimension:this.width,PixelYDimension:this.height}),b=E.writeHeaders(b)),E.purge(),E=null)}return R=!1,b},destroy:function(){w=null,v.call(this),this.getRuntime().getShim().removeInstance(this.uid)}})}return e.Image=l}),i(X,[u,c,h,f,m],function(e,t,n,i,r){function o(){var e;try{e=navigator.plugins["Shockwave Flash"],e=e.description}catch(t){try{e=new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(n){e="0.0"}}return e=e.match(/\d+/g),parseFloat(e[0]+"."+e[1])}function a(e){var i=n.get(e);i&&"OBJECT"==i.nodeName&&("IE"===t.browser?(i.style.display="none",function r(){4==i.readyState?s(e):setTimeout(r,10)}()):i.parentNode.removeChild(i))}function s(e){var t=n.get(e);if(t){for(var i in t)"function"==typeof t[i]&&(t[i]=null);t.parentNode.removeChild(t)}}function u(s){var u=this,d;s=e.extend({swf_url:t.swf_url},s),r.call(this,s,c,{access_binary:function(e){return e&&"browser"===u.mode},access_image_binary:function(e){return e&&"browser"===u.mode},display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:function(){return"client"===u.mode},resize_image:r.capTrue,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!e.arrayDiff(t,["","text","document"])||"browser"===u.mode},return_status_code:function(t){return"browser"===u.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:function(e){return e&&"browser"===u.mode},send_browser_cookies:function(e){return e&&"browser"===u.mode},send_custom_headers:function(e){return e&&"browser"===u.mode},send_multipart:r.capTrue,slice_blob:function(e){return e&&"browser"===u.mode},stream_upload:function(e){return e&&"browser"===u.mode},summon_file_dialog:!1,upload_filesize:function(t){return e.parseSizeStr(t)<=2097152||"client"===u.mode},use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}},{access_binary:function(e){return e?"browser":"client"},access_image_binary:function(e){return e?"browser":"client"},report_upload_progress:function(e){return e?"browser":"client"},return_response_type:function(t){return e.arrayDiff(t,["","text","json","document"])?"browser":["client","browser"]},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"browser":["client","browser"]},send_binary_string:function(e){return e?"browser":"client"},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"browser":"client"},stream_upload:function(e){return e?"client":"browser"},upload_filesize:function(t){return e.parseSizeStr(t)>=2097152?"client":"browser"}},"client"),o()<10&&(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid)},shimExec:function(e,t){var n=[].slice.call(arguments,2);return u.getShim().exec(this.uid,e,t,n)},init:function(){var n,r,o;o=this.getShimContainer(),e.extend(o.style,{position:"absolute",top:"-8px",left:"-8px",width:"9px",height:"9px",overflow:"hidden"}),n=' ',"IE"===t.browser?(r=document.createElement("div"),o.appendChild(r),r.outerHTML=n,r=o=null):o.innerHTML=n,d=setTimeout(function(){u&&!u.initialized&&u.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},5e3)},destroy:function(e){return function(){a(u.uid),e.call(u),clearTimeout(d),s=d=e=u=null}}(this.destroy)},l)}var c="flash",l={};return r.addConstructor(c,u),l}),i(V,[X,E,u],function(e,t,n){var i={init:function(e){var i=this,r=this.getRuntime();this.bind("Change",function(){var e=r.shimExec.call(i,"FileInput","getFiles");i.files=[],n.each(e,function(e){i.files.push(new t(r.uid,e))})},999),this.getRuntime().shimExec.call(this,"FileInput","init",{name:e.name,accept:e.accept,multiple:e.multiple}),this.trigger("ready")}};return e.FileInput=i}),i(W,[X,y],function(e,t){var n={slice:function(e,n,i,r){var o=this.getRuntime();return 0>n?n=Math.max(e.size+n,0):n>0&&(n=Math.min(n,e.size)),0>i?i=Math.max(e.size+i,0):i>0&&(i=Math.min(i,e.size)),e=o.shimExec.call(this,"Blob","slice",n,i,r||""),e&&(e=new t(o.uid,e)),e}};return e.Blob=n}),i(Y,[X,w],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i={read:function(e,t){var i=this;return i.result="","readAsDataURL"===e&&(i.result="data:"+(t.type||"")+";base64,"),i.bind("Progress",function(t,r){r&&(i.result+=n(r,e))},999),i.getRuntime().shimExec.call(this,"FileReader","readAsBase64",t.uid)}};return e.FileReader=i}),i($,[X,w],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i={read:function(e,t){var i,r=this.getRuntime();return(i=r.shimExec.call(this,"FileReaderSync","readAsBase64",t.uid))?("readAsDataURL"===e&&(i="data:"+(t.type||"")+";base64,"+i),n(i,e,t.type)):null}};return e.FileReaderSync=i}),i(J,[X,u,y,E,A,I,S],function(e,t,n,i,r,o,a){var s={send:function(e,i){function r(){e.transport=l.mode,l.shimExec.call(c,"XMLHttpRequest","send",e,i)}function s(e,t){l.shimExec.call(c,"XMLHttpRequest","appendBlob",e,t.uid),i=null,r()}function u(e,t){var n=new a;n.bind("TransportingComplete",function(){t(this.result)}),n.transport(e.getSource(),e.type,{ruid:l.uid})}var c=this,l=c.getRuntime();if(t.isEmptyObj(e.headers)||t.each(e.headers,function(e,t){l.shimExec.call(c,"XMLHttpRequest","setRequestHeader",t,e.toString())}),i instanceof o){var d;if(i.each(function(e,t){e instanceof n?d=t:l.shimExec.call(c,"XMLHttpRequest","append",t,e)}),i.hasBlob()){var h=i.getBlob();h.isDetached()?u(h,function(e){h.destroy(),s(d,e)}):s(d,h)}else i=null,r()}else i instanceof n?i.isDetached()?u(i,function(e){i.destroy(),i=e.uid,r()}):(i=i.uid,r()):r()},getResponse:function(e){var n,o,a=this.getRuntime();if(o=a.shimExec.call(this,"XMLHttpRequest","getResponseAsBlob")){if(o=new i(a.uid,o),"blob"===e)return o;try{if(n=new r,~t.inArray(e,["","text"]))return n.readAsText(o);if("json"===e&&window.JSON)return JSON.parse(n.readAsText(o))}finally{o.destroy()}}return null},abort:function(e){var t=this.getRuntime();t.shimExec.call(this,"XMLHttpRequest","abort"),this.dispatchEvent("readystatechange"),this.dispatchEvent("abort")}};return e.XMLHttpRequest=s}),i(Z,[X,y],function(e,t){var n={getAsBlob:function(e){var n=this.getRuntime(),i=n.shimExec.call(this,"Transporter","getAsBlob",e);return i?new t(n.uid,i):null}};return e.Transporter=n}),i(K,[X,u,S,y,A],function(e,t,n,i,r){var o={loadFromBlob:function(e){function t(e){r.shimExec.call(i,"Image","loadFromBlob",e.uid),i=r=null}var i=this,r=i.getRuntime();if(e.isDetached()){var o=new n;o.bind("TransportingComplete",function(){t(o.result.getSource())}),o.transport(e.getSource(),e.type,{ruid:r.uid})}else t(e.getSource())},loadFromImage:function(e){var t=this.getRuntime();return t.shimExec.call(this,"Image","loadFromImage",e.uid)},getInfo:function(){var e=this.getRuntime(),t=e.shimExec.call(this,"Image","getInfo");return!t.meta||!t.meta.thumb||t.meta.thumb.data instanceof i||(t.meta.thumb.data=new i(e.uid,t.meta.thumb.data)),t},getAsBlob:function(e,t){var n=this.getRuntime(),r=n.shimExec.call(this,"Image","getAsBlob",e,t);return r?new i(n.uid,r):null},getAsDataURL:function(){var e=this.getRuntime(),t=e.Image.getAsBlob.apply(this,arguments),n;return t?(n=new r,n.readAsDataURL(t)):null}};return e.Image=o}),i(Q,[u,c,h,f,m],function(e,t,n,i,r){function o(e){var t=!1,n=null,i,r,o,a,s,u=0;try{try{n=new ActiveXObject("AgControl.AgControl"),n.IsVersionSupported(e)&&(t=!0),n=null}catch(c){var l=navigator.plugins["Silverlight Plug-In"];if(l){for(i=l.description,"1.0.30226.2"===i&&(i="2.0.30226.2"),r=i.split(".");r.length>3;)r.pop();for(;r.length<4;)r.push(0);for(o=e.split(".");o.length>4;)o.pop();do a=parseInt(o[u],10),s=parseInt(r[u],10),u++;while(u=a&&!isNaN(a)&&(t=!0)}}}catch(d){t=!1}return t}function a(a){var c=this,l;a=e.extend({xap_url:t.xap_url},a),r.call(this,a,s,{access_binary:r.capTrue,access_image_binary:r.capTrue,display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:r.capTrue,resize_image:r.capTrue,return_response_headers:function(e){return e&&"client"===c.mode},return_response_type:function(e){return"json"!==e?!0:!!window.JSON},return_status_code:function(t){return"client"===c.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:r.capTrue,send_browser_cookies:function(e){return e&&"browser"===c.mode},send_custom_headers:function(e){return e&&"client"===c.mode},send_multipart:r.capTrue,slice_blob:r.capTrue,stream_upload:!0,summon_file_dialog:!1,upload_filesize:r.capTrue,use_http_method:function(t){return"client"===c.mode||!e.arrayDiff(t,["GET","POST"])}},{return_response_headers:function(e){return e?"client":"browser"},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"client":["client","browser"]},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"client":"browser"},use_http_method:function(t){return e.arrayDiff(t,["GET","POST"])?"client":["client","browser"]}}),o("2.0.31005.0")&&"Opera"!==t.browser||(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid).content.Moxie},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec(this.uid,e,t,n)},init:function(){var e;e=this.getShimContainer(),e.innerHTML=' ',l=setTimeout(function(){c&&!c.initialized&&c.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},"Windows"!==t.OS?1e4:5e3)},destroy:function(e){return function(){e.call(c),clearTimeout(l),a=l=e=c=null}}(this.destroy)},u)}var s="silverlight",u={};return r.addConstructor(s,a),u}),i(ee,[Q,E,u],function(e,t,n){var i={init:function(e){function i(e){for(var t="",n=0;ni;i++)n=t.keys[i],s=t[n],s&&(/^(\d|[1-9]\d+)$/.test(s)?s=parseInt(s,10):/^\d*\.\d+$/.test(s)&&(s=parseFloat(s)),r.meta[e][n]=s)}),!r.meta||!r.meta.thumb||r.meta.thumb.data instanceof n||(r.meta.thumb.data=new n(e.uid,r.meta.thumb.data))),r.width=parseInt(o.width,10),r.height=parseInt(o.height,10),r.size=parseInt(o.size,10),r.type=o.type,r.name=o.name,r}})}),i(ue,[u,f,m,c],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue;n.call(this,t,o,{access_binary:s(window.FileReader||window.File&&File.getAsDataURL),access_image_binary:!1,display_media:s(a.Image&&(i.can("create_canvas")||i.can("use_data_uri_over32kb"))),do_cors:!1,drag_and_drop:!1,filter_by_extension:s(function(){return"Chrome"===i.browser&&i.verComp(i.version,28,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||"Safari"===i.browser&&i.verComp(i.version,7,">=")}()),resize_image:function(){return a.Image&&r.can("access_binary")&&i.can("create_canvas")},report_upload_progress:!1,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!!~e.inArray(t,["text","document",""])},return_status_code:function(t){return!e.arrayDiff(t,[200,404])},select_file:function(){return i.can("use_fileinput")},select_multiple:!1,send_binary_string:!1,send_custom_headers:!1,send_multipart:!0,slice_blob:!1,stream_upload:function(){return r.can("select_file")},summon_file_dialog:function(){return r.can("select_file")&&("Firefox"===i.browser&&i.verComp(i.version,4,">=")||"Opera"===i.browser&&i.verComp(i.version,12,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||!!~e.inArray(i.browser,["Chrome","Safari"]))},upload_filesize:u,use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}}),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html4",a={};return n.addConstructor(o,r),a}),i(ce,[ue,E,u,h,N,d,c],function(e,t,n,i,r,o,a){function s(){function e(){var o=this,l=o.getRuntime(),d,h,f,p,m,g;g=n.guid("uid_"),d=l.getShimContainer(),s&&(f=i.get(s+"_form"),f&&n.extend(f.style,{top:"100%"})),p=document.createElement("form"),p.setAttribute("id",g+"_form"),p.setAttribute("method","post"),p.setAttribute("enctype","multipart/form-data"),p.setAttribute("encoding","multipart/form-data"),n.extend(p.style,{overflow:"hidden",position:"absolute",top:0,left:0,width:"100%",height:"100%"}),m=document.createElement("input"),m.setAttribute("id",g),m.setAttribute("type","file"),m.setAttribute("name",c.name||"Filedata"),m.setAttribute("accept",u.join(",")),n.extend(m.style,{fontSize:"999px",opacity:0}),p.appendChild(m),d.appendChild(p),n.extend(m.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),"IE"===a.browser&&a.verComp(a.version,10,"<")&&n.extend(m.style,{filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=0)"}),m.onchange=function(){var n;if(this.value){if(this.files){if(n=this.files[0],0===n.size)return void p.parentNode.removeChild(p)}else n={name:this.value};n=new t(l.uid,n),this.onchange=function(){},e.call(o),o.files=[n],m.setAttribute("id",n.uid),p.setAttribute("id",n.uid+"_form"),o.trigger("change"),m=p=null}},l.can("summon_file_dialog")&&(h=i.get(c.browse_button),r.removeEvent(h,"click",o.uid),r.addEvent(h,"click",function(e){m&&!m.disabled&&m.click(),e.preventDefault()},o.uid)),s=g,d=f=h=null}var s,u=[],c;n.extend(this,{init:function(t){var n=this,a=n.getRuntime(),s;c=t,u=t.accept.mimes||o.extList2mimes(t.accept,a.can("filter_by_extension")),s=a.getShimContainer(),function(){var e,o,u;e=i.get(t.browse_button),a.can("summon_file_dialog")&&("static"===i.getStyle(e,"position")&&(e.style.position="relative"),o=parseInt(i.getStyle(e,"z-index"),10)||1,e.style.zIndex=o,s.style.zIndex=o-1),u=a.can("summon_file_dialog")?e:s,r.addEvent(u,"mouseover",function(){n.trigger("mouseenter")},n.uid),r.addEvent(u,"mouseout",function(){n.trigger("mouseleave")},n.uid),r.addEvent(u,"mousedown",function(){n.trigger("mousedown")},n.uid),r.addEvent(i.get(t.container),"mouseup",function(){n.trigger("mouseup")},n.uid),e=null}(),e.call(this),s=null,n.trigger({type:"ready",async:!0})},disable:function(e){var t;(t=i.get(s))&&(t.disabled=!!e)},destroy:function(){var e=this.getRuntime(),t=e.getShim(),n=e.getShimContainer();r.removeAllEvents(n,this.uid),r.removeAllEvents(c&&i.get(c.container),this.uid),r.removeAllEvents(c&&i.get(c.browse_button),this.uid),n&&(n.innerHTML=""),t.removeInstance(this.uid),s=u=c=n=t=null}})}return e.FileInput=s}),i(le,[ue,F],function(e,t){return e.FileReader=t}),i(de,[ue,u,h,x,f,N,y,I],function(e,t,n,i,r,o,a,s){function u(){function e(e){var t=this,i,r,a,s,u=!1;if(l){if(i=l.id.replace(/_iframe$/,""),r=n.get(i+"_form")){for(a=r.getElementsByTagName("input"),s=a.length;s--;)switch(a[s].getAttribute("type")){case"hidden":a[s].parentNode.removeChild(a[s]);break;case"file":u=!0}a=[],u||r.parentNode.removeChild(r),r=null}setTimeout(function(){o.removeEvent(l,"load",t.uid),l.parentNode&&l.parentNode.removeChild(l);var n=t.getRuntime().getShimContainer();n.children.length||n.parentNode.removeChild(n),n=l=null,e()},1)}}var u,c,l;t.extend(this,{send:function(d,h){function f(){var n=m.getShimContainer()||document.body,r=document.createElement("div");r.innerHTML='',l=r.firstChild,n.appendChild(l),o.addEvent(l,"load",function(){var n;try{n=l.contentWindow.document||l.contentDocument||window.frames[l.id].document,/^4(0[0-9]|1[0-7]|2[2346])\s/.test(n.title)?u=n.title.replace(/^(\d+).*$/,"$1"):(u=200,c=t.trim(n.body.innerHTML),p.trigger({type:"progress",loaded:c.length,total:c.length}),y&&p.trigger({type:"uploadprogress",loaded:y.size||1025,total:y.size||1025}))}catch(r){if(!i.hasSameOrigin(d.url))return void e.call(p,function(){p.trigger("error")});u=404}e.call(p,function(){p.trigger("load")})},p.uid)}var p=this,m=p.getRuntime(),g,v,w,y;if(u=c=null,h instanceof s&&h.hasBlob()){if(y=h.getBlob(),g=y.uid,w=n.get(g),v=n.get(g+"_form"),!v)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR)}else g=t.guid("uid_"),v=document.createElement("form"),v.setAttribute("id",g+"_form"),v.setAttribute("method",d.method),v.setAttribute("enctype","multipart/form-data"),v.setAttribute("encoding","multipart/form-data"),m.getShimContainer().appendChild(v);v.setAttribute("target",g+"_iframe"),h instanceof s&&h.each(function(e,n){if(e instanceof a)w&&w.setAttribute("name",n);else{var i=document.createElement("input");t.extend(i,{type:"hidden",name:n,value:e}),w?v.insertBefore(i,w):v.appendChild(i)}}),v.setAttribute("action",d.url),f(),v.submit(),p.trigger("loadstart")},getStatus:function(){return u},getResponse:function(e){if("json"===e&&"string"===t.typeOf(c)&&window.JSON)try{
+return JSON.parse(c.replace(/^\s*]*>/,"").replace(/<\/pre>\s*$/,""))}catch(n){return null}return c},abort:function(){var t=this;l&&l.contentWindow&&(l.contentWindow.stop?l.contentWindow.stop():l.contentWindow.document.execCommand?l.contentWindow.document.execCommand("Stop"):l.src="about:blank"),e.call(this,function(){t.dispatchEvent("abort")})}})}return e.XMLHttpRequest=u}),i(he,[ue,j],function(e,t){return e.Image=t}),a([u,c,l,d,h,f,p,m,g,v,w,y,E,_,b,x,R,A,I,T,S,O,N])}(this);;(function(e){"use strict";var t={},n=e.moxie.core.utils.Basic.inArray;return function r(e){var i,s;for(i in e)s=typeof e[i],s==="object"&&!~n(i,["Exceptions","Env","Mime"])?r(e[i]):s==="function"&&(t[i]=e[i])}(e.moxie),t.Env=e.moxie.core.utils.Env,t.Mime=e.moxie.core.utils.Mime,t.Exceptions=e.moxie.core.Exceptions,e.mOxie=t,e.o||(e.o=t),t})(this);
+/**
+ * Plupload - multi-runtime File Uploader
+ * v2.1.8
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ *
+ * Date: 2015-07-21
+ */
+;(function(e,t,n){function s(e){function r(e,t,r){var i={chunks:"slice_blob",jpgresize:"send_binary_string",pngresize:"send_binary_string",progress:"report_upload_progress",multi_selection:"select_multiple",dragdrop:"drag_and_drop",drop_element:"drag_and_drop",headers:"send_custom_headers",urlstream_upload:"send_binary_string",canSendBinary:"send_binary",triggerDialog:"summon_file_dialog"};i[e]?n[i[e]]=t:r||(n[e]=t)}var t=e.required_features,n={};if(typeof t=="string")o.each(t.split(/\s*,\s*/),function(e){r(e,!0)});else if(typeof t=="object")o.each(t,function(e,t){r(t,e)});else if(t===!0){e.chunk_size>0&&(n.slice_blob=!0);if(e.resize.enabled||!e.multipart)n.send_binary_string=!0;o.each(e,function(e,t){r(t,!!e,!0)})}return n}var r=e.setTimeout,i={},o={VERSION:"2.1.8",STOPPED:1,STARTED:2,QUEUED:1,UPLOADING:2,FAILED:4,DONE:5,GENERIC_ERROR:-100,HTTP_ERROR:-200,IO_ERROR:-300,SECURITY_ERROR:-400,INIT_ERROR:-500,FILE_SIZE_ERROR:-600,FILE_EXTENSION_ERROR:-601,FILE_DUPLICATE_ERROR:-602,IMAGE_FORMAT_ERROR:-700,MEMORY_ERROR:-701,IMAGE_DIMENSIONS_ERROR:-702,mimeTypes:t.mimes,ua:t.ua,typeOf:t.typeOf,extend:t.extend,guid:t.guid,get:function(n){var r=[],i;t.typeOf(n)!=="array"&&(n=[n]);var s=n.length;while(s--)i=t.get(n[s]),i&&r.push(i);return r.length?r:null},each:t.each,getPos:t.getPos,getSize:t.getSize,xmlEncode:function(e){var t={"<":"lt",">":"gt","&":"amp",'"':"quot","'":"#39"},n=/[<>&\"\']/g;return e?(""+e).replace(n,function(e){return t[e]?"&"+t[e]+";":e}):e},toArray:t.toArray,inArray:t.inArray,addI18n:t.addI18n,translate:t.translate,isEmptyObj:t.isEmptyObj,hasClass:t.hasClass,addClass:t.addClass,removeClass:t.removeClass,getStyle:t.getStyle,addEvent:t.addEvent,removeEvent:t.removeEvent,removeAllEvents:t.removeAllEvents,cleanName:function(e){var t,n;n=[/[\300-\306]/g,"A",/[\340-\346]/g,"a",/\307/g,"C",/\347/g,"c",/[\310-\313]/g,"E",/[\350-\353]/g,"e",/[\314-\317]/g,"I",/[\354-\357]/g,"i",/\321/g,"N",/\361/g,"n",/[\322-\330]/g,"O",/[\362-\370]/g,"o",/[\331-\334]/g,"U",/[\371-\374]/g,"u"];for(t=0;t0?"&":"?")+n),e},formatSize:function(e){function t(e,t){return Math.round(e*Math.pow(10,t))/Math.pow(10,t)}if(e===n||/\D/.test(e))return o.translate("N/A");var r=Math.pow(1024,4);return e>r?t(e/r,1)+" "+o.translate("tb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("gb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("mb"):e>1024?Math.round(e/1024)+" "+o.translate("kb"):e+" "+o.translate("b")},parseSize:t.parseSizeStr,predictRuntime:function(e,n){var r,i;return r=new o.Uploader(e),i=t.Runtime.thatCan(r.getOption().required_features,n||e.runtimes),r.destroy(),i},addFileFilter:function(e,t){i[e]=t}};o.addFileFilter("mime_types",function(e,t,n){e.length&&!e.regexp.test(t.name)?(this.trigger("Error",{code:o.FILE_EXTENSION_ERROR,message:o.translate("File extension error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("max_file_size",function(e,t,n){var r;e=o.parseSize(e),t.size!==r&&e&&t.size>e?(this.trigger("Error",{code:o.FILE_SIZE_ERROR,message:o.translate("File size error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("prevent_duplicates",function(e,t,n){if(e){var r=this.files.length;while(r--)if(t.name===this.files[r].name&&t.size===this.files[r].size){this.trigger("Error",{code:o.FILE_DUPLICATE_ERROR,message:o.translate("Duplicate file error."),file:t}),n(!1);return}}n(!0)}),o.Uploader=function(e){function g(){var e,t=0,n;if(this.state==o.STARTED){for(n=0;n0?Math.ceil(e.loaded/e.size*100):100,b()}function b(){var e,t;d.reset();for(e=0;e0?Math.ceil(d.uploaded/f.length*100):0:(d.bytesPerSec=Math.ceil(d.loaded/((+(new Date)-p||1)/1e3)),d.percent=d.size>0?Math.ceil(d.loaded/d.size*100):0)}function w(){var e=c[0]||h[0];return e?e.getRuntime().uid:!1}function E(e,n){if(e.ruid){var r=t.Runtime.getInfo(e.ruid);if(r)return r.can(n)}return!1}function S(){this.bind("FilesAdded FilesRemoved",function(e){e.trigger("QueueChanged"),e.refresh()}),this.bind("CancelUpload",O),this.bind("BeforeUpload",C),this.bind("UploadFile",k),this.bind("UploadProgress",L),this.bind("StateChanged",A),this.bind("QueueChanged",b),this.bind("Error",_),this.bind("FileUploaded",M),this.bind("Destroy",D)}function x(e,n){var r=this,i=0,s=[],u={runtime_order:e.runtimes,required_caps:e.required_features,preferred_caps:l,swf_url:e.flash_swf_url,xap_url:e.silverlight_xap_url};o.each(e.runtimes.split(/\s*,\s*/),function(t){e[t]&&(u[t]=e[t])}),e.browse_button&&o.each(e.browse_button,function(n){s.push(function(s){var a=new t.FileInput(o.extend({},u,{accept:e.filters.mime_types,name:e.file_data_name,multiple:e.multi_selection,container:e.container,browse_button:n}));a.onready=function(){var e=t.Runtime.getInfo(this.ruid);t.extend(r.features,{chunks:e.can("slice_blob"),multipart:e.can("send_multipart"),multi_selection:e.can("select_multiple")}),i++,c.push(this),s()},a.onchange=function(){r.addFile(this.files)},a.bind("mouseenter mouseleave mousedown mouseup",function(r){v||(e.browse_button_hover&&("mouseenter"===r.type?t.addClass(n,e.browse_button_hover):"mouseleave"===r.type&&t.removeClass(n,e.browse_button_hover)),e.browse_button_active&&("mousedown"===r.type?t.addClass(n,e.browse_button_active):"mouseup"===r.type&&t.removeClass(n,e.browse_button_active)))}),a.bind("mousedown",function(){r.trigger("Browse")}),a.bind("error runtimeerror",function(){a=null,s()}),a.init()})}),e.drop_element&&o.each(e.drop_element,function(e){s.push(function(n){var s=new t.FileDrop(o.extend({},u,{drop_zone:e}));s.onready=function(){var e=t.Runtime.getInfo(this.ruid);r.features.dragdrop=e.can("drag_and_drop"),i++,h.push(this),n()},s.ondrop=function(){r.addFile(this.files)},s.bind("error runtimeerror",function(){s=null,n()}),s.init()})}),t.inSeries(s,function(){typeof n=="function"&&n(i)})}function T(e,r,i){var s=new t.Image;try{s.onload=function(){if(r.width>this.width&&r.height>this.height&&r.quality===n&&r.preserve_headers&&!r.crop)return this.destroy(),i(e);s.downsize(r.width,r.height,r.crop,r.preserve_headers)},s.onresize=function(){i(this.getAsBlob(e.type,r.quality)),this.destroy()},s.onerror=function(){i(e)},s.load(e)}catch(o){i(e)}}function N(e,n,r){function f(e,t,n){var r=a[e];switch(e){case"max_file_size":e==="max_file_size"&&(a.max_file_size=a.filters.max_file_size=t);break;case"chunk_size":if(t=o.parseSize(t))a[e]=t,a.send_file_name=!0;break;case"multipart":a[e]=t,t||(a.send_file_name=!0);break;case"unique_names":a[e]=t,t&&(a.send_file_name=!0);break;case"filters":o.typeOf(t)==="array"&&(t={mime_types:t}),n?o.extend(a.filters,t):a.filters=t,t.mime_types&&(a.filters.mime_types.regexp=function(e){var t=[];return o.each(e,function(e){o.each(e.extensions.split(/,/),function(e){/^\s*\*\s*$/.test(e)?t.push("\\.*"):t.push("\\."+e.replace(new RegExp("["+"/^$.*+?|()[]{}\\".replace(/./g,"\\$&")+"]","g"),"\\$&"))})}),new RegExp("("+t.join("|")+")$","i")}(a.filters.mime_types));break;case"resize":n?o.extend(a.resize,t,{enabled:!0}):a.resize=t;break;case"prevent_duplicates":a.prevent_duplicates=a.filters.prevent_duplicates=!!t;break;case"browse_button":case"drop_element":t=o.get(t);case"container":case"runtimes":case"multi_selection":case"flash_swf_url":case"silverlight_xap_url":a[e]=t,n||(u=!0);break;default:a[e]=t}n||i.trigger("OptionChanged",e,t,r)}var i=this,u=!1;typeof e=="object"?o.each(e,function(e,t){f(t,e,r)}):f(e,n,r),r?(a.required_features=s(o.extend({},a)),l=s(o.extend({},a,{required_features:!0}))):u&&(i.trigger("Destroy"),x.call(i,a,function(e){e?(i.runtime=t.Runtime.getInfo(w()).type,i.trigger("Init",{runtime:i.runtime}),i.trigger("PostInit")):i.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})}))}function C(e,t){if(e.settings.unique_names){var n=t.name.match(/\.([^.]+)$/),r="part";n&&(r=n[1]),t.target_name=t.id+"."+r}}function k(e,n){function h(){u-->0?r(p,1e3):(n.loaded=f,e.trigger("Error",{code:o.HTTP_ERROR,message:o.translate("HTTP Error."),file:n,response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()}))}function p(){var d,v,g={},y;if(n.status!==o.UPLOADING||e.state===o.STOPPED)return;e.settings.send_file_name&&(g.name=n.target_name||n.name),s&&a.chunks&&c.size>s?(y=Math.min(s,c.size-f),d=c.slice(f,f+y)):(y=c.size,d=c),s&&a.chunks&&(e.settings.send_chunk_number?(g.chunk=Math.ceil(f/s),g.chunks=Math.ceil(c.size/s)):(g.offset=f,g.total=c.size)),m=new t.XMLHttpRequest,m.upload&&(m.upload.onprogress=function(t){n.loaded=Math.min(n.size,f+t.loaded),e.trigger("UploadProgress",n)}),m.onload=function(){if(m.status>=400){h();return}u=e.settings.max_retries,y=c.size?(n.size!=n.origSize&&(c.destroy(),c=null),e.trigger("UploadProgress",n),n.status=o.DONE,e.trigger("FileUploaded",n,{response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()})):r(p,1)},m.onerror=function(){h()},m.onloadend=function(){this.destroy(),m=null},e.settings.multipart&&a.multipart?(m.open("post",i,!0),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),v=new t.FormData,o.each(o.extend(g,e.settings.multipart_params),function(e,t){v.append(t,e)}),v.append(e.settings.file_data_name,d),m.send(v,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url})):(i=o.buildUrl(e.settings.url,o.extend(g,e.settings.multipart_params)),m.open("post",i,!0),m.setRequestHeader("Content-Type","application/octet-stream"),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),m.send(d,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url}))}var i=e.settings.url,s=e.settings.chunk_size,u=e.settings.max_retries,a=e.features,f=0,c;n.loaded&&(f=n.loaded=s?s*Math.floor(n.loaded/s):0),c=n.getSource(),e.settings.resize.enabled&&E(c,"send_binary_string")&&!!~t.inArray(c.type,["image/jpeg","image/png"])?T.call(this,c,e.settings.resize,function(e){c=e,n.size=e.size,p()}):p()}function L(e,t){y(t)}function A(e){if(e.state==o.STARTED)p=+(new Date);else if(e.state==o.STOPPED)for(var t=e.files.length-1;t>=0;t--)e.files[t].status==o.UPLOADING&&(e.files[t].status=o.QUEUED,b())}function O(){m&&m.abort()}function M(e){b(),r(function(){g.call(e)},1)}function _(e,t){t.code===o.INIT_ERROR?e.destroy():t.code===o.HTTP_ERROR&&(t.file.status=o.FAILED,y(t.file),e.state==o.STARTED&&(e.trigger("CancelUpload"),r(function(){g.call(e)},1)))}function D(e){e.stop(),o.each(f,function(e){e.destroy()}),f=[],c.length&&(o.each(c,function(e){e.destroy()}),c=[]),h.length&&(o.each(h,function(e){e.destroy()}),h=[]),l={},v=!1,p=m=null,d.reset()}var u=o.guid(),a,f=[],l={},c=[],h=[],p,d,v=!1,m;a={runtimes:t.Runtime.order,max_retries:0,chunk_size:0,multipart:!0,multi_selection:!0,file_data_name:"file",flash_swf_url:"js/Moxie.swf",silverlight_xap_url:"js/Moxie.xap",filters:{mime_types:[],prevent_duplicates:!1,max_file_size:0},resize:{enabled:!1,preserve_headers:!0,crop:!1},send_file_name:!0,send_chunk_number:!0},N.call(this,e,null,!0),d=new o.QueueProgress,o.extend(this,{id:u,uid:u,state:o.STOPPED,features:{},runtime:null,files:f,settings:a,total:d,init:function(){var e=this;typeof a.preinit=="function"?a.preinit(e):o.each(a.preinit,function(t,n){e.bind(n,t)}),S.call(this);if(!a.browse_button||!a.url){this.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")});return}x.call(this,a,function(n){typeof a.init=="function"?a.init(e):o.each(a.init,function(t,n){e.bind(n,t)}),n?(e.runtime=t.Runtime.getInfo(w()).type,e.trigger("Init",{runtime:e.runtime}),e.trigger("PostInit")):e.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})})},setOption:function(e,t){N.call(this,e,t,!this.runtime)},getOption:function(e){return e?a[e]:a},refresh:function(){c.length&&o.each(c,function(e){e.trigger("Refresh")}),this.trigger("Refresh")},start:function(){this.state!=o.STARTED&&(this.state=o.STARTED,this.trigger("StateChanged"),g.call(this))},stop:function(){this.state!=o.STOPPED&&(this.state=o.STOPPED,this.trigger("StateChanged"),this.trigger("CancelUpload"))},disableBrowse:function(){v=arguments[0]!==n?arguments[0]:!0,c.length&&o.each(c,function(e){e.disable(v)}),this.trigger("DisableBrowse",v)},getFile:function(e){var t;for(t=f.length-1;t>=0;t--)if(f[t].id===e)return f[t]},addFile:function(e,n){function c(e,n){var r=[];t.each(s.settings.filters,function(t,n){i[n]&&r.push(function(r){i[n].call(s,t,e,function(e){r(!e)})})}),t.inSeries(r,n)}function h(e){var i=t.typeOf(e);if(e instanceof t.File){if(!e.ruid&&!e.isDetached()){if(!l)return!1;e.ruid=l,e.connectRuntime(l)}h(new o.File(e))}else e instanceof t.Blob?(h(e.getSource()),e.destroy()):e instanceof o.File?(n&&(e.name=n),u.push(function(t){c(e,function(n){n||(f.push(e),a.push(e),s.trigger("FileFiltered",e)),r(t,1)})})):t.inArray(i,["file","blob"])!==-1?h(new t.File(null,e)):i==="node"&&t.typeOf(e.files)==="filelist"?t.each(e.files,h):i==="array"&&(n=null,t.each(e,h))}var s=this,u=[],a=[],l;l=w(),h(e),u.length&&t.inSeries(u,function(){a.length&&s.trigger("FilesAdded",a)})},removeFile:function(e){var t=typeof e=="string"?e:e.id;for(var n=f.length-1;n>=0;n--)if(f[n].id===t)return this.splice(n,1)[0]},splice:function(e,t){var r=f.splice(e===n?0:e,t===n?f.length:t),i=!1;return this.state==o.STARTED&&(o.each(r,function(e){if(e.status===o.UPLOADING)return i=!0,!1}),i&&this.stop()),this.trigger("FilesRemoved",r),o.each(r,function(e){e.destroy()}),i&&this.start(),r},dispatchEvent:function(e){var t,n,r;e=e.toLowerCase(),t=this.hasEventListener(e);if(t){t.sort(function(e,t){return t.priority-e.priority}),n=[].slice.call(arguments),n.shift(),n.unshift(this);for(var i=0;i0&&(n.slice_blob=!0);if(e.resize.enabled||!e.multipart)n.send_binary_string=!0;o.each(e,function(e,t){r(t,!!e,!0)})}return n}var r=e.setTimeout,i={},o={VERSION:"2.1.8",STOPPED:1,STARTED:2,QUEUED:1,UPLOADING:2,FAILED:4,DONE:5,GENERIC_ERROR:-100,HTTP_ERROR:-200,IO_ERROR:-300,SECURITY_ERROR:-400,INIT_ERROR:-500,FILE_SIZE_ERROR:-600,FILE_EXTENSION_ERROR:-601,FILE_DUPLICATE_ERROR:-602,IMAGE_FORMAT_ERROR:-700,MEMORY_ERROR:-701,IMAGE_DIMENSIONS_ERROR:-702,mimeTypes:t.mimes,ua:t.ua,typeOf:t.typeOf,extend:t.extend,guid:t.guid,get:function(n){var r=[],i;t.typeOf(n)!=="array"&&(n=[n]);var s=n.length;while(s--)i=t.get(n[s]),i&&r.push(i);return r.length?r:null},each:t.each,getPos:t.getPos,getSize:t.getSize,xmlEncode:function(e){var t={"<":"lt",">":"gt","&":"amp",'"':"quot","'":"#39"},n=/[<>&\"\']/g;return e?(""+e).replace(n,function(e){return t[e]?"&"+t[e]+";":e}):e},toArray:t.toArray,inArray:t.inArray,addI18n:t.addI18n,translate:t.translate,isEmptyObj:t.isEmptyObj,hasClass:t.hasClass,addClass:t.addClass,removeClass:t.removeClass,getStyle:t.getStyle,addEvent:t.addEvent,removeEvent:t.removeEvent,removeAllEvents:t.removeAllEvents,cleanName:function(e){var t,n;n=[/[\300-\306]/g,"A",/[\340-\346]/g,"a",/\307/g,"C",/\347/g,"c",/[\310-\313]/g,"E",/[\350-\353]/g,"e",/[\314-\317]/g,"I",/[\354-\357]/g,"i",/\321/g,"N",/\361/g,"n",/[\322-\330]/g,"O",/[\362-\370]/g,"o",/[\331-\334]/g,"U",/[\371-\374]/g,"u"];for(t=0;t0?"&":"?")+n),e},formatSize:function(e){function t(e,t){return Math.round(e*Math.pow(10,t))/Math.pow(10,t)}if(e===n||/\D/.test(e))return o.translate("N/A");var r=Math.pow(1024,4);return e>r?t(e/r,1)+" "+o.translate("tb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("gb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("mb"):e>1024?Math.round(e/1024)+" "+o.translate("kb"):e+" "+o.translate("b")},parseSize:t.parseSizeStr,predictRuntime:function(e,n){var r,i;return r=new o.Uploader(e),i=t.Runtime.thatCan(r.getOption().required_features,n||e.runtimes),r.destroy(),i},addFileFilter:function(e,t){i[e]=t}};o.addFileFilter("mime_types",function(e,t,n){e.length&&!e.regexp.test(t.name)?(this.trigger("Error",{code:o.FILE_EXTENSION_ERROR,message:o.translate("File extension error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("max_file_size",function(e,t,n){var r;e=o.parseSize(e),t.size!==r&&e&&t.size>e?(this.trigger("Error",{code:o.FILE_SIZE_ERROR,message:o.translate("File size error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("prevent_duplicates",function(e,t,n){if(e){var r=this.files.length;while(r--)if(t.name===this.files[r].name&&t.size===this.files[r].size){this.trigger("Error",{code:o.FILE_DUPLICATE_ERROR,message:o.translate("Duplicate file error."),file:t}),n(!1);return}}n(!0)}),o.Uploader=function(e){function g(){var e,t=0,n;if(this.state==o.STARTED){for(n=0;n0?Math.ceil(e.loaded/e.size*100):100,b()}function b(){var e,t;d.reset();for(e=0;e0?Math.ceil(d.uploaded/f.length*100):0:(d.bytesPerSec=Math.ceil(d.loaded/((+(new Date)-p||1)/1e3)),d.percent=d.size>0?Math.ceil(d.loaded/d.size*100):0)}function w(){var e=c[0]||h[0];return e?e.getRuntime().uid:!1}function E(e,n){if(e.ruid){var r=t.Runtime.getInfo(e.ruid);if(r)return r.can(n)}return!1}function S(){this.bind("FilesAdded FilesRemoved",function(e){e.trigger("QueueChanged"),e.refresh()}),this.bind("CancelUpload",O),this.bind("BeforeUpload",C),this.bind("UploadFile",k),this.bind("UploadProgress",L),this.bind("StateChanged",A),this.bind("QueueChanged",b),this.bind("Error",_),this.bind("FileUploaded",M),this.bind("Destroy",D)}function x(e,n){var r=this,i=0,s=[],u={runtime_order:e.runtimes,required_caps:e.required_features,preferred_caps:l,swf_url:e.flash_swf_url,xap_url:e.silverlight_xap_url};o.each(e.runtimes.split(/\s*,\s*/),function(t){e[t]&&(u[t]=e[t])}),e.browse_button&&o.each(e.browse_button,function(n){s.push(function(s){var a=new t.FileInput(o.extend({},u,{accept:e.filters.mime_types,name:e.file_data_name,multiple:e.multi_selection,container:e.container,browse_button:n}));a.onready=function(){var e=t.Runtime.getInfo(this.ruid);t.extend(r.features,{chunks:e.can("slice_blob"),multipart:e.can("send_multipart"),multi_selection:e.can("select_multiple")}),i++,c.push(this),s()},a.onchange=function(){r.addFile(this.files)},a.bind("mouseenter mouseleave mousedown mouseup",function(r){v||(e.browse_button_hover&&("mouseenter"===r.type?t.addClass(n,e.browse_button_hover):"mouseleave"===r.type&&t.removeClass(n,e.browse_button_hover)),e.browse_button_active&&("mousedown"===r.type?t.addClass(n,e.browse_button_active):"mouseup"===r.type&&t.removeClass(n,e.browse_button_active)))}),a.bind("mousedown",function(){r.trigger("Browse")}),a.bind("error runtimeerror",function(){a=null,s()}),a.init()})}),e.drop_element&&o.each(e.drop_element,function(e){s.push(function(n){var s=new t.FileDrop(o.extend({},u,{drop_zone:e}));s.onready=function(){var e=t.Runtime.getInfo(this.ruid);r.features.dragdrop=e.can("drag_and_drop"),i++,h.push(this),n()},s.ondrop=function(){r.addFile(this.files)},s.bind("error runtimeerror",function(){s=null,n()}),s.init()})}),t.inSeries(s,function(){typeof n=="function"&&n(i)})}function T(e,r,i){var s=new t.Image;try{s.onload=function(){if(r.width>this.width&&r.height>this.height&&r.quality===n&&r.preserve_headers&&!r.crop)return this.destroy(),i(e);s.downsize(r.width,r.height,r.crop,r.preserve_headers)},s.onresize=function(){i(this.getAsBlob(e.type,r.quality)),this.destroy()},s.onerror=function(){i(e)},s.load(e)}catch(o){i(e)}}function N(e,n,r){function f(e,t,n){var r=a[e];switch(e){case"max_file_size":e==="max_file_size"&&(a.max_file_size=a.filters.max_file_size=t);break;case"chunk_size":if(t=o.parseSize(t))a[e]=t,a.send_file_name=!0;break;case"multipart":a[e]=t,t||(a.send_file_name=!0);break;case"unique_names":a[e]=t,t&&(a.send_file_name=!0);break;case"filters":o.typeOf(t)==="array"&&(t={mime_types:t}),n?o.extend(a.filters,t):a.filters=t,t.mime_types&&(a.filters.mime_types.regexp=function(e){var t=[];return o.each(e,function(e){o.each(e.extensions.split(/,/),function(e){/^\s*\*\s*$/.test(e)?t.push("\\.*"):t.push("\\."+e.replace(new RegExp("["+"/^$.*+?|()[]{}\\".replace(/./g,"\\$&")+"]","g"),"\\$&"))})}),new RegExp("("+t.join("|")+")$","i")}(a.filters.mime_types));break;case"resize":n?o.extend(a.resize,t,{enabled:!0}):a.resize=t;break;case"prevent_duplicates":a.prevent_duplicates=a.filters.prevent_duplicates=!!t;break;case"browse_button":case"drop_element":t=o.get(t);case"container":case"runtimes":case"multi_selection":case"flash_swf_url":case"silverlight_xap_url":a[e]=t,n||(u=!0);break;default:a[e]=t}n||i.trigger("OptionChanged",e,t,r)}var i=this,u=!1;typeof e=="object"?o.each(e,function(e,t){f(t,e,r)}):f(e,n,r),r?(a.required_features=s(o.extend({},a)),l=s(o.extend({},a,{required_features:!0}))):u&&(i.trigger("Destroy"),x.call(i,a,function(e){e?(i.runtime=t.Runtime.getInfo(w()).type,i.trigger("Init",{runtime:i.runtime}),i.trigger("PostInit")):i.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})}))}function C(e,t){if(e.settings.unique_names){var n=t.name.match(/\.([^.]+)$/),r="part";n&&(r=n[1]),t.target_name=t.id+"."+r}}function k(e,n){function h(){u-->0?r(p,1e3):(n.loaded=f,e.trigger("Error",{code:o.HTTP_ERROR,message:o.translate("HTTP Error."),file:n,response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()}))}function p(){var d,v,g={},y;if(n.status!==o.UPLOADING||e.state===o.STOPPED)return;e.settings.send_file_name&&(g.name=n.target_name||n.name),s&&a.chunks&&c.size>s?(y=Math.min(s,c.size-f),d=c.slice(f,f+y)):(y=c.size,d=c),s&&a.chunks&&(e.settings.send_chunk_number?(g.chunk=Math.ceil(f/s),g.chunks=Math.ceil(c.size/s)):(g.offset=f,g.total=c.size)),m=new t.XMLHttpRequest,m.upload&&(m.upload.onprogress=function(t){n.loaded=Math.min(n.size,f+t.loaded),e.trigger("UploadProgress",n)}),m.onload=function(){if(m.status>=400){h();return}u=e.settings.max_retries,y=c.size?(n.size!=n.origSize&&(c.destroy(),c=null),e.trigger("UploadProgress",n),n.status=o.DONE,e.trigger("FileUploaded",n,{response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()})):r(p,1)},m.onerror=function(){h()},m.onloadend=function(){this.destroy(),m=null},e.settings.multipart&&a.multipart?(m.open("post",i,!0),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),v=new t.FormData,o.each(o.extend(g,e.settings.multipart_params),function(e,t){v.append(t,e)}),v.append(e.settings.file_data_name,d),m.send(v,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url})):(i=o.buildUrl(e.settings.url,o.extend(g,e.settings.multipart_params)),m.open("post",i,!0),m.setRequestHeader("Content-Type","application/octet-stream"),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),m.send(d,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url}))}var i=e.settings.url,s=e.settings.chunk_size,u=e.settings.max_retries,a=e.features,f=0,c;n.loaded&&(f=n.loaded=s?s*Math.floor(n.loaded/s):0),c=n.getSource(),e.settings.resize.enabled&&E(c,"send_binary_string")&&!!~t.inArray(c.type,["image/jpeg","image/png"])?T.call(this,c,e.settings.resize,function(e){c=e,n.size=e.size,p()}):p()}function L(e,t){y(t)}function A(e){if(e.state==o.STARTED)p=+(new Date);else if(e.state==o.STOPPED)for(var t=e.files.length-1;t>=0;t--)e.files[t].status==o.UPLOADING&&(e.files[t].status=o.QUEUED,b())}function O(){m&&m.abort()}function M(e){b(),r(function(){g.call(e)},1)}function _(e,t){t.code===o.INIT_ERROR?e.destroy():t.code===o.HTTP_ERROR&&(t.file.status=o.FAILED,y(t.file),e.state==o.STARTED&&(e.trigger("CancelUpload"),r(function(){g.call(e)},1)))}function D(e){e.stop(),o.each(f,function(e){e.destroy()}),f=[],c.length&&(o.each(c,function(e){e.destroy()}),c=[]),h.length&&(o.each(h,function(e){e.destroy()}),h=[]),l={},v=!1,p=m=null,d.reset()}var u=o.guid(),a,f=[],l={},c=[],h=[],p,d,v=!1,m;a={runtimes:t.Runtime.order,max_retries:0,chunk_size:0,multipart:!0,multi_selection:!0,file_data_name:"file",flash_swf_url:"js/Moxie.swf",silverlight_xap_url:"js/Moxie.xap",filters:{mime_types:[],prevent_duplicates:!1,max_file_size:0},resize:{enabled:!1,preserve_headers:!0,crop:!1},send_file_name:!0,send_chunk_number:!0},N.call(this,e,null,!0),d=new o.QueueProgress,o.extend(this,{id:u,uid:u,state:o.STOPPED,features:{},runtime:null,files:f,settings:a,total:d,init:function(){var e=this;typeof a.preinit=="function"?a.preinit(e):o.each(a.preinit,function(t,n){e.bind(n,t)}),S.call(this);if(!a.browse_button||!a.url){this.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")});return}x.call(this,a,function(n){typeof a.init=="function"?a.init(e):o.each(a.init,function(t,n){e.bind(n,t)}),n?(e.runtime=t.Runtime.getInfo(w()).type,e.trigger("Init",{runtime:e.runtime}),e.trigger("PostInit")):e.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})})},setOption:function(e,t){N.call(this,e,t,!this.runtime)},getOption:function(e){return e?a[e]:a},refresh:function(){c.length&&o.each(c,function(e){e.trigger("Refresh")}),this.trigger("Refresh")},start:function(){this.state!=o.STARTED&&(this.state=o.STARTED,this.trigger("StateChanged"),g.call(this))},stop:function(){this.state!=o.STOPPED&&(this.state=o.STOPPED,this.trigger("StateChanged"),this.trigger("CancelUpload"))},disableBrowse:function(){v=arguments[0]!==n?arguments[0]:!0,c.length&&o.each(c,function(e){e.disable(v)}),this.trigger("DisableBrowse",v)},getFile:function(e){var t;for(t=f.length-1;t>=0;t--)if(f[t].id===e)return f[t]},addFile:function(e,n){function c(e,n){var r=[];t.each(s.settings.filters,function(t,n){i[n]&&r.push(function(r){i[n].call(s,t,e,function(e){r(!e)})})}),t.inSeries(r,n)}function h(e){var i=t.typeOf(e);if(e instanceof t.File){if(!e.ruid&&!e.isDetached()){if(!l)return!1;e.ruid=l,e.connectRuntime(l)}h(new o.File(e))}else e instanceof t.Blob?(h(e.getSource()),e.destroy()):e instanceof o.File?(n&&(e.name=n),u.push(function(t){c(e,function(n){n||(f.push(e),a.push(e),s.trigger("FileFiltered",e)),r(t,1)})})):t.inArray(i,["file","blob"])!==-1?h(new t.File(null,e)):i==="node"&&t.typeOf(e.files)==="filelist"?t.each(e.files,h):i==="array"&&(n=null,t.each(e,h))}var s=this,u=[],a=[],l;l=w(),h(e),u.length&&t.inSeries(u,function(){a.length&&s.trigger("FilesAdded",a)})},removeFile:function(e){var t=typeof e=="string"?e:e.id;for(var n=f.length-1;n>=0;n--)if(f[n].id===t)return this.splice(n,1)[0]},splice:function(e,t){var r=f.splice(e===n?0:e,t===n?f.length:t),i=!1;return this.state==o.STARTED&&(o.each(r,function(e){if(e.status===o.UPLOADING)return i=!0,!1}),i&&this.stop()),this.trigger("FilesRemoved",r),o.each(r,function(e){e.destroy()}),i&&this.start(),r},dispatchEvent:function(e){var t,n,r;e=e.toLowerCase(),t=this.hasEventListener(e);if(t){t.sort(function(e,t){return t.priority-e.priority}),n=[].slice.call(arguments),n.shift(),n.unshift(this);for(var i=0;i ',
+ all[0]
+ ) {
+ v++;
+ }
+ return v > 4 ? v : false;
+ };
+
+ var logger = {
+ MUTE: 0,
+ FATA: 1,
+ ERROR: 2,
+ WARN: 3,
+ INFO: 4,
+ DEBUG: 5,
+ TRACE: 6,
+ level: 0
+ };
+
+ function log(type, args){
+ var header = "[qiniu-js-sdk]["+type+"]";
+ var msg = header;
+ for (var i = 0; i < args.length; i++) {
+ if (typeof args[i] === "string") {
+ msg += " " + args[i];
+ } else {
+ msg += " " + that.stringifyJSON(args[i]);
+ }
+ }
+ if (that.detectIEVersion()) {
+ // http://stackoverflow.com/questions/5538972/console-log-apply-not-working-in-ie9
+ //var log = Function.prototype.bind.call(console.log, console);
+ //log.apply(console, args);
+ console.log(msg);
+ }else{
+ args.unshift(header);
+ console.log.apply(console, args);
+ }
+ if (document.getElementById('qiniu-js-sdk-log')) {
+ document.getElementById('qiniu-js-sdk-log').innerHTML += ''+msg+'
';
+ }
+ }
+
+ function makeLogFunc(code){
+ var func = code.toLowerCase();
+ logger[func] = function(){
+ // logger[func].history = logger[func].history || [];
+ // logger[func].history.push(arguments);
+ if(window.console && window.console.log && logger.level>=logger[code]){
+ var args = Array.prototype.slice.call(arguments);
+ log(func,args);
+ }
+ };
+ }
+
+ for (var property in logger){
+ if (logger.hasOwnProperty(property) && (typeof logger[property]) === "number" && !logger.hasOwnProperty(property.toLowerCase())) {
+ makeLogFunc(property);
+ }
+ }
+
+
+ var qiniuUploadUrl;
+ if (window.location.protocol === 'https:') {
+ qiniuUploadUrl = 'https://up.qbox.me';
+ } else {
+ qiniuUploadUrl = 'http://upload.qiniu.com';
+ }
+
+ /**
+ * qiniu upload urls
+ * 'qiniuUploadUrls' is used to change target when current url is not avaliable
+ * @type {Array}
+ */
+ var qiniuUploadUrls = [
+ "http://upload.qiniu.com",
+ "http://up.qiniu.com"
+ ];
+
+ var qiniuUpHosts = {
+ "http": [
+ "http://upload.qiniu.com",
+ "http://up.qiniu.com"
+ ],
+ "https": [
+ "https://up.qbox.me"
+ ]
+ };
+
+ var changeUrlTimes = 0;
+
+ /**
+ * reset upload url
+ * if current page protocal is https
+ * it will always return 'https://up.qbox.me'
+ * else
+ * it will set 'qiniuUploadUrl' value with 'qiniuUploadUrls' looply
+ */
+ this.resetUploadUrl = function(){
+ var hosts = window.location.protocol === 'https:' ? qiniuUpHosts.https : qiniuUpHosts.http;
+ var i = changeUrlTimes % hosts.length;
+ qiniuUploadUrl = hosts[i];
+ changeUrlTimes++;
+ logger.debug('resetUploadUrl: '+qiniuUploadUrl);
+ };
+
+ // this.resetUploadUrl();
+
+
+ /**
+ * is image
+ * @param {String} url of a file
+ * @return {Boolean} file is a image or not
+ */
+ this.isImage = function(url) {
+ url = url.split(/[?#]/)[0];
+ return (/\.(png|jpg|jpeg|gif|bmp)$/i).test(url);
+ };
+
+ /**
+ * get file extension
+ * @param {String} filename
+ * @return {String} file extension
+ * @example
+ * input: test.txt
+ * output: txt
+ */
+ this.getFileExtension = function(filename) {
+ var tempArr = filename.split(".");
+ var ext;
+ if (tempArr.length === 1 || (tempArr[0] === "" && tempArr.length === 2)) {
+ ext = "";
+ } else {
+ ext = tempArr.pop().toLowerCase(); //get the extension and make it lower-case
+ }
+ return ext;
+ };
+
+ /**
+ * encode string by utf8
+ * @param {String} string to encode
+ * @return {String} encoded string
+ */
+ this.utf8_encode = function(argString) {
+ // http://kevin.vanzonneveld.net
+ // + original by: Webtoolkit.info (http://www.webtoolkit.info/)
+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // + improved by: sowberry
+ // + tweaked by: Jack
+ // + bugfixed by: Onno Marsman
+ // + improved by: Yves Sucaet
+ // + bugfixed by: Onno Marsman
+ // + bugfixed by: Ulrich
+ // + bugfixed by: Rafal Kukawski
+ // + improved by: kirilloid
+ // + bugfixed by: kirilloid
+ // * example 1: this.utf8_encode('Kevin van Zonneveld');
+ // * returns 1: 'Kevin van Zonneveld'
+
+ if (argString === null || typeof argString === 'undefined') {
+ return '';
+ }
+
+ var string = (argString + ''); // .replace(/\r\n/g, '\n').replace(/\r/g, '\n');
+ var utftext = '',
+ start, end, stringl = 0;
+
+ start = end = 0;
+ stringl = string.length;
+ for (var n = 0; n < stringl; n++) {
+ var c1 = string.charCodeAt(n);
+ var enc = null;
+
+ if (c1 < 128) {
+ end++;
+ } else if (c1 > 127 && c1 < 2048) {
+ enc = String.fromCharCode(
+ (c1 >> 6) | 192, (c1 & 63) | 128
+ );
+ } else if (c1 & 0xF800 ^ 0xD800 > 0) {
+ enc = String.fromCharCode(
+ (c1 >> 12) | 224, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128
+ );
+ } else { // surrogate pairs
+ if (c1 & 0xFC00 ^ 0xD800 > 0) {
+ throw new RangeError('Unmatched trail surrogate at ' + n);
+ }
+ var c2 = string.charCodeAt(++n);
+ if (c2 & 0xFC00 ^ 0xDC00 > 0) {
+ throw new RangeError('Unmatched lead surrogate at ' + (n - 1));
+ }
+ c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000;
+ enc = String.fromCharCode(
+ (c1 >> 18) | 240, ((c1 >> 12) & 63) | 128, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128
+ );
+ }
+ if (enc !== null) {
+ if (end > start) {
+ utftext += string.slice(start, end);
+ }
+ utftext += enc;
+ start = end = n + 1;
+ }
+ }
+
+ if (end > start) {
+ utftext += string.slice(start, stringl);
+ }
+
+ return utftext;
+ };
+
+ this.base64_decode = function (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 dec;
+ };
+
+ /**
+ * encode data by base64
+ * @param {String} data to encode
+ * @return {String} encoded data
+ */
+ this.base64_encode = function(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)
+ // - depends on: this.utf8_encode
+ // * example 1: this.base64_encode('Kevin van Zonneveld');
+ // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
+ // 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,
+ enc = '',
+ tmp_arr = [];
+
+ if (!data) {
+ return data;
+ }
+
+ data = this.utf8_encode(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('');
+
+ switch (data.length % 3) {
+ case 1:
+ enc = enc.slice(0, -2) + '==';
+ break;
+ case 2:
+ enc = enc.slice(0, -1) + '=';
+ break;
+ }
+
+ return enc;
+ };
+
+ /**
+ * encode string in url by base64
+ * @param {String} string in url
+ * @return {String} encoded string
+ */
+ this.URLSafeBase64Encode = function(v) {
+ v = this.base64_encode(v);
+ return v.replace(/\//g, '_').replace(/\+/g, '-');
+ };
+
+ this.URLSafeBase64Decode = function(v) {
+ v = v.replace(/_/g, '/').replace(/-/g, '+');
+ return this.base64_decode(v);
+ };
+
+ // TODO: use mOxie
+ /**
+ * craete object used to AJAX
+ * @return {Object}
+ */
+ this.createAjax = function(argument) {
+ var xmlhttp = {};
+ if (window.XMLHttpRequest) {
+ xmlhttp = new XMLHttpRequest();
+ } else {
+ xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ return xmlhttp;
+ };
+
+ // TODO: enhance IE compatibility
+ /**
+ * parse json string to javascript object
+ * @param {String} json string
+ * @return {Object} object
+ */
+ this.parseJSON = function(data) {
+ // Attempt to parse using the native JSON parser first
+ if (window.JSON && window.JSON.parse) {
+ return window.JSON.parse(data);
+ }
+
+ //var rx_one = /^[\],:{}\s]*$/,
+ // rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+ // rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+ // rx_four = /(?:^|:|,)(?:\s*\[)+/g,
+ var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+
+ //var json;
+
+ var text = String(data);
+ rx_dangerous.lastIndex = 0;
+ if(rx_dangerous.test(text)){
+ text = text.replace(rx_dangerous, function(a){
+ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+ // todo 使用一下判断,增加安全性
+ //if (
+ // rx_one.test(
+ // text
+ // .replace(rx_two, '@')
+ // .replace(rx_three, ']')
+ // .replace(rx_four, '')
+ // )
+ //) {
+ // return eval('(' + text + ')');
+ //}
+
+ return eval('('+text+')');
+ };
+
+ /**
+ * parse javascript object to json string
+ * @param {Object} object
+ * @return {String} json string
+ */
+ this.stringifyJSON = function(obj) {
+ // Attempt to parse using the native JSON parser first
+ if (window.JSON && window.JSON.stringify) {
+ return window.JSON.stringify(obj);
+ }
+ switch (typeof (obj)) {
+ case 'string':
+ return '"' + obj.replace(/(["\\])/g, '\\$1') + '"';
+ case 'array':
+ return '[' + obj.map(that.stringifyJSON).join(',') + ']';
+ case 'object':
+ if (obj instanceof Array) {
+ var strArr = [];
+ var len = obj.length;
+ for (var i = 0; i < len; i++) {
+ strArr.push(that.stringifyJSON(obj[i]));
+ }
+ return '[' + strArr.join(',') + ']';
+ } else if (obj === null) {
+ return 'null';
+ } else {
+ var string = [];
+ for (var property in obj) {
+ if (obj.hasOwnProperty(property)) {
+ string.push(that.stringifyJSON(property) + ':' + that.stringifyJSON(obj[property]));
+ }
+ }
+ return '{' + string.join(',') + '}';
+ }
+ break;
+ case 'number':
+ return obj;
+ case false:
+ return obj;
+ case 'boolean':
+ return obj;
+ }
+ };
+
+ /**
+ * trim space beside text
+ * @param {String} untrimed string
+ * @return {String} trimed string
+ */
+ this.trim = function(text) {
+ return text === null ? "" : text.replace(/^\s+|\s+$/g, '');
+ };
+
+ /**
+ * create a uploader by QiniuJsSDK
+ * @param {object} options to create a new uploader
+ * @return {object} uploader
+ */
+ this.uploader = function(op) {
+
+ /********** inner function define start **********/
+
+ // according the different condition to reset chunk size
+ // and the upload strategy according with the chunk size
+ // when chunk size is zero will cause to direct upload
+ // see the statement binded on 'BeforeUpload' event
+ var reset_chunk_size = function() {
+ var ie = that.detectIEVersion();
+ var BLOCK_BITS, MAX_CHUNK_SIZE, chunk_size;
+ // case Safari 5、Windows 7、iOS 7 set isSpecialSafari to true
+ var isSpecialSafari = (mOxie.Env.browser === "Safari" && mOxie.Env.version <= 5 && mOxie.Env.os === "Windows" && mOxie.Env.osVersion === "7") || (mOxie.Env.browser === "Safari" && mOxie.Env.os === "iOS" && mOxie.Env.osVersion === "7");
+ // case IE 9-,chunk_size is not empty and flash is included in runtimes
+ // set op.chunk_size to zero
+ //if (ie && ie < 9 && op.chunk_size && op.runtimes.indexOf('flash') >= 0) {
+ if (ie && ie < 9 && op.chunk_size && op.runtimes.indexOf('flash') >= 0) {
+ // link: http://www.plupload.com/docs/Frequently-Asked-Questions#when-to-use-chunking-and-when-not
+ // when plupload chunk_size setting is't null ,it cause bug in ie8/9 which runs flash runtimes (not support html5) .
+ op.chunk_size = 0;
+ } else if (isSpecialSafari) {
+ // win7 safari / iOS7 safari have bug when in chunk upload mode
+ // reset chunk_size to 0
+ // disable chunk in special version safari
+ op.chunk_size = 0;
+ } else {
+ BLOCK_BITS = 20;
+ MAX_CHUNK_SIZE = 4 << BLOCK_BITS; //4M
+
+ chunk_size = plupload.parseSize(op.chunk_size);
+ if (chunk_size > MAX_CHUNK_SIZE) {
+ op.chunk_size = MAX_CHUNK_SIZE;
+ }
+ // qiniu service max_chunk_size is 4m
+ // reset chunk_size to max_chunk_size(4m) when chunk_size > 4m
+ }
+ // if op.chunk_size set 0 will be cause to direct upload
+ };
+
+ var getHosts = function(hosts) {
+ var result = [];
+ for (var i = 0; i < hosts.length; i++) {
+ var host = hosts[i];
+ if (host.indexOf('-H') === 0) {
+ result.push(host.split(' ')[2]);
+ } else {
+ result.push(host);
+ }
+ }
+ return result;
+ };
+
+ var getPutPolicy = function (uptoken) {
+ var segments = uptoken.split(":");
+ var ak = segments[0];
+ var putPolicy = that.parseJSON(that.URLSafeBase64Decode(segments[2]));
+ putPolicy.ak = ak;
+ if (putPolicy.scope.indexOf(":") >= 0) {
+ putPolicy.bucket = putPolicy.scope.split(":")[0];
+ putPolicy.key = putPolicy.scope.split(":")[1];
+ } else {
+ putPolicy.bucket = putPolicy.scope;
+ }
+ return putPolicy;
+ };
+
+ var getUpHosts = function(uptoken) {
+ var putPolicy = getPutPolicy(uptoken);
+ // var uphosts_url = "//uc.qbox.me/v1/query?ak="+ak+"&bucket="+putPolicy.scope;
+ // IE 9- is not support protocal relative url
+ var uphosts_url = window.location.protocol + "//uc.qbox.me/v1/query?ak=" + putPolicy.ak + "&bucket=" + putPolicy.bucket;
+ logger.debug("putPolicy: ", putPolicy);
+ logger.debug("get uphosts from: ", uphosts_url);
+ var ie = that.detectIEVersion();
+ var ajax;
+ if (ie && ie <= 9) {
+ ajax = new mOxie.XMLHttpRequest();
+ mOxie.Env.swf_url = op.flash_swf_url;
+ }else{
+ ajax = that.createAjax();
+ }
+ ajax.open('GET', uphosts_url, false);
+ var onreadystatechange = function(){
+ logger.debug("ajax.readyState: ", ajax.readyState);
+ if (ajax.readyState === 4) {
+ logger.debug("ajax.status: ", ajax.status);
+ if (ajax.status < 400) {
+ var res = that.parseJSON(ajax.responseText);
+ qiniuUpHosts.http = getHosts(res.http.up);
+ qiniuUpHosts.https = getHosts(res.https.up);
+ logger.debug("get new uphosts: ", qiniuUpHosts);
+ that.resetUploadUrl();
+ } else {
+ logger.error("get uphosts error: ", ajax.responseText);
+ }
+ }
+ };
+ if (ie && ie <= 9) {
+ ajax.bind('readystatechange', onreadystatechange);
+ }else{
+ ajax.onreadystatechange = onreadystatechange;
+ }
+ ajax.send();
+ // ajax.send();
+ // if (ajax.status < 400) {
+ // var res = that.parseJSON(ajax.responseText);
+ // qiniuUpHosts.http = getHosts(res.http.up);
+ // qiniuUpHosts.https = getHosts(res.https.up);
+ // logger.debug("get new uphosts: ", qiniuUpHosts);
+ // that.resetUploadUrl();
+ // } else {
+ // logger.error("get uphosts error: ", ajax.responseText);
+ // }
+ return;
+ };
+
+ var getUptoken = function(file) {
+ if (!that.token || (op.uptoken_url && that.tokenInfo.isExpired())) {
+ return getNewUpToken(file);
+ } else {
+ return that.token;
+ }
+ };
+
+ // getNewUptoken maybe called at Init Event or BeforeUpload Event
+ // case Init Event, the file param of getUptken will be set a null value
+ // if op.uptoken has value, set uptoken with op.uptoken
+ // else if op.uptoken_url has value, set uptoken from op.uptoken_url
+ // else if op.uptoken_func has value, set uptoken by result of op.uptoken_func
+ var getNewUpToken = function(file) {
+ if (op.uptoken) {
+ that.token = op.uptoken;
+ } else if (op.uptoken_url) {
+ logger.debug("get uptoken from: ", that.uptoken_url);
+ // TODO: use mOxie
+ var ajax = that.createAjax();
+ ajax.open('GET', that.uptoken_url, false);
+ ajax.setRequestHeader("If-Modified-Since", "0");
+ // ajax.onreadystatechange = function() {
+ // if (ajax.readyState === 4 && ajax.status === 200) {
+ // var res = that.parseJSON(ajax.responseText);
+ // that.token = res.uptoken;
+ // }
+ // };
+ ajax.send();
+ if (ajax.status === 200) {
+ var res = that.parseJSON(ajax.responseText);
+ that.token = res.uptoken;
+ var segments = that.token.split(":");
+ var putPolicy = that.parseJSON(that.URLSafeBase64Decode(segments[2]));
+ if (!that.tokenMap) {
+ that.tokenMap = {};
+ }
+ var getTimestamp = function(time) {
+ return Math.ceil(time.getTime()/1000);
+ };
+ var serverTime = getTimestamp(new Date(ajax.getResponseHeader("date")));
+ var clientTime = getTimestamp(new Date());
+ that.tokenInfo = {
+ serverDelay: clientTime - serverTime,
+ deadline: putPolicy.deadline,
+ isExpired: function() {
+ var leftTime = this.deadline - getTimestamp(new Date()) + this.serverDelay;
+ return leftTime < 600;
+ }
+ };
+ logger.debug("get new uptoken: ", that.token);
+ logger.debug("get token info: ", that.tokenInfo);
+ } else {
+ logger.error("get uptoken error: ", ajax.responseText);
+ }
+ } else if (op.uptoken_func) {
+ logger.debug("get uptoken from uptoken_func");
+ that.token = op.uptoken_func(file);
+ logger.debug("get new uptoken: ", that.token);
+ } else {
+ logger.error("one of [uptoken, uptoken_url, uptoken_func] settings in options is required!");
+ }
+ if (that.token) {
+ getUpHosts(that.token);
+ }
+ return that.token;
+ };
+
+ // get file key according with the user passed options
+ var getFileKey = function(up, file, func) {
+ // WARNING
+ // When you set the key in putPolicy by "scope": "bucket:key"
+ // You should understand the risk of override a file in the bucket
+ // So the code below that automatically get key from uptoken has been commented
+ // var putPolicy = getPutPolicy(that.token)
+ // if (putPolicy.key) {
+ // logger.debug("key is defined in putPolicy.scope: ", putPolicy.key)
+ // return putPolicy.key
+ // }
+ var key = '',
+ unique_names = false;
+ if (!op.save_key) {
+ unique_names = up.getOption && up.getOption('unique_names');
+ unique_names = unique_names || (up.settings && up.settings.unique_names);
+ if (unique_names) {
+ var ext = that.getFileExtension(file.name);
+ key = ext ? file.id + '.' + ext : file.id;
+ } else if (typeof func === 'function') {
+ key = func(up, file);
+ } else {
+ key = file.name;
+ }
+ }
+ return key;
+ };
+
+ /********** inner function define end **********/
+
+ if (op.log_level) {
+ logger.level = op.log_level;
+ }
+
+ if (!op.domain) {
+ throw 'domain setting in options is required!';
+ }
+
+ if (!op.browse_button) {
+ throw 'browse_button setting in options is required!';
+ }
+
+ if (!op.uptoken && !op.uptoken_url && !op.uptoken_func) {
+ throw 'one of [uptoken, uptoken_url, uptoken_func] settings in options is required!';
+ }
+
+ logger.debug("init uploader start");
+
+ logger.debug("environment: ", mOxie.Env);
+
+ logger.debug("userAgent: ", navigator.userAgent);
+
+ var option = {};
+
+ // hold the handler from user passed options
+ var _Error_Handler = op.init && op.init.Error;
+ var _FileUploaded_Handler = op.init && op.init.FileUploaded;
+
+ // replace the handler for intercept
+ op.init.Error = function() {};
+ op.init.FileUploaded = function() {};
+
+ that.uptoken_url = op.uptoken_url;
+ that.token = '';
+ that.key_handler = typeof op.init.Key === 'function' ? op.init.Key : '';
+ this.domain = op.domain;
+ // TODO: ctx is global in scope of a uploader instance
+ // this maybe cause error
+ var ctx = '';
+ var speedCalInfo = {
+ isResumeUpload: false,
+ resumeFilesize: 0,
+ startTime: '',
+ currentTime: ''
+ };
+
+ reset_chunk_size();
+ logger.debug("invoke reset_chunk_size()");
+ logger.debug("op.chunk_size: ", op.chunk_size);
+
+ var defaultSetting = {
+ url: qiniuUploadUrl,
+ multipart_params: {
+ token: ''
+ }
+ };
+ var ie = that.detectIEVersion();
+ // case IE 9-
+ // add accept in multipart params
+ if (ie && ie <= 9) {
+ defaultSetting.multipart_params.accept = 'text/plain; charset=utf-8';
+ logger.debug("add accept text/plain in multipart params");
+ }
+
+ // compose options with user passed options and default setting
+ plupload.extend(option, op, defaultSetting);
+
+ logger.debug("option: ", option);
+
+ // create a new uploader with composed options
+ var uploader = new plupload.Uploader(option);
+
+ logger.debug("new plupload.Uploader(option)");
+
+ // bind getNewUpToken to 'Init' event
+ uploader.bind('Init', function(up, params) {
+ logger.debug("Init event activated");
+ // if op.get_new_uptoken is not true
+ // invoke getNewUptoken when uploader init
+ // else
+ // getNewUptoken everytime before a new file upload
+ if(!op.get_new_uptoken){
+ getNewUpToken(null);
+ }
+ //getNewUpToken(null);
+ });
+
+ logger.debug("bind Init event");
+
+ // bind 'FilesAdded' event
+ // when file be added and auto_start has set value
+ // uploader will auto start upload the file
+ uploader.bind('FilesAdded', function(up, files) {
+ logger.debug("FilesAdded event activated");
+ var auto_start = up.getOption && up.getOption('auto_start');
+ auto_start = auto_start || (up.settings && up.settings.auto_start);
+ logger.debug("auto_start: ", auto_start);
+ logger.debug("files: ", files);
+
+ // detect is iOS
+ var is_ios = function (){
+ if(mOxie.Env.OS.toLowerCase()==="ios") {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ // if current env os is iOS change file name to [time].[ext]
+ if (is_ios()) {
+ for (var i = 0; i < files.length; i++) {
+ var file = files[i];
+ var ext = that.getFileExtension(file.name);
+ file.name = file.id + "." + ext;
+ }
+ }
+
+ if (auto_start) {
+ setTimeout(function(){
+ up.start();
+ logger.debug("invoke up.start()");
+ }, 0);
+ // up.start();
+ // plupload.each(files, function(i, file) {
+ // up.start();
+ // logger.debug("invoke up.start()")
+ // logger.debug("file: ", file);
+ // });
+ }
+ up.refresh(); // Reposition Flash/Silverlight
+ });
+
+ logger.debug("bind FilesAdded event");
+
+ // bind 'BeforeUpload' event
+ // intercept the process of upload
+ // - prepare uptoken
+ // - according the chunk size to make differnt upload strategy
+ // - resume upload with the last breakpoint of file
+ uploader.bind('BeforeUpload', function(up, file) {
+ logger.debug("BeforeUpload event activated");
+ // add a key named speed for file object
+ file.speed = file.speed || 0;
+ ctx = '';
+
+ if(op.get_new_uptoken){
+ getNewUpToken(file);
+ }
+
+ var directUpload = function(up, file, func) {
+ speedCalInfo.startTime = new Date().getTime();
+ var multipart_params_obj;
+ if (op.save_key) {
+ multipart_params_obj = {
+ 'token': that.token
+ };
+ } else {
+ multipart_params_obj = {
+ 'key': getFileKey(up, file, func),
+ 'token': that.token
+ };
+ }
+ var ie = that.detectIEVersion();
+ // case IE 9-
+ // add accept in multipart params
+ if (ie && ie <= 9) {
+ multipart_params_obj.accept = 'text/plain; charset=utf-8';
+ logger.debug("add accept text/plain in multipart params");
+ }
+
+ logger.debug("directUpload multipart_params_obj: ", multipart_params_obj);
+
+ var x_vars = op.x_vars;
+ if (x_vars !== undefined && typeof x_vars === 'object') {
+ for (var x_key in x_vars) {
+ if (x_vars.hasOwnProperty(x_key)) {
+ if (typeof x_vars[x_key] === 'function') {
+ multipart_params_obj['x:' + x_key] = x_vars[x_key](up, file);
+ } else if (typeof x_vars[x_key] !== 'object') {
+ multipart_params_obj['x:' + x_key] = x_vars[x_key];
+ }
+ }
+ }
+ }
+
+ up.setOption({
+ 'url': qiniuUploadUrl,
+ 'multipart': true,
+ 'chunk_size': is_android_weixin_or_qq() ? op.max_file_size : undefined,
+ 'multipart_params': multipart_params_obj
+ });
+ };
+
+ // detect is weixin or qq inner browser
+ var is_android_weixin_or_qq = function (){
+ var ua = navigator.userAgent.toLowerCase();
+ if((ua.match(/MicroMessenger/i) || mOxie.Env.browser === "QQBrowser" || ua.match(/V1_AND_SQ/i)) && mOxie.Env.OS.toLowerCase()==="android") {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ var chunk_size = up.getOption && up.getOption('chunk_size');
+ chunk_size = chunk_size || (up.settings && up.settings.chunk_size);
+
+ logger.debug("uploader.runtime: ",uploader.runtime);
+ logger.debug("chunk_size: ",chunk_size);
+
+ // TODO: flash support chunk upload
+ if ((uploader.runtime === 'html5' || uploader.runtime === 'flash') && chunk_size) {
+ if (file.size < chunk_size || is_android_weixin_or_qq()) {
+ logger.debug("directUpload because file.size < chunk_size || is_android_weixin_or_qq()");
+ // direct upload if file size is less then the chunk size
+ directUpload(up, file, that.key_handler);
+ } else {
+ // TODO: need a polifill to make it work in IE 9-
+ // ISSUE: if file.name is existed in localStorage
+ // but not the same file maybe cause error
+ var localFileInfo = localStorage.getItem(file.name);
+ var blockSize = chunk_size;
+ if (localFileInfo) {
+ // TODO: although only the html5 runtime will enter this statement
+ // but need uniform way to make convertion between string and json
+ localFileInfo = that.parseJSON(localFileInfo);
+ var now = (new Date()).getTime();
+ var before = localFileInfo.time || 0;
+ var aDay = 24 * 60 * 60 * 1000; // milliseconds of one day
+ // if the last upload time is within one day
+ // will upload continuously follow the last breakpoint
+ // else
+ // will reupload entire file
+ if (now - before < aDay) {
+
+ if (localFileInfo.percent !== 100) {
+ if (file.size === localFileInfo.total) {
+ // TODO: if file.name and file.size is the same
+ // but not the same file will cause error
+ file.percent = localFileInfo.percent;
+ file.loaded = localFileInfo.offset;
+ ctx = localFileInfo.ctx;
+
+ // set speed info
+ speedCalInfo.isResumeUpload = true;
+ speedCalInfo.resumeFilesize = localFileInfo.offset;
+
+ // set block size
+ if (localFileInfo.offset + blockSize > file.size) {
+ blockSize = file.size - localFileInfo.offset;
+ }
+ } else {
+ // remove file info when file.size is conflict with file info
+ localStorage.removeItem(file.name);
+ }
+
+ } else {
+ // remove file info when upload percent is 100%
+ // avoid 499 bug
+ localStorage.removeItem(file.name);
+ }
+ } else {
+ // remove file info when last upload time is over one day
+ localStorage.removeItem(file.name);
+ }
+ }
+ speedCalInfo.startTime = new Date().getTime();
+ var multipart_params_obj = {};
+ var ie = that.detectIEVersion();
+ // case IE 9-
+ // add accept in multipart params
+ if (ie && ie <= 9) {
+ multipart_params_obj.accept = 'text/plain; charset=utf-8';
+ logger.debug("add accept text/plain in multipart params");
+ }
+ // TODO: to support bput
+ // http://developer.qiniu.com/docs/v6/api/reference/up/bput.html
+ up.setOption({
+ 'url': qiniuUploadUrl + '/mkblk/' + blockSize,
+ 'multipart': false,
+ 'chunk_size': chunk_size,
+ 'required_features': "chunks",
+ 'headers': {
+ 'Authorization': 'UpToken ' + getUptoken(file)
+ },
+ 'multipart_params': multipart_params_obj
+ });
+ }
+ } else {
+ logger.debug("directUpload because uploader.runtime !== 'html5' || uploader.runtime !== 'flash' || !chunk_size");
+ // direct upload if runtime is not html5
+ directUpload(up, file, that.key_handler);
+ }
+ });
+
+ logger.debug("bind BeforeUpload event");
+
+ // bind 'UploadProgress' event
+ // calculate upload speed
+ uploader.bind('UploadProgress', function(up, file) {
+ logger.trace("UploadProgress event activated");
+ speedCalInfo.currentTime = new Date().getTime();
+ var timeUsed = speedCalInfo.currentTime - speedCalInfo.startTime; // ms
+ var fileUploaded = file.loaded || 0;
+ if (speedCalInfo.isResumeUpload) {
+ fileUploaded = file.loaded - speedCalInfo.resumeFilesize;
+ }
+ file.speed = (fileUploaded / timeUsed * 1000).toFixed(0) || 0; // unit: byte/s
+ });
+
+ logger.debug("bind UploadProgress event");
+
+ // bind 'ChunkUploaded' event
+ // store the chunk upload info and set next chunk upload url
+ uploader.bind('ChunkUploaded', function(up, file, info) {
+ logger.debug("ChunkUploaded event activated");
+ logger.debug("file: ", file);
+ logger.debug("info: ", info);
+ var res = that.parseJSON(info.response);
+ logger.debug("res: ", res);
+ // ctx should look like '[chunk01_ctx],[chunk02_ctx],[chunk03_ctx],...'
+ ctx = ctx ? ctx + ',' + res.ctx : res.ctx;
+ var leftSize = info.total - info.offset;
+ var chunk_size = up.getOption && up.getOption('chunk_size');
+ chunk_size = chunk_size || (up.settings && up.settings.chunk_size);
+ if (leftSize < chunk_size) {
+ up.setOption({
+ 'url': qiniuUploadUrl + '/mkblk/' + leftSize
+ });
+ logger.debug("up.setOption url: ", qiniuUploadUrl + '/mkblk/' + leftSize);
+ }
+ up.setOption({
+ 'headers': {
+ 'Authorization': 'UpToken ' + getUptoken(file)
+ }
+ });
+ localStorage.setItem(file.name, that.stringifyJSON({
+ ctx: ctx,
+ percent: file.percent,
+ total: info.total,
+ offset: info.offset,
+ time: (new Date()).getTime()
+ }));
+ });
+
+ logger.debug("bind ChunkUploaded event");
+
+ var retries = qiniuUploadUrls.length;
+
+ // if error is unkown switch upload url and retry
+ var unknow_error_retry = function(file){
+ if (retries-- > 0) {
+ setTimeout(function(){
+ that.resetUploadUrl();
+ file.status = plupload.QUEUED;
+ uploader.stop();
+ uploader.start();
+ }, 0);
+ return true;
+ }else{
+ retries = qiniuUploadUrls.length;
+ return false;
+ }
+ };
+
+ // bind 'Error' event
+ // check the err.code and return the errTip
+ uploader.bind('Error', (function(_Error_Handler) {
+ return function(up, err) {
+ logger.error("Error event activated");
+ logger.error("err: ", err);
+ var errTip = '';
+ var file = err.file;
+ if (file) {
+ switch (err.code) {
+ case plupload.FAILED:
+ errTip = '上传失败。请稍后再试。';
+ break;
+ case plupload.FILE_SIZE_ERROR:
+ var max_file_size = up.getOption && up.getOption('max_file_size');
+ max_file_size = max_file_size || (up.settings && up.settings.max_file_size);
+ errTip = '浏览器最大可上传' + max_file_size + '。更大文件请使用命令行工具。';
+ break;
+ case plupload.FILE_EXTENSION_ERROR:
+ errTip = '文件验证失败。请稍后重试。';
+ break;
+ case plupload.HTTP_ERROR:
+ if (err.response === '') {
+ // Fix parseJSON error ,when http error is like net::ERR_ADDRESS_UNREACHABLE
+ errTip = err.message || '未知网络错误。';
+ if (!unknow_error_retry(file)) {
+ return;
+ }
+ break;
+ }
+ var errorObj = that.parseJSON(err.response);
+ var errorText = errorObj.error;
+ switch (err.status) {
+ case 400:
+ errTip = "请求报文格式错误。";
+ break;
+ case 401:
+ errTip = "客户端认证授权失败。请重试或提交反馈。";
+ break;
+ case 405:
+ errTip = "客户端请求错误。请重试或提交反馈。";
+ break;
+ case 579:
+ errTip = "资源上传成功,但回调失败。";
+ break;
+ case 599:
+ errTip = "网络连接异常。请重试或提交反馈。";
+ if (!unknow_error_retry(file)) {
+ return;
+ }
+ break;
+ case 614:
+ errTip = "文件已存在。";
+ try {
+ errorObj = that.parseJSON(errorObj.error);
+ errorText = errorObj.error || 'file exists';
+ } catch (e) {
+ errorText = errorObj.error || 'file exists';
+ }
+ break;
+ case 631:
+ errTip = "指定空间不存在。";
+ break;
+ case 701:
+ errTip = "上传数据块校验出错。请重试或提交反馈。";
+ break;
+ default:
+ errTip = "未知错误。";
+ if (!unknow_error_retry(file)) {
+ return;
+ }
+ break;
+ }
+ errTip = errTip + '(' + err.status + ':' + errorText + ')';
+ break;
+ case plupload.SECURITY_ERROR:
+ errTip = '安全配置错误。请联系网站管理员。';
+ break;
+ case plupload.GENERIC_ERROR:
+ errTip = '上传失败。请稍后再试。';
+ break;
+ case plupload.IO_ERROR:
+ errTip = '上传失败。请稍后再试。';
+ break;
+ case plupload.INIT_ERROR:
+ errTip = '网站配置错误。请联系网站管理员。';
+ uploader.destroy();
+ break;
+ default:
+ errTip = err.message + err.details;
+ if (!unknow_error_retry(file)) {
+ return;
+ }
+ break;
+ }
+ if (_Error_Handler) {
+ _Error_Handler(up, err, errTip);
+ }
+ }
+ up.refresh(); // Reposition Flash/Silverlight
+ };
+ })(_Error_Handler));
+
+ logger.debug("bind Error event");
+
+ // bind 'FileUploaded' event
+ // intercept the complete of upload
+ // - get downtoken from downtoken_url if bucket is private
+ // - invoke mkfile api to compose chunks if upload strategy is chunk upload
+ uploader.bind('FileUploaded', (function(_FileUploaded_Handler) {
+ return function(up, file, info) {
+ logger.debug("FileUploaded event activated");
+ logger.debug("file: ", file);
+ logger.debug("info: ", info);
+ var last_step = function(up, file, info) {
+ if (op.downtoken_url) {
+ // if op.dowontoken_url is not empty
+ // need get downtoken before invoke the _FileUploaded_Handler
+ var ajax_downtoken = that.createAjax();
+ ajax_downtoken.open('POST', op.downtoken_url, true);
+ ajax_downtoken.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+ ajax_downtoken.onreadystatechange = function() {
+ if (ajax_downtoken.readyState === 4) {
+ if (ajax_downtoken.status === 200) {
+ var res_downtoken;
+ try {
+ res_downtoken = that.parseJSON(ajax_downtoken.responseText);
+ } catch (e) {
+ throw ('invalid json format');
+ }
+ var info_extended = {};
+ plupload.extend(info_extended, that.parseJSON(info), res_downtoken);
+ if (_FileUploaded_Handler) {
+ _FileUploaded_Handler(up, file, that.stringifyJSON(info_extended));
+ }
+ } else {
+ uploader.trigger('Error', {
+ status: ajax_downtoken.status,
+ response: ajax_downtoken.responseText,
+ file: file,
+ code: plupload.HTTP_ERROR
+ });
+ }
+ }
+ };
+ ajax_downtoken.send('key=' + that.parseJSON(info).key + '&domain=' + op.domain);
+ } else if (_FileUploaded_Handler) {
+ _FileUploaded_Handler(up, file, info);
+ }
+ };
+
+ var res = that.parseJSON(info.response);
+ ctx = ctx ? ctx : res.ctx;
+ // if ctx is not empty
+ // that means the upload strategy is chunk upload
+ // befroe the invoke the last_step
+ // we need request the mkfile to compose all uploaded chunks
+ // else
+ // invalke the last_step
+ logger.debug("ctx: ", ctx);
+ if (ctx) {
+ var key = '';
+ logger.debug("save_key: ", op.save_key);
+ if (!op.save_key) {
+ key = getFileKey(up, file, that.key_handler);
+ key = key ? '/key/' + that.URLSafeBase64Encode(key) : '';
+ }
+
+ var fname = '/fname/' + that.URLSafeBase64Encode(file.name);
+
+ logger.debug("op.x_vars: ", op.x_vars);
+ var x_vars = op.x_vars,
+ x_val = '',
+ x_vars_url = '';
+ if (x_vars !== undefined && typeof x_vars === 'object') {
+ for (var x_key in x_vars) {
+ if (x_vars.hasOwnProperty(x_key)) {
+ if (typeof x_vars[x_key] === 'function') {
+ x_val = that.URLSafeBase64Encode(x_vars[x_key](up, file));
+ } else if (typeof x_vars[x_key] !== 'object') {
+ x_val = that.URLSafeBase64Encode(x_vars[x_key]);
+ }
+ x_vars_url += '/x:' + x_key + '/' + x_val;
+ }
+ }
+ }
+
+ var url = qiniuUploadUrl + '/mkfile/' + file.size + key + fname + x_vars_url;
+
+ var ie = that.detectIEVersion();
+ var ajax;
+ if (ie && ie <= 9) {
+ ajax = new mOxie.XMLHttpRequest();
+ mOxie.Env.swf_url = op.flash_swf_url;
+ }else{
+ ajax = that.createAjax();
+ }
+ ajax.open('POST', url, true);
+ ajax.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
+ ajax.setRequestHeader('Authorization', 'UpToken ' + that.token);
+ var onreadystatechange = function(){
+ logger.debug("ajax.readyState: ", ajax.readyState);
+ if (ajax.readyState === 4) {
+ localStorage.removeItem(file.name);
+ var info;
+ if (ajax.status === 200) {
+ info = ajax.responseText;
+ logger.debug("mkfile is success: ", info);
+ last_step(up, file, info);
+ } else {
+ info = {
+ status: ajax.status,
+ response: ajax.responseText,
+ file: file,
+ code: -200,
+ responseHeaders: ajax.getAllResponseHeaders()
+ };
+ logger.debug("mkfile is error: ", info);
+ uploader.trigger('Error', info);
+ }
+ }
+ };
+ if (ie && ie <= 9) {
+ ajax.bind('readystatechange', onreadystatechange);
+ }else{
+ ajax.onreadystatechange = onreadystatechange;
+ }
+ ajax.send(ctx);
+ logger.debug("mkfile: ", url);
+ } else {
+ last_step(up, file, info.response);
+ }
+
+ };
+ })(_FileUploaded_Handler));
+
+ logger.debug("bind FileUploaded event");
+
+ // init uploader
+ uploader.init();
+
+ logger.debug("invoke uploader.init()");
+
+ logger.debug("init uploader end");
+
+ return uploader;
+ };
+
+ /**
+ * get url by key
+ * @param {String} key of file
+ * @return {String} url of file
+ */
+ this.getUrl = function(key) {
+ if (!key) {
+ return false;
+ }
+ key = encodeURI(key);
+ var domain = this.domain;
+ if (domain.slice(domain.length - 1) !== '/') {
+ domain = domain + '/';
+ }
+ return domain + key;
+ };
+
+ /**
+ * invoke the imageView2 api of Qiniu
+ * @param {Object} api params
+ * @param {String} key of file
+ * @return {String} url of processed image
+ */
+ this.imageView2 = function(op, key) {
+
+ if (!/^\d$/.test(op.mode)) {
+ return false;
+ }
+
+ var mode = op.mode,
+ w = op.w || '',
+ h = op.h || '',
+ q = op.q || '',
+ format = op.format || '';
+
+ if (!w && !h) {
+ return false;
+ }
+
+ var imageUrl = 'imageView2/' + mode;
+ imageUrl += w ? '/w/' + w : '';
+ imageUrl += h ? '/h/' + h : '';
+ imageUrl += q ? '/q/' + q : '';
+ imageUrl += format ? '/format/' + format : '';
+ if (key) {
+ imageUrl = this.getUrl(key) + '?' + imageUrl;
+ }
+ return imageUrl;
+ };
+
+ /**
+ * invoke the imageMogr2 api of Qiniu
+ * @param {Object} api params
+ * @param {String} key of file
+ * @return {String} url of processed image
+ */
+ this.imageMogr2 = function(op, key) {
+ var auto_orient = op['auto-orient'] || '',
+ thumbnail = op.thumbnail || '',
+ strip = op.strip || '',
+ gravity = op.gravity || '',
+ crop = op.crop || '',
+ quality = op.quality || '',
+ rotate = op.rotate || '',
+ format = op.format || '',
+ blur = op.blur || '';
+ //Todo check option
+
+ var imageUrl = 'imageMogr2';
+
+ imageUrl += auto_orient ? '/auto-orient' : '';
+ imageUrl += thumbnail ? '/thumbnail/' + thumbnail : '';
+ imageUrl += strip ? '/strip' : '';
+ imageUrl += gravity ? '/gravity/' + gravity : '';
+ imageUrl += quality ? '/quality/' + quality : '';
+ imageUrl += crop ? '/crop/' + crop : '';
+ imageUrl += rotate ? '/rotate/' + rotate : '';
+ imageUrl += format ? '/format/' + format : '';
+ imageUrl += blur ? '/blur/' + blur : '';
+
+ if (key) {
+ imageUrl = this.getUrl(key) + '?' + imageUrl;
+ }
+ return imageUrl;
+ };
+
+ /**
+ * invoke the watermark api of Qiniu
+ * @param {Object} api params
+ * @param {String} key of file
+ * @return {String} url of processed image
+ */
+ this.watermark = function(op, key) {
+ var mode = op.mode;
+ if (!mode) {
+ return false;
+ }
+
+ var imageUrl = 'watermark/' + mode;
+
+ if (mode === 1) {
+ var image = op.image || '';
+ if (!image) {
+ return false;
+ }
+ imageUrl += image ? '/image/' + this.URLSafeBase64Encode(image) : '';
+ } else if (mode === 2) {
+ var text = op.text ? op.text : '',
+ font = op.font ? op.font : '',
+ fontsize = op.fontsize ? op.fontsize : '',
+ fill = op.fill ? op.fill : '';
+ if (!text) {
+ return false;
+ }
+ imageUrl += text ? '/text/' + this.URLSafeBase64Encode(text) : '';
+ imageUrl += font ? '/font/' + this.URLSafeBase64Encode(font) : '';
+ imageUrl += fontsize ? '/fontsize/' + fontsize : '';
+ imageUrl += fill ? '/fill/' + this.URLSafeBase64Encode(fill) : '';
+ } else {
+ // Todo mode3
+ return false;
+ }
+
+ var dissolve = op.dissolve || '',
+ gravity = op.gravity || '',
+ dx = op.dx || '',
+ dy = op.dy || '';
+
+ imageUrl += dissolve ? '/dissolve/' + dissolve : '';
+ imageUrl += gravity ? '/gravity/' + gravity : '';
+ imageUrl += dx ? '/dx/' + dx : '';
+ imageUrl += dy ? '/dy/' + dy : '';
+
+ if (key) {
+ imageUrl = this.getUrl(key) + '?' + imageUrl;
+ }
+ return imageUrl;
+ };
+
+ /**
+ * invoke the imageInfo api of Qiniu
+ * @param {String} key of file
+ * @return {Object} image info
+ */
+ this.imageInfo = function(key) {
+ if (!key) {
+ return false;
+ }
+ var url = this.getUrl(key) + '?imageInfo';
+ var xhr = this.createAjax();
+ var info;
+ var that = this;
+ xhr.open('GET', url, false);
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4 && xhr.status === 200) {
+ info = that.parseJSON(xhr.responseText);
+ }
+ };
+ xhr.send();
+ return info;
+ };
+
+ /**
+ * invoke the exif api of Qiniu
+ * @param {String} key of file
+ * @return {Object} image exif
+ */
+ this.exif = function(key) {
+ if (!key) {
+ return false;
+ }
+ var url = this.getUrl(key) + '?exif';
+ var xhr = this.createAjax();
+ var info;
+ var that = this;
+ xhr.open('GET', url, false);
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4 && xhr.status === 200) {
+ info = that.parseJSON(xhr.responseText);
+ }
+ };
+ xhr.send();
+ return info;
+ };
+
+ /**
+ * invoke the exif or imageInfo api of Qiniu
+ * according with type param
+ * @param {String} ['exif'|'imageInfo']type of info
+ * @param {String} key of file
+ * @return {Object} image exif or info
+ */
+ this.get = function(type, key) {
+ if (!key || !type) {
+ return false;
+ }
+ if (type === 'exif') {
+ return this.exif(key);
+ } else if (type === 'imageInfo') {
+ return this.imageInfo(key);
+ }
+ return false;
+ };
+
+ /**
+ * invoke api of Qiniu like a pipeline
+ * @param {Array of Object} params of a series api call
+ * each object in array is options of api which name is set as 'fop' property
+ * each api's output will be next api's input
+ * @param {String} key of file
+ * @return {String|Boolean} url of processed image
+ */
+ this.pipeline = function(arr, key) {
+ var isArray = Object.prototype.toString.call(arr) === '[object Array]';
+ var option, errOp, imageUrl = '';
+ if (isArray) {
+ for (var i = 0, len = arr.length; i < len; i++) {
+ option = arr[i];
+ if (!option.fop) {
+ return false;
+ }
+ switch (option.fop) {
+ case 'watermark':
+ imageUrl += this.watermark(option) + '|';
+ break;
+ case 'imageView2':
+ imageUrl += this.imageView2(option) + '|';
+ break;
+ case 'imageMogr2':
+ imageUrl += this.imageMogr2(option) + '|';
+ break;
+ default:
+ errOp = true;
+ break;
+ }
+ if (errOp) {
+ return false;
+ }
+ }
+ if (key) {
+ imageUrl = this.getUrl(key) + '?' + imageUrl;
+ var length = imageUrl.length;
+ if (imageUrl.slice(length - 1) === '|') {
+ imageUrl = imageUrl.slice(0, length - 1);
+ }
+ }
+ return imageUrl;
+ }
+ return false;
+ };
+}
+
+var Qiniu = new QiniuJsSDK();
+
+global.Qiniu = Qiniu;
+
+global.QiniuJsSDK = QiniuJsSDK;
+
+})( window );
diff --git a/qiniu_fields/static/qiniu_fields/qiniu/qiniu.min.js b/qiniu_fields/static/qiniu_fields/qiniu/qiniu.min.js
new file mode 100755
index 0000000..15b6508
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/qiniu/qiniu.min.js
@@ -0,0 +1,3 @@
+/*! qiniu-js v1.0.19 | Copyright 2015 by Qiniu */
+!function(global){function createCookie(a,b,c){var d=new Date;d.setTime(d.getTime()+24*c*60*60*1e3);var e="; expires="+d.toGMTString();document.cookie=a+"="+b+e+"; path=/"}function readCookie(a){var b=a+"=";var c=document.cookie.split(";");for(var d=0,e=c.length;e>d;d++){var f=c[d];while(" "===f.charAt(0))f=f.substring(1,f.length);if(0===f.indexOf(b))return f.substring(b.length,f.length)}return null}window.localStorage||(window.localStorage={setItem:function(a,b){createCookie(a,b,30)},getItem:function(a){return readCookie(a)},removeItem:function(a){createCookie(a,"",-1)}});function QiniuJsSDK(){var that=this;this.detectIEVersion=function(){var a=4,b=document.createElement("div"),c=b.getElementsByTagName("i");while(b.innerHTML="",c[0])a++;return a>4?a:!1};var logger={MUTE:0,FATA:1,ERROR:2,WARN:3,INFO:4,DEBUG:5,TRACE:6,level:0};function log(a,b){var c="[qiniu-js-sdk]["+a+"]";var d=c;for(var e=0;e"+d+"
")}function makeLogFunc(a){var b=a.toLowerCase();logger[b]=function(){if(window.console&&window.console.log&&logger.level>=logger[a]){var c=Array.prototype.slice.call(arguments);log(b,c)}}}for(var property in logger)logger.hasOwnProperty(property)&&"number"==typeof logger[property]&&!logger.hasOwnProperty(property.toLowerCase())&&makeLogFunc(property);var qiniuUploadUrl;qiniuUploadUrl="https:"===window.location.protocol?"https://up.qbox.me":"http://upload.qiniu.com";var qiniuUploadUrls=["http://upload.qiniu.com","http://up.qiniu.com"];var qiniuUpHosts={http:["http://upload.qiniu.com","http://up.qiniu.com"],https:["https://up.qbox.me"]};var changeUrlTimes=0;this.resetUploadUrl=function(){var a="https:"===window.location.protocol?qiniuUpHosts.https:qiniuUpHosts.http;var b=changeUrlTimes%a.length;qiniuUploadUrl=a[b],changeUrlTimes++,logger.debug("resetUploadUrl: "+qiniuUploadUrl)},this.isImage=function(a){return a=a.split(/[?#]/)[0],/\.(png|jpg|jpeg|gif|bmp)$/i.test(a)},this.getFileExtension=function(a){var b=a.split(".");var c;return c=1===b.length||""===b[0]&&2===b.length?"":b.pop().toLowerCase()},this.utf8_encode=function(a){if(null===a||"undefined"==typeof a)return"";var b=a+"";var c="",d,e,f=0;d=e=0,f=b.length;for(var g=0;f>g;g++){var h=b.charCodeAt(g);var i=null;if(128>h)e++;else if(h>127&&2048>h)i=String.fromCharCode(h>>6|192,63&h|128);else if(63488&h^!0)i=String.fromCharCode(h>>12|224,h>>6&63|128,63&h|128);else{if(64512&h^!0)throw new RangeError("Unmatched trail surrogate at "+g);var j=b.charCodeAt(++g);if(64512&j^!0)throw new RangeError("Unmatched lead surrogate at "+(g-1));h=((1023&h)<<10)+(1023&j)+65536,i=String.fromCharCode(h>>18|240,h>>12&63|128,h>>6&63|128,63&h|128)}null!==i&&(e>d&&(c+=b.slice(d,e)),c+=i,d=e=g+1)}return e>d&&(c+=b.slice(d,f)),c},this.base64_decode=function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var c,d,e,f,g,h,i,j,k=0,l=0,m="",n=[];if(!a)return a;a+="";do f=b.indexOf(a.charAt(k++)),g=b.indexOf(a.charAt(k++)),h=b.indexOf(a.charAt(k++)),i=b.indexOf(a.charAt(k++)),j=f<<18|g<<12|h<<6|i,c=j>>16&255,d=j>>8&255,e=255&j,64===h?n[l++]=String.fromCharCode(c):64===i?n[l++]=String.fromCharCode(c,d):n[l++]=String.fromCharCode(c,d,e);while(k>18&63,g=j>>12&63,h=j>>6&63,i=63&j,n[l++]=b.charAt(f)+b.charAt(g)+b.charAt(h)+b.charAt(i);while(kd;d++)b.push(that.stringifyJSON(a[d]));return"["+b.join(",")+"]"}if(null===a)return"null";var e=[];for(var f in a)a.hasOwnProperty(f)&&e.push(that.stringifyJSON(f)+":"+that.stringifyJSON(a[f]));return"{"+e.join(",")+"}";case"number":return a;case!1:return a;case"boolean":return a}},this.trim=function(a){return null===a?"":a.replace(/^\s+|\s+$/g,"")},this.uploader=function(a){var b=function(){var b=that.detectIEVersion();var c,d,e;var f="Safari"===mOxie.Env.browser&&mOxie.Env.version<=5&&"Windows"===mOxie.Env.os&&"7"===mOxie.Env.osVersion||"Safari"===mOxie.Env.browser&&"iOS"===mOxie.Env.os&&"7"===mOxie.Env.osVersion;b&&9>b&&a.chunk_size&&a.runtimes.indexOf("flash")>=0?a.chunk_size=0:f?a.chunk_size=0:(c=20,d=4<d&&(a.chunk_size=d))};var c=function(a){var b=[];for(var c=0;c=0?(d.bucket=d.scope.split(":")[0],d.key=d.scope.split(":")[1]):d.bucket=d.scope,d};var e=function(b){var e=d(b);var f=window.location.protocol+"//uc.qbox.me/v1/query?ak="+e.ak+"&bucket="+e.bucket;logger.debug("putPolicy: ",e),logger.debug("get uphosts from: ",f);var g=that.detectIEVersion();var h;g&&9>=g?(h=new mOxie.XMLHttpRequest,mOxie.Env.swf_url=a.flash_swf_url):h=that.createAjax(),h.open("GET",f,!1);var i=function(){if(logger.debug("ajax.readyState: ",h.readyState),4===h.readyState)if(logger.debug("ajax.status: ",h.status),h.status<400){var a=that.parseJSON(h.responseText);qiniuUpHosts.http=c(a.http.up),qiniuUpHosts.https=c(a.https.up),logger.debug("get new uphosts: ",qiniuUpHosts),that.resetUploadUrl()}else logger.error("get uphosts error: ",h.responseText)};g&&9>=g?h.bind("readystatechange",i):h.onreadystatechange=i,h.send()};var f=function(b){return!that.token||a.uptoken_url&&that.tokenInfo.isExpired()?g(b):that.token};var g=function(b){if(a.uptoken)that.token=a.uptoken;else if(a.uptoken_url){logger.debug("get uptoken from: ",that.uptoken_url);var c=that.createAjax();if(c.open("GET",that.uptoken_url,!1),c.setRequestHeader("If-Modified-Since","0"),c.send(),200===c.status){var d=that.parseJSON(c.responseText);that.token=d.uptoken;var f=that.token.split(":");var g=that.parseJSON(that.URLSafeBase64Decode(f[2]));that.tokenMap||(that.tokenMap={});var h=function(a){return Math.ceil(a.getTime()/1e3)};var i=h(new Date(c.getResponseHeader("date")));var j=h(new Date);that.tokenInfo={serverDelay:j-i,deadline:g.deadline,isExpired:function(){var a=this.deadline-h(new Date)+this.serverDelay;return 600>a}},logger.debug("get new uptoken: ",that.token),logger.debug("get token info: ",that.tokenInfo)}else logger.error("get uptoken error: ",c.responseText)}else a.uptoken_func?(logger.debug("get uptoken from uptoken_func"),that.token=a.uptoken_func(b),logger.debug("get new uptoken: ",that.token)):logger.error("one of [uptoken, uptoken_url, uptoken_func] settings in options is required!");return that.token&&e(that.token),that.token};var h=function(b,c,d){var e="",f=!1;if(!a.save_key)if(f=b.getOption&&b.getOption("unique_names"),f=f||b.settings&&b.settings.unique_names){var g=that.getFileExtension(c.name);e=g?c.id+"."+g:c.id}else e="function"==typeof d?d(b,c):c.name;return e};if(a.log_level&&(logger.level=a.log_level),!a.domain)throw"domain setting in options is required!";if(!a.browse_button)throw"browse_button setting in options is required!";if(!a.uptoken&&!a.uptoken_url&&!a.uptoken_func)throw"one of [uptoken, uptoken_url, uptoken_func] settings in options is required!";logger.debug("init uploader start"),logger.debug("environment: ",mOxie.Env),logger.debug("userAgent: ",navigator.userAgent);var i={};var j=a.init&&a.init.Error;var k=a.init&&a.init.FileUploaded;a.init.Error=function(){},a.init.FileUploaded=function(){},that.uptoken_url=a.uptoken_url,that.token="",that.key_handler="function"==typeof a.init.Key?a.init.Key:"",this.domain=a.domain;var l="";var m={isResumeUpload:!1,resumeFilesize:0,startTime:"",currentTime:""};b(),logger.debug("invoke reset_chunk_size()"),logger.debug("op.chunk_size: ",a.chunk_size);var n={url:qiniuUploadUrl,multipart_params:{token:""}};var o=that.detectIEVersion();o&&9>=o&&(n.multipart_params.accept="text/plain; charset=utf-8",logger.debug("add accept text/plain in multipart params")),plupload.extend(i,a,n),logger.debug("option: ",i);var p=new plupload.Uploader(i);logger.debug("new plupload.Uploader(option)"),p.bind("Init",function(b,c){logger.debug("Init event activated"),a.get_new_uptoken||g(null)}),logger.debug("bind Init event"),p.bind("FilesAdded",function(a,b){logger.debug("FilesAdded event activated");var c=a.getOption&&a.getOption("auto_start");c=c||a.settings&&a.settings.auto_start,logger.debug("auto_start: ",c),logger.debug("files: ",b);var d=function(){return"ios"===mOxie.Env.OS.toLowerCase()?!0:!1};if(d())for(var e=0;e=g&&(f.accept="text/plain; charset=utf-8",logger.debug("add accept text/plain in multipart params")),logger.debug("directUpload multipart_params_obj: ",f);var i=a.x_vars;if(void 0!==i&&"object"==typeof i)for(var j in i)i.hasOwnProperty(j)&&("function"==typeof i[j]?f["x:"+j]=i[j](b,c):"object"!=typeof i[j]&&(f["x:"+j]=i[j]));b.setOption({url:qiniuUploadUrl,multipart:!0,chunk_size:e()?a.max_file_size:void 0,multipart_params:f})};var e=function(){var a=navigator.userAgent.toLowerCase();return(a.match(/MicroMessenger/i)||"QQBrowser"===mOxie.Env.browser||a.match(/V1_AND_SQ/i))&&"android"===mOxie.Env.OS.toLowerCase()?!0:!1};var i=b.getOption&&b.getOption("chunk_size");if(i=i||b.settings&&b.settings.chunk_size,logger.debug("uploader.runtime: ",p.runtime),logger.debug("chunk_size: ",i),"html5"!==p.runtime&&"flash"!==p.runtime||!i)logger.debug("directUpload because uploader.runtime !== 'html5' || uploader.runtime !== 'flash' || !chunk_size"),d(b,c,that.key_handler);else if(c.sizen-o&&100!==j.percent&&c.size===j.total?(c.percent=j.percent,c.loaded=j.offset,l=j.ctx,m.isResumeUpload=!0,m.resumeFilesize=j.offset,j.offset+k>c.size&&(k=c.size-j.offset)):localStorage.removeItem(c.name)}m.startTime=(new Date).getTime();var r={};var s=that.detectIEVersion();s&&9>=s&&(r.accept="text/plain; charset=utf-8",logger.debug("add accept text/plain in multipart params")),b.setOption({url:qiniuUploadUrl+"/mkblk/"+k,multipart:!1,chunk_size:i,required_features:"chunks",headers:{Authorization:"UpToken "+f(c)},multipart_params:r})}}),logger.debug("bind BeforeUpload event"),p.bind("UploadProgress",function(a,b){logger.trace("UploadProgress event activated"),m.currentTime=(new Date).getTime();var c=m.currentTime-m.startTime;var d=b.loaded||0;m.isResumeUpload&&(d=b.loaded-m.resumeFilesize),b.speed=(d/c*1e3).toFixed(0)||0}),logger.debug("bind UploadProgress event"),p.bind("ChunkUploaded",function(a,b,c){logger.debug("ChunkUploaded event activated"),logger.debug("file: ",b),logger.debug("info: ",c);var d=that.parseJSON(c.response);logger.debug("res: ",d),l=l?l+","+d.ctx:d.ctx;var e=c.total-c.offset;var g=a.getOption&&a.getOption("chunk_size");g=g||a.settings&&a.settings.chunk_size,g>e&&(a.setOption({url:qiniuUploadUrl+"/mkblk/"+e}),logger.debug("up.setOption url: ",qiniuUploadUrl+"/mkblk/"+e)),a.setOption({headers:{Authorization:"UpToken "+f(b)}}),localStorage.setItem(b.name,that.stringifyJSON({ctx:l,percent:b.percent,total:c.total,offset:c.offset,time:(new Date).getTime()}))}),logger.debug("bind ChunkUploaded event");var q=qiniuUploadUrls.length;var r=function(a){return q-->0?(setTimeout(function(){that.resetUploadUrl(),a.status=plupload.QUEUED,p.stop(),p.start()},0),!0):(q=qiniuUploadUrls.length,!1)};return p.bind("Error",function(a){return function(b,c){logger.error("Error event activated"),logger.error("err: ",c);var d="";var e=c.file;if(e){switch(c.code){case plupload.FAILED:d="\u4e0a\u4f20\u5931\u8d25\u3002\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002";break;case plupload.FILE_SIZE_ERROR:var f=b.getOption&&b.getOption("max_file_size");f=f||b.settings&&b.settings.max_file_size,d="\u6d4f\u89c8\u5668\u6700\u5927\u53ef\u4e0a\u4f20"+f+"\u3002\u66f4\u5927\u6587\u4ef6\u8bf7\u4f7f\u7528\u547d\u4ee4\u884c\u5de5\u5177\u3002";break;case plupload.FILE_EXTENSION_ERROR:d="\u6587\u4ef6\u9a8c\u8bc1\u5931\u8d25\u3002\u8bf7\u7a0d\u540e\u91cd\u8bd5\u3002";break;case plupload.HTTP_ERROR:if(""===c.response){if(d=c.message||"\u672a\u77e5\u7f51\u7edc\u9519\u8bef\u3002",!r(e))return;break}var g=that.parseJSON(c.response);var h=g.error;switch(c.status){case 400:d="\u8bf7\u6c42\u62a5\u6587\u683c\u5f0f\u9519\u8bef\u3002";break;case 401:d="\u5ba2\u6237\u7aef\u8ba4\u8bc1\u6388\u6743\u5931\u8d25\u3002\u8bf7\u91cd\u8bd5\u6216\u63d0\u4ea4\u53cd\u9988\u3002";break;case 405:d="\u5ba2\u6237\u7aef\u8bf7\u6c42\u9519\u8bef\u3002\u8bf7\u91cd\u8bd5\u6216\u63d0\u4ea4\u53cd\u9988\u3002";break;case 579:d="\u8d44\u6e90\u4e0a\u4f20\u6210\u529f\uff0c\u4f46\u56de\u8c03\u5931\u8d25\u3002";break;case 599:if(d="\u7f51\u7edc\u8fde\u63a5\u5f02\u5e38\u3002\u8bf7\u91cd\u8bd5\u6216\u63d0\u4ea4\u53cd\u9988\u3002",!r(e))return;break;case 614:d="\u6587\u4ef6\u5df2\u5b58\u5728\u3002";try{g=that.parseJSON(g.error),h=g.error||"file exists"}catch(i){h=g.error||"file exists"}break;case 631:d="\u6307\u5b9a\u7a7a\u95f4\u4e0d\u5b58\u5728\u3002";break;case 701:d="\u4e0a\u4f20\u6570\u636e\u5757\u6821\u9a8c\u51fa\u9519\u3002\u8bf7\u91cd\u8bd5\u6216\u63d0\u4ea4\u53cd\u9988\u3002";break;default:if(d="\u672a\u77e5\u9519\u8bef\u3002",!r(e))return}d=d+"("+c.status+"\uff1a"+h+")";break;case plupload.SECURITY_ERROR:d="\u5b89\u5168\u914d\u7f6e\u9519\u8bef\u3002\u8bf7\u8054\u7cfb\u7f51\u7ad9\u7ba1\u7406\u5458\u3002";break;case plupload.GENERIC_ERROR:d="\u4e0a\u4f20\u5931\u8d25\u3002\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002";break;case plupload.IO_ERROR:d="\u4e0a\u4f20\u5931\u8d25\u3002\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002";break;case plupload.INIT_ERROR:d="\u7f51\u7ad9\u914d\u7f6e\u9519\u8bef\u3002\u8bf7\u8054\u7cfb\u7f51\u7ad9\u7ba1\u7406\u5458\u3002",p.destroy();break;default:if(d=c.message+c.details,!r(e))return}a&&a(b,c,d)}b.refresh()}}(j)),logger.debug("bind Error event"),p.bind("FileUploaded",function(b){return function(c,d,e){logger.debug("FileUploaded event activated"),logger.debug("file: ",d),logger.debug("info: ",e);var f=function(c,d,e){if(a.downtoken_url){var f=that.createAjax();f.open("POST",a.downtoken_url,!0),f.setRequestHeader("Content-type","application/x-www-form-urlencoded"),f.onreadystatechange=function(){if(4===f.readyState)if(200===f.status){var a;try{a=that.parseJSON(f.responseText)}catch(g){throw"invalid json format"}var h={};plupload.extend(h,that.parseJSON(e),a),b&&b(c,d,that.stringifyJSON(h))}else p.trigger("Error",{status:f.status,response:f.responseText,file:d,code:plupload.HTTP_ERROR})},f.send("key="+that.parseJSON(e).key+"&domain="+a.domain)}else b&&b(c,d,e)};var g=that.parseJSON(e.response);if(l=l?l:g.ctx,logger.debug("ctx: ",l),l){var i="";logger.debug("save_key: ",a.save_key),a.save_key||(i=h(c,d,that.key_handler),i=i?"/key/"+that.URLSafeBase64Encode(i):"");var j="/fname/"+that.URLSafeBase64Encode(d.name);logger.debug("op.x_vars: ",a.x_vars);var k=a.x_vars,m="",n="";if(void 0!==k&&"object"==typeof k)for(var o in k)k.hasOwnProperty(o)&&("function"==typeof k[o]?m=that.URLSafeBase64Encode(k[o](c,d)):"object"!=typeof k[o]&&(m=that.URLSafeBase64Encode(k[o])),n+="/x:"+o+"/"+m);var q=qiniuUploadUrl+"/mkfile/"+d.size+i+j+n;var r=that.detectIEVersion();var s;r&&9>=r?(s=new mOxie.XMLHttpRequest,mOxie.Env.swf_url=a.flash_swf_url):s=that.createAjax(),s.open("POST",q,!0),s.setRequestHeader("Content-Type","text/plain;charset=UTF-8"),s.setRequestHeader("Authorization","UpToken "+that.token);var t=function(){if(logger.debug("ajax.readyState: ",s.readyState),4===s.readyState){localStorage.removeItem(d.name);var a;200===s.status?(a=s.responseText,logger.debug("mkfile is success: ",a),f(c,d,a)):(a={status:s.status,response:s.responseText,file:d,code:-200,responseHeaders:s.getAllResponseHeaders()},logger.debug("mkfile is error: ",a),p.trigger("Error",a))}};r&&9>=r?s.bind("readystatechange",t):s.onreadystatechange=t,s.send(l),logger.debug("mkfile: ",q)}else f(c,d,e.response)}}(k)),logger.debug("bind FileUploaded event"),p.init(),logger.debug("invoke uploader.init()"),logger.debug("init uploader end"),p},this.getUrl=function(a){if(!a)return!1;a=encodeURI(a);var b=this.domain;return"/"!==b.slice(b.length-1)&&(b+="/"),b+a},this.imageView2=function(a,b){if(!/^\d$/.test(a.mode))return!1;var c=a.mode,d=a.w||"",e=a.h||"",f=a.q||"",g=a.format||"";if(!d&&!e)return!1;var h="imageView2/"+c;return h+=d?"/w/"+d:"",h+=e?"/h/"+e:"",h+=f?"/q/"+f:"",h+=g?"/format/"+g:"",b&&(h=this.getUrl(b)+"?"+h),h},this.imageMogr2=function(a,b){var c=a["auto-orient"]||"",d=a.thumbnail||"",e=a.strip||"",f=a.gravity||"",g=a.crop||"",h=a.quality||"",i=a.rotate||"",j=a.format||"",k=a.blur||"";var l="imageMogr2";return l+=c?"/auto-orient":"",l+=d?"/thumbnail/"+d:"",l+=e?"/strip":"",l+=f?"/gravity/"+f:"",l+=h?"/quality/"+h:"",l+=g?"/crop/"+g:"",l+=i?"/rotate/"+i:"",l+=j?"/format/"+j:"",l+=k?"/blur/"+k:"",b&&(l=this.getUrl(b)+"?"+l),l},this.watermark=function(a,b){var c=a.mode;if(!c)return!1;var d="watermark/"+c;if(1===c){var e=a.image||"";if(!e)return!1;d+=e?"/image/"+this.URLSafeBase64Encode(e):""}else{if(2!==c)return!1;var f=a.text?a.text:"",g=a.font?a.font:"",h=a.fontsize?a.fontsize:"",i=a.fill?a.fill:"";if(!f)return!1;d+=f?"/text/"+this.URLSafeBase64Encode(f):"",d+=g?"/font/"+this.URLSafeBase64Encode(g):"",d+=h?"/fontsize/"+h:"",d+=i?"/fill/"+this.URLSafeBase64Encode(i):""}var j=a.dissolve||"",k=a.gravity||"",l=a.dx||"",m=a.dy||"";return d+=j?"/dissolve/"+j:"",d+=k?"/gravity/"+k:"",d+=l?"/dx/"+l:"",d+=m?"/dy/"+m:"",b&&(d=this.getUrl(b)+"?"+d),d},this.imageInfo=function(a){if(!a)return!1;var b=this.getUrl(a)+"?imageInfo";var c=this.createAjax();var d;var e=this;return c.open("GET",b,!1),c.onreadystatechange=function(){4===c.readyState&&200===c.status&&(d=e.parseJSON(c.responseText))},c.send(),d},this.exif=function(a){if(!a)return!1;var b=this.getUrl(a)+"?exif";var c=this.createAjax();var d;var e=this;return c.open("GET",b,!1),c.onreadystatechange=function(){4===c.readyState&&200===c.status&&(d=e.parseJSON(c.responseText))},c.send(),d},this.get=function(a,b){return b&&a?"exif"===a?this.exif(b):"imageInfo"===a?this.imageInfo(b):!1:!1},this.pipeline=function(a,b){var c="[object Array]"===Object.prototype.toString.call(a);var d,e,f="";if(c){for(var g=0,h=a.length;h>g;g++){if(d=a[g],!d.fop)return!1;switch(d.fop){case"watermark":f+=this.watermark(d)+"|";break;case"imageView2":f+=this.imageView2(d)+"|";break;case"imageMogr2":f+=this.imageMogr2(d)+"|";break;default:e=!0}if(e)return!1}if(b){f=this.getUrl(b)+"?"+f;var i=f.length;"|"===f.slice(i-1)&&(f=f.slice(0,i-1))}return f}return!1}}var Qiniu=new QiniuJsSDK;global.Qiniu=Qiniu,global.QiniuJsSDK=QiniuJsSDK}(window);
+//# sourceMappingURL=dist/qiniu.min.map
\ No newline at end of file
diff --git a/qiniu_fields/static/qiniu_fields/qiniu/qiniu.min.map b/qiniu_fields/static/qiniu_fields/qiniu/qiniu.min.map
new file mode 100755
index 0000000..bca46a2
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/qiniu/qiniu.min.map
@@ -0,0 +1 @@
+{"version":3,"file":"dist/qiniu.min.js","sources":["dist/qiniu.js"],"names":["global","createCookie","key","value","exp","date","Date","setTime","getTime","expires","toGMTString","document","cookie","readCookie","nameEQ","ca","split","i","max","length","c","charAt","substring","indexOf","window","localStorage","setItem","getItem","removeItem","QiniuJsSDK","that","this","detectIEVersion","v","div","createElement","all","getElementsByTagName","innerHTML","logger","MUTE","FATA","ERROR","WARN","INFO","DEBUG","TRACE","level","log","type","args","header","msg","stringifyJSON","console","unshift","apply","getElementById","makeLogFunc","code","func","toLowerCase","Array","prototype","slice","call","arguments","property","hasOwnProperty","qiniuUploadUrl","location","protocol","qiniuUploadUrls","qiniuUpHosts","http","https","changeUrlTimes","resetUploadUrl","hosts","debug","isImage","url","test","getFileExtension","filename","tempArr","ext","pop","utf8_encode","argString","string","utftext","start","end","stringl","n","c1","charCodeAt","enc","String","fromCharCode","RangeError","c2","base64_decode","data","b64","o1","o2","o3","h1","h2","h3","h4","bits","ac","dec","tmp_arr","join","base64_encode","URLSafeBase64Encode","replace","URLSafeBase64Decode","createAjax","argument","xmlhttp","XMLHttpRequest","ActiveXObject","parseJSON","JSON","parse","rx_dangerous","text","lastIndex","a","toString","eval","obj","stringify","map","strArr","len","push","trim","uploader","op","reset_chunk_size","ie","BLOCK_BITS","MAX_CHUNK_SIZE","chunk_size","isSpecialSafari","mOxie","Env","browser","version","os","osVersion","runtimes","plupload","parseSize","getHosts","result","host","getPutPolicy","uptoken","segments","ak","putPolicy","scope","bucket","getUpHosts","uphosts_url","ajax","swf_url","flash_swf_url","open","onreadystatechange","readyState","status","res","responseText","up","error","bind","send","getUptoken","file","token","uptoken_url","tokenInfo","isExpired","getNewUpToken","setRequestHeader","tokenMap","getTimestamp","time","Math","ceil","serverTime","getResponseHeader","clientTime","serverDelay","deadline","leftTime","uptoken_func","getFileKey","unique_names","save_key","getOption","settings","name","id","log_level","domain","browse_button","navigator","userAgent","option","_Error_Handler","init","Error","_FileUploaded_Handler","FileUploaded","key_handler","Key","ctx","speedCalInfo","isResumeUpload","resumeFilesize","startTime","currentTime","defaultSetting","multipart_params","accept","extend","Uploader","params","get_new_uptoken","files","auto_start","is_ios","OS","setTimeout","refresh","speed","directUpload","multipart_params_obj","x_vars","undefined","x_key","setOption","multipart","is_android_weixin_or_qq","max_file_size","ua","match","runtime","size","localFileInfo","blockSize","now","before","aDay","percent","total","loaded","offset","required_features","headers","Authorization","trace","timeUsed","fileUploaded","toFixed","info","response","leftSize","retries","unknow_error_retry","QUEUED","stop","err","errTip","FAILED","FILE_SIZE_ERROR","FILE_EXTENSION_ERROR","HTTP_ERROR","message","errorObj","errorText","e","SECURITY_ERROR","GENERIC_ERROR","IO_ERROR","INIT_ERROR","destroy","details","last_step","downtoken_url","ajax_downtoken","res_downtoken","info_extended","trigger","fname","x_val","x_vars_url","responseHeaders","getAllResponseHeaders","getUrl","encodeURI","imageView2","mode","w","h","q","format","imageUrl","imageMogr2","auto_orient","thumbnail","strip","gravity","crop","quality","rotate","blur","watermark","image","font","fontsize","fill","dissolve","dx","dy","imageInfo","xhr","exif","get","pipeline","arr","isArray","Object","errOp","fop","Qiniu"],"mappings":";CAgBC,SAAWA,QAQZ,QAASC,cAAaC,EAAKC,EAAOC,GAC9B,GAAIC,GAAO,GAAIC,KACfD,GAAKE,QAAQF,EAAKG,UAAmB,GAANJ,EAAW,GAAK,GAAK,IACpD,IAAIK,GAAU,aAAeJ,EAAKK,aAClCC,UAASC,OAASV,EAAM,IAAMC,EAAQM,EAAU,WAOpD,QAASI,YAAWX,GAChB,GAAIY,GAASZ,EAAM,GACnB,IAAIa,GAAKJ,SAASC,OAAOI,MAAM,IAC/B,KAAK,GAAIC,GAAI,EAAGC,EAAMH,EAAGI,OAAYD,EAAJD,EAASA,IAAK,CAC3C,GAAIG,GAAIL,EAAGE,EACX,OAAuB,MAAhBG,EAAEC,OAAO,GACZD,EAAIA,EAAEE,UAAU,EAAGF,EAAED,OAEzB,IAA0B,IAAtBC,EAAEG,QAAQT,GACV,MAAOM,GAAEE,UAAUR,EAAOK,OAAQC,EAAED,QAG5C,MAAO,MAKLK,OAAOC,eACTD,OAAOC,cACHC,QAAS,SAAUxB,EAAKC,GACpBF,aAAaC,EAAKC,EAAO,KAE7BwB,QAAS,SAAUzB,GACf,MAAOW,YAAWX,IAEtB0B,WAAY,SAAU1B,GAClBD,aAAaC,EAAK,GAAI,MAKlC,SAAS2B,cAEL,GAAIC,MAAOC,IAUXA,MAAKC,gBAAkB,WACnB,GAAIC,GAAI,EACJC,EAAMvB,SAASwB,cAAc,OAC7BC,EAAMF,EAAIG,qBAAqB,IACnC,OACIH,EAAII,UAAY,iBAAmBL,EAAI,wBACvCG,EAAI,GAEJH,GAEJ,OAAOA,GAAI,EAAIA,GAAI,EAGvB,IAAIM,SACAC,KAAM,EACNC,KAAM,EACNC,MAAO,EACPC,KAAM,EACNC,KAAM,EACNC,MAAO,EACPC,MAAO,EACPC,MAAO,EAGX,SAASC,KAAIC,EAAMC,GACf,GAAIC,GAAS,kBAAkBF,EAAK,GACpC,IAAIG,GAAMD,CACV,KAAK,GAAIlC,GAAI,EAAGA,EAAIiC,EAAK/B,OAAQF,IAEzBmC,GADmB,gBAAZF,GAAKjC,GACL,IAAMiC,EAAKjC,GAEX,IAAMa,KAAKuB,cAAcH,EAAKjC,GAGzCa,MAAKE,kBAILsB,QAAQN,IAAII,IAEZF,EAAKK,QAAQJ,GACbG,QAAQN,IAAIQ,MAAMF,QAASJ,IAE3BvC,SAAS8C,eAAe,sBACxB9C,SAAS8C,eAAe,oBAAoBnB,WAAa,MAAMc,EAAI,QAI3E,QAASM,aAAYC,GACjB,GAAIC,GAAOD,EAAKE,aAChBtB,QAAOqB,GAAQ,WAGX,GAAGpC,OAAO8B,SAAW9B,OAAO8B,QAAQN,KAAOT,OAAOQ,OAAOR,OAAOoB,GAAM,CAClE,GAAIT,GAAOY,MAAMC,UAAUC,MAAMC,KAAKC,UACtClB,KAAIY,EAAKV,KAKrB,IAAK,GAAIiB,YAAY5B,QACbA,OAAO6B,eAAeD,WAA2C,gBAAtB5B,QAAO4B,YAA4B5B,OAAO6B,eAAeD,SAASN,gBAC7GH,YAAYS,SAKpB,IAAIE,eAEAA,gBAD6B,WAA7B7C,OAAO8C,SAASC,SACC,qBAEA,yBAQrB,IAAIC,kBACA,0BACA,sBAGJ,IAAIC,eACDC,MACI,0BACA,uBAEJC,OACI,sBAIP,IAAIC,gBAAiB,CASrB7C,MAAK8C,eAAiB,WACzB,GAAIC,GAAqC,WAA7BtD,OAAO8C,SAASC,SAAwBE,aAAaE,MAAQF,aAAaC,IACtF,IAAIzD,GAAI2D,eAAiBE,EAAM3D,MAC/BkD,gBAAiBS,EAAM7D,GACvB2D,iBACArC,OAAOwC,MAAM,mBAAmBV,iBAW7BtC,KAAKiD,QAAU,SAASC,GAEpB,MADAA,GAAMA,EAAIjE,MAAM,QAAQ,GACjB,6BAA+BkE,KAAKD,IAW/ClD,KAAKoD,iBAAmB,SAASC,GAC7B,GAAIC,GAAUD,EAASpE,MAAM,IAC7B,IAAIsE,EAMJ,OAJIA,GADmB,IAAnBD,EAAQlE,QAAgC,KAAfkE,EAAQ,IAAgC,IAAnBA,EAAQlE,OAChD,GAEAkE,EAAQE,MAAM1B,eAU5B9B,KAAKyD,YAAc,SAASC,GAgBxB,GAAkB,OAAdA,GAA2C,mBAAdA,GAC7B,MAAO,EAGX,IAAIC,GAAUD,EAAY,EAC1B,IAAIE,GAAU,GACVC,EAAOC,EAAKC,EAAU,CAE1BF,GAAQC,EAAM,EACdC,EAAUJ,EAAOvE,MACjB,KAAK,GAAI4E,GAAI,EAAOD,EAAJC,EAAaA,IAAK,CAC9B,GAAIC,GAAKN,EAAOO,WAAWF,EAC3B,IAAIG,GAAM,IAEV,IAAS,IAALF,EACAH,QACG,IAAIG,EAAK,KAAY,KAALA,EACnBE,EAAMC,OAAOC,aACRJ,GAAM,EAAK,IAAW,GAALA,EAAW,SAE9B,IAAS,MAALA,GAAc,EACrBE,EAAMC,OAAOC,aACRJ,GAAM,GAAM,IAAOA,GAAM,EAAK,GAAM,IAAW,GAALA,EAAW,SAEvD,CACH,GAAS,MAALA,GAAc,EACd,KAAM,IAAIK,YAAW,gCAAkCN,EAE3D,IAAIO,GAAKZ,EAAOO,aAAaF,EAC7B,IAAS,MAALO,GAAc,EACd,KAAM,IAAID,YAAW,gCAAkCN,EAAI,GAE/DC,KAAY,KAALA,IAAe,KAAY,KAALM,GAAc,MAC3CJ,EAAMC,OAAOC,aACRJ,GAAM,GAAM,IAAOA,GAAM,GAAM,GAAM,IAAOA,GAAM,EAAK,GAAM,IAAW,GAALA,EAAW,KAG3E,OAARE,IACIL,EAAMD,IACND,GAAWD,EAAO1B,MAAM4B,EAAOC,IAEnCF,GAAWO,EACXN,EAAQC,EAAME,EAAI,GAQ1B,MAJIF,GAAMD,IACND,GAAWD,EAAO1B,MAAM4B,EAAOE,IAG5BH,GAGX5D,KAAKwE,cAAgB,SAAUC,GAkB3B,GAAIC,GAAM,mEACV,IAAIC,GAAIC,EAAIC,EAAIC,EAAIC,EAAIC,EAAIC,EAAIC,EAAMhG,EAAI,EAC1CiG,EAAK,EACLC,EAAM,GACNC,IAEA,KAAKZ,EACD,MAAOA,EAGXA,IAAQ,EAER,GACIK,GAAKJ,EAAIlF,QAAQiF,EAAKnF,OAAOJ,MAC7B6F,EAAKL,EAAIlF,QAAQiF,EAAKnF,OAAOJ,MAC7B8F,EAAKN,EAAIlF,QAAQiF,EAAKnF,OAAOJ,MAC7B+F,EAAKP,EAAIlF,QAAQiF,EAAKnF,OAAOJ,MAE7BgG,EAAOJ,GAAM,GAAKC,GAAM,GAAKC,GAAM,EAAIC,EAEvCN,EAAKO,GAAQ,GAAK,IAClBN,EAAKM,GAAQ,EAAI,IACjBL,EAAY,IAAPK,EAEM,KAAPF,EACAK,EAAQF,KAAQf,OAAOC,aAAaM,GACtB,KAAPM,EACPI,EAAQF,KAAQf,OAAOC,aAAaM,EAAIC,GAExCS,EAAQF,KAAQf,OAAOC,aAAaM,EAAIC,EAAIC,SAE3C3F,EAAIuF,EAAKrF,OAIlB,OAFAgG,GAAMC,EAAQC,KAAK,KAUvBtF,KAAKuF,cAAgB,SAASd,GAgB1B,GAAIC,GAAM,mEACV,IAAIC,GAAIC,EAAIC,EAAIC,EAAIC,EAAIC,EAAIC,EAAIC,EAAMhG,EAAI,EACtCiG,EAAK,EACLhB,EAAM,GACNkB,IAEJ,KAAKZ,EACD,MAAOA,EAGXA,GAAOzE,KAAKyD,YAAYgB,EAAO,GAE/B,GACIE,GAAKF,EAAKP,WAAWhF,KACrB0F,EAAKH,EAAKP,WAAWhF,KACrB2F,EAAKJ,EAAKP,WAAWhF,KAErBgG,EAAOP,GAAM,GAAKC,GAAM,EAAIC,EAE5BC,EAAKI,GAAQ,GAAK,GAClBH,EAAKG,GAAQ,GAAK,GAClBF,EAAKE,GAAQ,EAAI,GACjBD,EAAY,GAAPC,EAGLG,EAAQF,KAAQT,EAAIpF,OAAOwF,GAAMJ,EAAIpF,OAAOyF,GAAML,EAAIpF,OAAO0F,GAAMN,EAAIpF,OAAO2F,SACzE/F,EAAIuF,EAAKrF,OAIlB,QAFA+E,EAAMkB,EAAQC,KAAK,IAEXb,EAAKrF,OAAS,GAClB,IAAK,GACD+E,EAAMA,EAAIlC,MAAM,EAAG,IAAM,IACzB,MACJ,KAAK,GACDkC,EAAMA,EAAIlC,MAAM,EAAG,IAAM,IAIjC,MAAOkC,IAQXnE,KAAKwF,oBAAsB,SAAStF,GAEhC,MADAA,GAAIF,KAAKuF,cAAcrF,GAChBA,EAAEuF,QAAQ,MAAO,KAAKA,QAAQ,MAAO,MAGhDzF,KAAK0F,oBAAsB,SAASxF,GAEhC,MADAA,GAAIA,EAAEuF,QAAQ,KAAM,KAAKA,QAAQ,KAAM,KAChCzF,KAAKwE,cAActE,IAQ9BF,KAAK2F,WAAa,SAASC,GACvB,GAAIC,KAMJ,OAJIA,GADApG,OAAOqG,eACG,GAAIA,gBAEJ,GAAIC,eAAc,sBAWpC/F,KAAKgG,UAAY,SAASvB,MAEtB,GAAIhF,OAAOwG,MAAQxG,OAAOwG,KAAKC,MAC3B,MAAOzG,QAAOwG,KAAKC,MAAMzB,KAO7B,IAAO0B,cAAe,0GAItB,IAAIC,MAAOhC,OAAOK,KAoBlB,OAnBA0B,cAAaE,UAAY,EACtBF,aAAahD,KAAKiD,QACjBA,KAAOA,KAAKX,QAAQU,aAAc,SAASG,GACxC,MAAO,OAAS,OAASA,EAAEpC,WAAW,GAAGqC,SAAS,KAAKtE,MAAM,OAgB7DuE,KAAK,IAAIJ,KAAK,MAQzBpG,KAAKsB,cAAgB,SAASmF,GAE1B,GAAIhH,OAAOwG,MAAQxG,OAAOwG,KAAKS,UAC3B,MAAOjH,QAAOwG,KAAKS,UAAUD,EAEjC,cAAe,IACX,IAAK,SACD,MAAO,IAAMA,EAAIhB,QAAQ,WAAY,QAAU,GACnD,KAAK,QACD,MAAO,IAAMgB,EAAIE,IAAI5G,KAAKuB,eAAegE,KAAK,KAAO,GACzD,KAAK,SACD,GAAImB,YAAe1E,OAAO,CACtB,GAAI6E,KACJ,IAAIC,GAAMJ,EAAIrH,MACd,KAAK,GAAIF,GAAI,EAAO2H,EAAJ3H,EAASA,IACrB0H,EAAOE,KAAK/G,KAAKuB,cAAcmF,EAAIvH,IAEvC,OAAO,IAAM0H,EAAOtB,KAAK,KAAO,IAC7B,GAAY,OAARmB,EACP,MAAO,MAEP,IAAI9C,KACJ,KAAK,GAAIvB,KAAYqE,GACbA,EAAIpE,eAAeD,IACnBuB,EAAOmD,KAAK/G,KAAKuB,cAAcc,GAAY,IAAMrC,KAAKuB,cAAcmF,EAAIrE,IAGhF,OAAO,IAAMuB,EAAO2B,KAAK,KAAO,GAGxC,KAAK,SACD,MAAOmB,EACX,MAAK,EACD,MAAOA,EACX,KAAK,UACD,MAAOA,KASnBzG,KAAK+G,KAAO,SAASX,GACjB,MAAgB,QAATA,EAAgB,GAAKA,EAAKX,QAAQ,aAAc,KAQ3DzF,KAAKgH,SAAW,SAASC,GAQrB,GAAIC,GAAmB,WACnB,GAAIC,GAAKpH,KAAKE,iBACd,IAAImH,GAAYC,EAAgBC,CAEhC,IAAIC,GAAyC,WAAtBC,MAAMC,IAAIC,SAAwBF,MAAMC,IAAIE,SAAW,GAAsB,YAAjBH,MAAMC,IAAIG,IAA4C,MAAxBJ,MAAMC,IAAII,WAA6C,WAAtBL,MAAMC,IAAIC,SAAyC,QAAjBF,MAAMC,IAAIG,IAAwC,MAAxBJ,MAAMC,IAAII,SAIpNV,IAAW,EAALA,GAAUF,EAAGK,YAAcL,EAAGa,SAAStI,QAAQ,UAAY,EAGjEyH,EAAGK,WAAa,EACTC,EAIPN,EAAGK,WAAa,GAEhBF,EAAa,GACbC,EAAiB,GAAKD,EAEtBE,EAAaS,SAASC,UAAUf,EAAGK,YAC/BA,EAAaD,IACbJ,EAAGK,WAAaD,IAQ5B,IAAIY,GAAW,SAASlF,GACpB,GAAImF,KACJ,KAAK,GAAIhJ,GAAI,EAAGA,EAAI6D,EAAM3D,OAAQF,IAAK,CACnC,GAAIiJ,GAAOpF,EAAM7D,EACU,KAAvBiJ,EAAK3I,QAAQ,MACb0I,EAAOpB,KAAKqB,EAAKlJ,MAAM,KAAK,IAE5BiJ,EAAOpB,KAAKqB,GAGpB,MAAOD,GAGX,IAAIE,GAAe,SAAUC,GACzB,GAAIC,GAAWD,EAAQpJ,MAAM,IAC7B,IAAIsJ,GAAKD,EAAS,EAClB,IAAIE,GAAYzI,KAAKiG,UAAUjG,KAAK2F,oBAAoB4C,EAAS,IAQjE,OAPAE,GAAUD,GAAKA,EACXC,EAAUC,MAAMjJ,QAAQ,MAAQ,GAChCgJ,EAAUE,OAASF,EAAUC,MAAMxJ,MAAM,KAAK,GAC9CuJ,EAAUrK,IAAMqK,EAAUC,MAAMxJ,MAAM,KAAK,IAE3CuJ,EAAUE,OAASF,EAAUC,MAE1BD,EAGX,IAAIG,GAAa,SAASN,GACtB,GAAIG,GAAYJ,EAAaC,EAG7B,IAAIO,GAAcnJ,OAAO8C,SAASC,SAAW,4BAA8BgG,EAAUD,GAAK,WAAaC,EAAUE,MACjHlI,QAAOwC,MAAM,cAAewF,GAC5BhI,OAAOwC,MAAM,qBAAsB4F,EACnC,IAAIzB,GAAKpH,KAAKE,iBACd,IAAI4I,EACA1B,IAAY,GAANA,GACN0B,EAAO,GAAIrB,OAAM1B,eACjB0B,MAAMC,IAAIqB,QAAU7B,EAAG8B,eAEvBF,EAAO9I,KAAK4F,aAEhBkD,EAAKG,KAAK,MAAOJ,GAAa,EAC9B,IAAIK,GAAqB,WAErB,GADAzI,OAAOwC,MAAM,oBAAqB6F,EAAKK,YACf,IAApBL,EAAKK,WAEL,GADA1I,OAAOwC,MAAM,gBAAiB6F,EAAKM,QAC/BN,EAAKM,OAAS,IAAK,CACnB,GAAIC,GAAMrJ,KAAKiG,UAAU6C,EAAKQ,aAC9B3G,cAAaC,KAAOsF,EAASmB,EAAIzG,KAAK2G,IACtC5G,aAAaE,MAAQqF,EAASmB,EAAIxG,MAAM0G,IACxC9I,OAAOwC,MAAM,oBAAqBN,cAClC3C,KAAK+C,qBAELtC,QAAO+I,MAAM,sBAAuBV,EAAKQ,cAIjDlC,IAAY,GAANA,EACN0B,EAAKW,KAAK,mBAAoBP,GAE9BJ,EAAKI,mBAAqBA,EAE9BJ,EAAKY,OAcT,IAAIC,GAAa,SAASC,GACtB,OAAK5J,KAAK6J,OAAU3C,EAAG4C,aAAe9J,KAAK+J,UAAUC,YAC1CC,EAAcL,GAEd5J,KAAK6J,MASpB,IAAII,GAAgB,SAASL,GACzB,GAAI1C,EAAGoB,QACHtI,KAAK6J,MAAQ3C,EAAGoB,YACb,IAAIpB,EAAG4C,YAAa,CACvBrJ,OAAOwC,MAAM,qBAAsBjD,KAAK8J,YAExC,IAAIhB,GAAO9I,KAAK4F,YAUhB,IATAkD,EAAKG,KAAK,MAAOjJ,KAAK8J,aAAa,GACnChB,EAAKoB,iBAAiB,oBAAqB,KAO3CpB,EAAKY,OACe,MAAhBZ,EAAKM,OAAgB,CACrB,GAAIC,GAAMrJ,KAAKiG,UAAU6C,EAAKQ,aAC9BtJ,MAAK6J,MAAQR,EAAIf,OACjB,IAAIC,GAAWvI,KAAK6J,MAAM3K,MAAM,IAChC,IAAIuJ,GAAYzI,KAAKiG,UAAUjG,KAAK2F,oBAAoB4C,EAAS,IAC5DvI,MAAKmK,WACNnK,KAAKmK,YAET,IAAIC,GAAe,SAASC,GACxB,MAAOC,MAAKC,KAAKF,EAAK3L,UAAU,KAEpC,IAAI8L,GAAaJ,EAAa,GAAI5L,MAAKsK,EAAK2B,kBAAkB,SAC9D,IAAIC,GAAaN,EAAa,GAAI5L,MAClCwB,MAAK+J,WACDY,YAAaD,EAAaF,EAC1BI,SAAUnC,EAAUmC,SACpBZ,UAAW,WACP,GAAIa,GAAW5K,KAAK2K,SAAWR,EAAa,GAAI5L,OAAUyB,KAAK0K,WAC/D,OAAkB,KAAXE,IAGfpK,OAAOwC,MAAM,oBAAqBjD,KAAK6J,OACvCpJ,OAAOwC,MAAM,mBAAoBjD,KAAK+J,eAEtCtJ,QAAO+I,MAAM,sBAAuBV,EAAKQ,kBAEtCpC,GAAG4D,cACVrK,OAAOwC,MAAM,iCACbjD,KAAK6J,MAAQ3C,EAAG4D,aAAalB,GAC7BnJ,OAAOwC,MAAM,oBAAqBjD,KAAK6J,QAEvCpJ,OAAO+I,MAAM,+EAKjB,OAHIxJ,MAAK6J,OACLjB,EAAW5I,KAAK6J,OAEb7J,KAAK6J,MAIhB,IAAIkB,GAAa,SAASxB,EAAIK,EAAM9H,GAUhC,GAAI1D,GAAM,GACN4M,GAAe,CACnB,KAAK9D,EAAG+D,SAGJ,GAFAD,EAAezB,EAAG2B,WAAa3B,EAAG2B,UAAU,gBAC5CF,EAAeA,GAAiBzB,EAAG4B,UAAY5B,EAAG4B,SAASH,aACzC,CACd,GAAIxH,GAAMxD,KAAKqD,iBAAiBuG,EAAKwB,KACrChN,GAAMoF,EAAMoG,EAAKyB,GAAK,IAAM7H,EAAMoG,EAAKyB,OAEvCjN,GADuB,kBAAT0D,GACRA,EAAKyH,EAAIK,GAETA,EAAKwB,IAGnB,OAAOhN,GASX,IAJI8I,EAAGoE,YACH7K,OAAOQ,MAAQiG,EAAGoE,YAGjBpE,EAAGqE,OACJ,KAAM,wCAGV,KAAKrE,EAAGsE,cACJ,KAAM,+CAGV,KAAKtE,EAAGoB,UAAYpB,EAAG4C,cAAgB5C,EAAG4D,aACtC,KAAM,8EAGVrK,QAAOwC,MAAM,uBAEbxC,OAAOwC,MAAM,gBAAiBwE,MAAMC,KAEpCjH,OAAOwC,MAAM,cAAewI,UAAUC,UAEtC,IAAIC,KAGJ,IAAIC,GAAiB1E,EAAG2E,MAAQ3E,EAAG2E,KAAKC,KACxC,IAAIC,GAAwB7E,EAAG2E,MAAQ3E,EAAG2E,KAAKG,YAG/C9E,GAAG2E,KAAKC,MAAQ,aAChB5E,EAAG2E,KAAKG,aAAe,aAEvBhM,KAAK8J,YAAc5C,EAAG4C,YACtB9J,KAAK6J,MAAQ,GACb7J,KAAKiM,YAAqC,kBAAhB/E,GAAG2E,KAAKK,IAAqBhF,EAAG2E,KAAKK,IAAM,GACrEjM,KAAKsL,OAASrE,EAAGqE,MAGjB,IAAIY,GAAM,EACV,IAAIC,IACAC,gBAAgB,EAChBC,eAAgB,EAChBC,UAAW,GACXC,YAAa,GAGjBrF,KACA1G,OAAOwC,MAAM,6BACbxC,OAAOwC,MAAM,kBAAmBiE,EAAGK,WAEnC,IAAIkF,IACAtJ,IAAKZ,eACLmK,kBACI7C,MAAO,IAGf,IAAIzC,GAAKpH,KAAKE,iBAGVkH,IAAY,GAANA,IACNqF,EAAeC,iBAAiBC,OAAS,4BACzClM,OAAOwC,MAAM,8CAIjB+E,SAAS4E,OAAOjB,EAAQzE,EAAIuF,GAE5BhM,OAAOwC,MAAM,WAAY0I,EAGzB,IAAI1E,GAAW,GAAIe,UAAS6E,SAASlB,EAErClL,QAAOwC,MAAM,iCAGbgE,EAASwC,KAAK,OAAQ,SAASF,EAAIuD,GAC/BrM,OAAOwC,MAAM,wBAKTiE,EAAG6F,iBACH9C,EAAc,QAKtBxJ,OAAOwC,MAAM,mBAKbgE,EAASwC,KAAK,aAAc,SAASF,EAAIyD,GACrCvM,OAAOwC,MAAM,6BACb,IAAIgK,GAAa1D,EAAG2B,WAAa3B,EAAG2B,UAAU,aAC9C+B,GAAaA,GAAe1D,EAAG4B,UAAY5B,EAAG4B,SAAS8B,WACvDxM,OAAOwC,MAAM,eAAgBgK,GAC7BxM,OAAOwC,MAAM,UAAW+J,EAGxB,IAAIE,GAAS,WACT,MAAgC,QAA7BzF,MAAMC,IAAIyF,GAAGpL,eACL,GAEA,EAKf,IAAImL,IACA,IAAK,GAAI/N,GAAI,EAAGA,EAAI6N,EAAM3N,OAAQF,IAAK,CACnC,GAAIyK,GAAOoD,EAAM7N,EACjB,IAAIqE,GAAMxD,KAAKqD,iBAAiBuG,EAAKwB,KACrCxB,GAAKwB,KAAOxB,EAAKyB,GAAK,IAAM7H,EAIhCyJ,GACAG,WAAW,WACP7D,EAAGzF,QACHrD,OAAOwC,MAAM,sBACd,GAQPsG,EAAG8D,YAGP5M,OAAOwC,MAAM,yBAObgE,EAASwC,KAAK,eAAgB,SAASF,EAAIK,GACvCnJ,OAAOwC,MAAM,gCAEb2G,EAAK0D,MAAQ1D,EAAK0D,OAAS,EAC3BnB,EAAM,GAEHjF,EAAG6F,iBACF9C,EAAcL,EAGlB,IAAI2D,GAAe,SAAShE,EAAIK,EAAM9H,GAClCsK,EAAaG,WAAY,GAAI/N,OAAOE,SACpC,IAAI8O,EAEAA,GADAtG,EAAG+D,UAECpB,MAAS7J,KAAK6J,QAIdzL,IAAO2M,EAAWxB,EAAIK,EAAM9H,GAC5B+H,MAAS7J,KAAK6J,MAGtB,IAAIzC,GAAKpH,KAAKE,iBAGVkH,IAAY,GAANA,IACNoG,EAAqBb,OAAS,4BAC9BlM,OAAOwC,MAAM,8CAGjBxC,OAAOwC,MAAM,sCAAuCuK,EAEpD,IAAIC,GAASvG,EAAGuG,MAChB,IAAeC,SAAXD,GAA0C,gBAAXA,GAC/B,IAAK,GAAIE,KAASF,GACVA,EAAOnL,eAAeqL,KACO,kBAAlBF,GAAOE,GACdH,EAAqB,KAAOG,GAASF,EAAOE,GAAOpE,EAAIK,GACvB,gBAAlB6D,GAAOE,KACrBH,EAAqB,KAAOG,GAASF,EAAOE,IAM5DpE,GAAGqE,WACCzK,IAAOZ,eACPsL,WAAa,EACbtG,WAAcuG,IAA4B5G,EAAG6G,cAAgBL,OAC7DhB,iBAAoBc,IAK5B,IAAIM,GAA0B,WAC1B,GAAIE,GAAKvC,UAAUC,UAAU3J,aAC7B,QAAIiM,EAAGC,MAAM,oBAA4C,cAAtBxG,MAAMC,IAAIC,SAA2BqG,EAAGC,MAAM,gBAA+C,YAA7BxG,MAAMC,IAAIyF,GAAGpL,eACrG,GAEA,EAIf,IAAIwF,GAAagC,EAAG2B,WAAa3B,EAAG2B,UAAU,aAO9C,IANA3D,EAAaA,GAAegC,EAAG4B,UAAY5B,EAAG4B,SAAS5D,WAEvD9G,OAAOwC,MAAM,qBAAqBgE,EAASiH,SAC3CzN,OAAOwC,MAAM,eAAesE,GAGF,UAArBN,EAASiH,SAA4C,UAArBjH,EAASiH,UAAwB3G,EA8ElE9G,OAAOwC,MAAM,oGAEbsK,EAAahE,EAAIK,EAAM5J,KAAKiM,iBA/E5B,IAAIrC,EAAKuE,KAAO5G,GAAcuG,IAC1BrN,OAAOwC,MAAM,4EAEbsK,EAAahE,EAAIK,EAAM5J,KAAKiM,iBACzB,CAIH,GAAImC,GAAgBzO,aAAaE,QAAQ+J,EAAKwB,KAC9C,IAAIiD,GAAY9G,CAChB,IAAI6G,EAAe,CAGfA,EAAgBpO,KAAKiG,UAAUmI,EAC/B,IAAIE,IAAM,GAAK9P,OAAQE,SACvB,IAAI6P,GAASH,EAAc/D,MAAQ,CACnC,IAAImE,GAAO,KAKQA,GAAfF,EAAMC,GAEwB,MAA1BH,EAAcK,SACV7E,EAAKuE,OAASC,EAAcM,OAG5B9E,EAAK6E,QAAUL,EAAcK,QAC7B7E,EAAK+E,OAASP,EAAcQ,OAC5BzC,EAAMiC,EAAcjC,IAGpBC,EAAaC,gBAAiB,EAC9BD,EAAaE,eAAiB8B,EAAcQ,OAGxCR,EAAcQ,OAASP,EAAYzE,EAAKuE,OACxCE,EAAYzE,EAAKuE,KAAOC,EAAcQ,SAclDjP,aAAaG,WAAW8J,EAAKwB,MAGrCgB,EAAaG,WAAY,GAAI/N,OAAOE,SACpC,IAAI8O,KACJ,IAAIpG,GAAKpH,KAAKE,iBAGVkH,IAAY,GAANA,IACNoG,EAAqBb,OAAS,4BAC9BlM,OAAOwC,MAAM,8CAIjBsG,EAAGqE,WACCzK,IAAOZ,eAAiB,UAAY8L,EACpCR,WAAa,EACbtG,WAAcA,EACdsH,kBAAqB,SACrBC,SACIC,cAAiB,WAAapF,EAAWC,IAE7C8C,iBAAoBc,OAUpC/M,OAAOwC,MAAM,2BAIbgE,EAASwC,KAAK,iBAAkB,SAASF,EAAIK,GACzCnJ,OAAOuO,MAAM,kCACb5C,EAAaI,aAAc,GAAIhO,OAAOE,SACtC,IAAIuQ,GAAW7C,EAAaI,YAAcJ,EAAaG,SACvD,IAAI2C,GAAetF,EAAK+E,QAAU,CAC9BvC,GAAaC,iBACb6C,EAAetF,EAAK+E,OAASvC,EAAaE,gBAE9C1C,EAAK0D,OAAS4B,EAAeD,EAAW,KAAME,QAAQ,IAAM,IAGhE1O,OAAOwC,MAAM,6BAIbgE,EAASwC,KAAK,gBAAiB,SAASF,EAAIK,EAAMwF,GAC9C3O,OAAOwC,MAAM,iCACbxC,OAAOwC,MAAM,SAAU2G,GACvBnJ,OAAOwC,MAAM,SAAUmM,EACvB,IAAI/F,GAAMrJ,KAAKiG,UAAUmJ,EAAKC,SAC9B5O,QAAOwC,MAAM,QAASoG,GAEtB8C,EAAMA,EAAMA,EAAM,IAAM9C,EAAI8C,IAAM9C,EAAI8C,GACtC,IAAImD,GAAWF,EAAKV,MAAQU,EAAKR,MACjC,IAAIrH,GAAagC,EAAG2B,WAAa3B,EAAG2B,UAAU,aAC9C3D,GAAaA,GAAegC,EAAG4B,UAAY5B,EAAG4B,SAAS5D,WACxCA,EAAX+H,IACA/F,EAAGqE,WACCzK,IAAOZ,eAAiB,UAAY+M,IAExC7O,OAAOwC,MAAM,qBAAsBV,eAAiB,UAAY+M,IAEpE/F,EAAGqE,WACCkB,SACIC,cAAiB,WAAapF,EAAWC,MAGjDjK,aAAaC,QAAQgK,EAAKwB,KAAMpL,KAAKuB,eACjC4K,IAAKA,EACLsC,QAAS7E,EAAK6E,QACdC,MAAOU,EAAKV,MACZE,OAAQQ,EAAKR,OACbvE,MAAM,GAAK7L,OAAQE,eAI3B+B,OAAOwC,MAAM,2BAEb,IAAIsM,GAAU7M,gBAAgBrD,MAG9B,IAAImQ,GAAqB,SAAS5F,GAC9B,MAAI2F,KAAY,GACZnC,WAAW,WACPpN,KAAK+C,iBACL6G,EAAKR,OAASpB,SAASyH,OACvBxI,EAASyI,OACTzI,EAASnD,SACV,IACI,IAEPyL,EAAU7M,gBAAgBrD,QACnB,GAyPf,OAnPA4H,GAASwC,KAAK,QAAS,SAAUmC,GAC7B,MAAO,UAASrC,EAAIoG,GAChBlP,OAAO+I,MAAM,yBACb/I,OAAO+I,MAAM,QAASmG,EACtB,IAAIC,GAAS,EACb,IAAIhG,GAAO+F,EAAI/F,IACf,IAAIA,EAAM,CACN,OAAQ+F,EAAI9N,MACR,IAAKmG,UAAS6H,OACVD,EAAS,oEACT,MACJ,KAAK5H,UAAS8H,gBACV,GAAI/B,GAAgBxE,EAAG2B,WAAa3B,EAAG2B,UAAU,gBACjD6C,GAAgBA,GAAkBxE,EAAG4B,UAAY5B,EAAG4B,SAAS4C,cAC7D6B,EAAS,mDAAa7B,EAAgB,sFACtC,MACJ,KAAK/F,UAAS+H,qBACVH,EAAS,gFACT,MACJ,KAAK5H,UAASgI,WACV,GAAqB,KAAjBL,EAAIN,SAAiB,CAGrB,GADAO,EAASD,EAAIM,SAAW,8CACnBT,EAAmB5F,GACpB,MAEJ,OAEJ,GAAIsG,GAAWlQ,KAAKiG,UAAU0J,EAAIN,SAClC,IAAIc,GAAYD,EAAS1G,KACzB,QAAQmG,EAAIvG,QACR,IAAK,KACDwG,EAAS,wDACT,MACJ,KAAK,KACDA,EAAS,oHACT,MACJ,KAAK,KACDA,EAAS,wGACT,MACJ,KAAK,KACDA,EAAS,gFACT,MACJ,KAAK,KAED,GADAA,EAAS,oGACJJ,EAAmB5F,GACpB,MAEJ,MACJ,KAAK,KACDgG,EAAS,sCACT,KACIM,EAAWlQ,KAAKiG,UAAUiK,EAAS1G,OACnC2G,EAAYD,EAAS1G,OAAS,cAChC,MAAO4G,GACLD,EAAYD,EAAS1G,OAAS,cAElC,KACJ,KAAK,KACDoG,EAAS,kDACT,MACJ,KAAK,KACDA,EAAS,oHACT,MACJ,SAEI,GADAA,EAAS,kCACJJ,EAAmB5F,GACpB,OAIZgG,EAASA,EAAS,IAAMD,EAAIvG,OAAS,SAAM+G,EAAY,GACvD,MACJ,KAAKnI,UAASqI,eACVT,EAAS,kGACT,MACJ,KAAK5H,UAASsI,cACVV,EAAS,oEACT,MACJ,KAAK5H,UAASuI,SACVX,EAAS,oEACT,MACJ,KAAK5H,UAASwI,WACVZ,EAAS,mGACT3I,EAASwJ,SACT,MACJ,SAEI,GADAb,EAASD,EAAIM,QAAUN,EAAIe,SACtBlB,EAAmB5F,GACpB,OAIRgC,GACAA,EAAerC,EAAIoG,EAAKC,GAGhCrG,EAAG8D,YAERzB,IAEHnL,OAAOwC,MAAM,oBAMbgE,EAASwC,KAAK,eAAgB,SAAUsC,GACpC,MAAO,UAASxC,EAAIK,EAAMwF,GACtB3O,OAAOwC,MAAM,gCACbxC,OAAOwC,MAAM,SAAU2G,GACvBnJ,OAAOwC,MAAM,SAAUmM,EACvB,IAAIuB,GAAY,SAASpH,EAAIK,EAAMwF,GAC/B,GAAIlI,EAAG0J,cAAe,CAGlB,GAAIC,GAAiB7Q,KAAK4F,YAC1BiL,GAAe5H,KAAK,OAAQ/B,EAAG0J,eAAe,GAC9CC,EAAe3G,iBAAiB,eAAgB,qCAChD2G,EAAe3H,mBAAqB,WAChC,GAAkC,IAA9B2H,EAAe1H,WACf,GAA8B,MAA1B0H,EAAezH,OAAgB,CAC/B,GAAI0H,EACJ,KACIA,EAAgB9Q,KAAKiG,UAAU4K,EAAevH,cAChD,MAAO8G,GACL,KAAM,sBAEV,GAAIW,KACJ/I,UAAS4E,OAAOmE,EAAe/Q,KAAKiG,UAAUmJ,GAAO0B,GACjD/E,GACAA,EAAsBxC,EAAIK,EAAM5J,KAAKuB,cAAcwP,QAGvD9J,GAAS+J,QAAQ,SACb5H,OAAQyH,EAAezH,OACvBiG,SAAUwB,EAAevH,aACzBM,KAAMA,EACN/H,KAAMmG,SAASgI,cAK/Ba,EAAenH,KAAK,OAAS1J,KAAKiG,UAAUmJ,GAAMhR,IAAM,WAAa8I,EAAGqE,YACjEQ,IACPA,EAAsBxC,EAAIK,EAAMwF,GAIxC,IAAI/F,GAAMrJ,KAAKiG,UAAUmJ,EAAKC,SAS9B,IARAlD,EAAMA,EAAMA,EAAM9C,EAAI8C,IAOtB1L,OAAOwC,MAAM,QAASkJ,GAClBA,EAAK,CACL,GAAI/N,GAAM,EACVqC,QAAOwC,MAAM,aAAciE,EAAG+D,UACzB/D,EAAG+D,WACJ7M,EAAM2M,EAAWxB,EAAIK,EAAM5J,KAAKiM,aAChC7N,EAAMA,EAAM,QAAU4B,KAAKyF,oBAAoBrH,GAAO,GAG1D,IAAI6S,GAAQ,UAAYjR,KAAKyF,oBAAoBmE,EAAKwB,KAEtD3K,QAAOwC,MAAM,cAAeiE,EAAGuG,OAC/B,IAAIA,GAASvG,EAAGuG,OACZyD,EAAQ,GACRC,EAAa,EACjB,IAAezD,SAAXD,GAA0C,gBAAXA,GAC/B,IAAK,GAAIE,KAASF,GACVA,EAAOnL,eAAeqL,KACO,kBAAlBF,GAAOE,GACduD,EAAQlR,KAAKyF,oBAAoBgI,EAAOE,GAAOpE,EAAIK,IACnB,gBAAlB6D,GAAOE,KACrBuD,EAAQlR,KAAKyF,oBAAoBgI,EAAOE,KAE5CwD,GAAc,MAAQxD,EAAQ,IAAMuD,EAKhD,IAAI/N,GAAMZ,eAAiB,WAAaqH,EAAKuE,KAAO/P,EAAM6S,EAAQE,CAElE,IAAI/J,GAAKpH,KAAKE,iBACd,IAAI4I,EACA1B,IAAY,GAANA,GACN0B,EAAO,GAAIrB,OAAM1B,eACjB0B,MAAMC,IAAIqB,QAAU7B,EAAG8B,eAEvBF,EAAO9I,KAAK4F,aAEhBkD,EAAKG,KAAK,OAAQ9F,GAAK,GACvB2F,EAAKoB,iBAAiB,eAAgB,4BACtCpB,EAAKoB,iBAAiB,gBAAiB,WAAalK,KAAK6J,MACzD,IAAIX,GAAqB,WAErB,GADAzI,OAAOwC,MAAM,oBAAqB6F,EAAKK,YACf,IAApBL,EAAKK,WAAkB,CACvBxJ,aAAaG,WAAW8J,EAAKwB,KAC7B,IAAIgE,EACgB,OAAhBtG,EAAKM,QACLgG,EAAOtG,EAAKQ,aACZ7I,OAAOwC,MAAM,sBAAuBmM,GACpCuB,EAAUpH,EAAIK,EAAMwF,KAEpBA,GACIhG,OAAQN,EAAKM,OACbiG,SAAUvG,EAAKQ,aACfM,KAAMA,EACN/H,KAAM,KACNuP,gBAAiBtI,EAAKuI,yBAE1B5Q,OAAOwC,MAAM,oBAAqBmM,GAClCnI,EAAS+J,QAAQ,QAAS5B,KAIlChI,IAAY,GAANA,EACN0B,EAAKW,KAAK,mBAAoBP,GAE9BJ,EAAKI,mBAAqBA,EAE9BJ,EAAKY,KAAKyC,GACV1L,OAAOwC,MAAM,WAAYE,OAEzBwN,GAAUpH,EAAIK,EAAMwF,EAAKC,YAIlCtD,IAEHtL,OAAOwC,MAAM,2BAGbgE,EAAS4E,OAETpL,OAAOwC,MAAM,0BAEbxC,OAAOwC,MAAM,qBAENgE,GAQXhH,KAAKqR,OAAS,SAASlT,GACnB,IAAKA,EACD,OAAO,CAEXA,GAAMmT,UAAUnT,EAChB,IAAImN,GAAStL,KAAKsL,MAIlB,OAHwC,MAApCA,EAAOrJ,MAAMqJ,EAAOlM,OAAS,KAC7BkM,GAAkB,KAEfA,EAASnN,GASpB6B,KAAKuR,WAAa,SAAStK,EAAI9I,GAE3B,IAAK,OAAOgF,KAAK8D,EAAGuK,MAChB,OAAO,CAGX,IAAIA,GAAOvK,EAAGuK,KACVC,EAAIxK,EAAGwK,GAAK,GACZC,EAAIzK,EAAGyK,GAAK,GACZC,EAAI1K,EAAG0K,GAAK,GACZC,EAAS3K,EAAG2K,QAAU,EAE1B,KAAKH,IAAMC,EACP,OAAO,CAGX,IAAIG,GAAW,cAAgBL,CAQ/B,OAPAK,IAAYJ,EAAI,MAAQA,EAAI,GAC5BI,GAAYH,EAAI,MAAQA,EAAI,GAC5BG,GAAYF,EAAI,MAAQA,EAAI,GAC5BE,GAAYD,EAAS,WAAaA,EAAS,GACvCzT,IACA0T,EAAW7R,KAAKqR,OAAOlT,GAAO,IAAM0T,GAEjCA,GASX7R,KAAK8R,WAAa,SAAS7K,EAAI9I,GAC3B,GAAI4T,GAAc9K,EAAG,gBAAkB,GACnC+K,EAAY/K,EAAG+K,WAAa,GAC5BC,EAAQhL,EAAGgL,OAAS,GACpBC,EAAUjL,EAAGiL,SAAW,GACxBC,EAAOlL,EAAGkL,MAAQ,GAClBC,EAAUnL,EAAGmL,SAAW,GACxBC,EAASpL,EAAGoL,QAAU,GACtBT,EAAS3K,EAAG2K,QAAU,GACtBU,EAAOrL,EAAGqL,MAAQ,EAGtB,IAAIT,GAAW,YAef,OAbAA,IAAYE,EAAc,eAAiB,GAC3CF,GAAYG,EAAY,cAAgBA,EAAY,GACpDH,GAAYI,EAAQ,SAAW,GAC/BJ,GAAYK,EAAU,YAAcA,EAAU,GAC9CL,GAAYO,EAAU,YAAcA,EAAU,GAC9CP,GAAYM,EAAO,SAAWA,EAAO,GACrCN,GAAYQ,EAAS,WAAaA,EAAS,GAC3CR,GAAYD,EAAS,WAAaA,EAAS,GAC3CC,GAAYS,EAAO,SAAWA,EAAO,GAEjCnU,IACA0T,EAAW7R,KAAKqR,OAAOlT,GAAO,IAAM0T,GAEjCA,GASX7R,KAAKuS,UAAY,SAAStL,EAAI9I,GAC1B,GAAIqT,GAAOvK,EAAGuK,IACd,KAAKA,EACD,OAAO,CAGX,IAAIK,GAAW,aAAeL,CAE9B,IAAa,IAATA,EAAY,CACZ,GAAIgB,GAAQvL,EAAGuL,OAAS,EACxB,KAAKA,EACD,OAAO,CAEXX,IAAYW,EAAQ,UAAYxS,KAAKwF,oBAAoBgN,GAAS,OAC/D,CAAA,GAAa,IAAThB,EAcP,OAAO,CAbP,IAAIpL,GAAOa,EAAGb,KAAOa,EAAGb,KAAO,GAC3BqM,EAAOxL,EAAGwL,KAAOxL,EAAGwL,KAAO,GAC3BC,EAAWzL,EAAGyL,SAAWzL,EAAGyL,SAAW,GACvCC,EAAO1L,EAAG0L,KAAO1L,EAAG0L,KAAO,EAC/B,KAAKvM,EACD,OAAO,CAEXyL,IAAYzL,EAAO,SAAWpG,KAAKwF,oBAAoBY,GAAQ,GAC/DyL,GAAYY,EAAO,SAAWzS,KAAKwF,oBAAoBiN,GAAQ,GAC/DZ,GAAYa,EAAW,aAAeA,EAAW,GACjDb,GAAYc,EAAO,SAAW3S,KAAKwF,oBAAoBmN,GAAQ,GAMnE,GAAIC,GAAW3L,EAAG2L,UAAY,GAC1BV,EAAUjL,EAAGiL,SAAW,GACxBW,EAAK5L,EAAG4L,IAAM,GACdC,EAAK7L,EAAG6L,IAAM,EAUlB,OARAjB,IAAYe,EAAW,aAAeA,EAAW,GACjDf,GAAYK,EAAU,YAAcA,EAAU,GAC9CL,GAAYgB,EAAK,OAASA,EAAK,GAC/BhB,GAAYiB,EAAK,OAASA,EAAK,GAE3B3U,IACA0T,EAAW7R,KAAKqR,OAAOlT,GAAO,IAAM0T,GAEjCA,GAQX7R,KAAK+S,UAAY,SAAS5U,GACtB,IAAKA,EACD,OAAO,CAEX,IAAI+E,GAAMlD,KAAKqR,OAAOlT,GAAO,YAC7B,IAAI6U,GAAMhT,KAAK2F,YACf,IAAIwJ,EACJ,IAAIpP,GAAOC,IAQX,OAPAgT,GAAIhK,KAAK,MAAO9F,GAAK,GACrB8P,EAAI/J,mBAAqB,WACE,IAAnB+J,EAAI9J,YAAmC,MAAf8J,EAAI7J,SAC5BgG,EAAOpP,EAAKiG,UAAUgN,EAAI3J,gBAGlC2J,EAAIvJ,OACG0F,GAQXnP,KAAKiT,KAAO,SAAS9U,GACjB,IAAKA,EACD,OAAO,CAEX,IAAI+E,GAAMlD,KAAKqR,OAAOlT,GAAO,OAC7B,IAAI6U,GAAMhT,KAAK2F,YACf,IAAIwJ,EACJ,IAAIpP,GAAOC,IAQX,OAPAgT,GAAIhK,KAAK,MAAO9F,GAAK,GACrB8P,EAAI/J,mBAAqB,WACE,IAAnB+J,EAAI9J,YAAmC,MAAf8J,EAAI7J,SAC5BgG,EAAOpP,EAAKiG,UAAUgN,EAAI3J,gBAGlC2J,EAAIvJ,OACG0F,GAUXnP,KAAKkT,IAAM,SAAShS,EAAM/C,GACtB,MAAKA,IAAQ+C,EAGA,SAATA,EACOlB,KAAKiT,KAAK9U,GACD,cAAT+C,EACAlB,KAAK+S,UAAU5U,IAEnB,GAPI,GAkBf6B,KAAKmT,SAAW,SAASC,EAAKjV,GAC1B,GAAIkV,GAAkD,mBAAxCC,OAAOtR,UAAUuE,SAASrE,KAAKkR,EAC7C,IAAI1H,GAAQ6H,EAAO1B,EAAW,EAC9B,IAAIwB,EAAS,CACT,IAAK,GAAInU,GAAI,EAAG2H,EAAMuM,EAAIhU,OAAYyH,EAAJ3H,EAASA,IAAK,CAE5C,GADAwM,EAAS0H,EAAIlU,IACRwM,EAAO8H,IACR,OAAO,CAEX,QAAQ9H,EAAO8H,KACX,IAAK,YACD3B,GAAY7R,KAAKuS,UAAU7G,GAAU,GACrC,MACJ,KAAK,aACDmG,GAAY7R,KAAKuR,WAAW7F,GAAU,GACtC,MACJ,KAAK,aACDmG,GAAY7R,KAAK8R,WAAWpG,GAAU,GACtC,MACJ,SACI6H,GAAQ,EAGhB,GAAIA,EACA,OAAO,EAGf,GAAIpV,EAAK,CACL0T,EAAW7R,KAAKqR,OAAOlT,GAAO,IAAM0T,CACpC,IAAIzS,GAASyS,EAASzS,MACa,OAA/ByS,EAAS5P,MAAM7C,EAAS,KACxByS,EAAWA,EAAS5P,MAAM,EAAG7C,EAAS,IAG9C,MAAOyS,GAEX,OAAO,GAIf,GAAI4B,OAAQ,GAAI3T,WAEhB7B,QAAOwV,MAAQA,MAEfxV,OAAO6B,WAAaA,YAEhBL"}
\ No newline at end of file
diff --git a/qiniu_fields/static/qiniu_fields/qiniu/ui.js b/qiniu_fields/static/qiniu_fields/qiniu/ui.js
new file mode 100644
index 0000000..545a875
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/qiniu/ui.js
@@ -0,0 +1,233 @@
+/*global plupload */
+/*global qiniu */
+function FileProgress(file, targetID) {
+ this.fileProgressID = file.id;
+ this.file = file;
+
+ this.opacity = 100;
+ this.height = 0;
+ this.fileProgressWrapper = $('#' + this.fileProgressID);
+ if (!this.fileProgressWrapper.length) {
+ this.fileProgressWrapper = $('
');
+ var Wrappeer = this.fileProgressWrapper;
+ Wrappeer.attr('id', this.fileProgressID).addClass('progressContainer');
+
+ var progressBarBox = $("
");
+ progressBarBox.addClass('info');
+ var progressBarWrapper = $("
");
+ progressBarWrapper.addClass("progress progress-striped");
+ progressBarWrapper.attr('style', 'width: 200px');
+
+ var progressBar = $("
");
+ progressBar.addClass("progress-bar progress-bar-info")
+ .attr('role', 'progressbar')
+ .attr('aria-valuemax', 100)
+ .attr('aria-valuenow', 0)
+ .attr('aria-valuein', 0)
+ .width('0%');
+
+ progressBarWrapper.append(progressBar);
+ progressBarBox.append(progressBarWrapper);
+
+ var progressBarStatus = $(' ');
+ progressBarBox.append(progressBarStatus);
+ var progressCancel = $(' ');
+ progressCancel.show().addClass('progressCancel ml15').text('×');
+ progressBarBox.append(progressCancel);
+
+ Wrappeer.append(progressBarBox);
+
+ $('#' + targetID).append(Wrappeer);
+ } else {
+ this.reset();
+ }
+
+ this.height = this.fileProgressWrapper.offset().top;
+ this.setTimer(null);
+}
+
+FileProgress.prototype.setTimer = function(timer) {
+ this.fileProgressWrapper.FP_TIMER = timer;
+};
+
+FileProgress.prototype.getTimer = function(timer) {
+ return this.fileProgressWrapper.FP_TIMER || null;
+};
+
+FileProgress.prototype.reset = function() {
+ this.fileProgressWrapper.attr('class', "progressContainer");
+ this.fileProgressWrapper.find('td .progress .progress-bar-info').attr('aria-valuenow', 0).width('0%').find('span').text('');
+ this.appear();
+};
+
+FileProgress.prototype.setChunkProgress = function(chunk_size) {
+ var chunk_amount = Math.ceil(this.file.size / chunk_size);
+ if (chunk_amount === 1) {
+ return false;
+ }
+
+ var viewProgress = $('查看分块上传进度 ');
+ var progressBarChunkTr = $(' ');
+ var progressBarChunk = $('
');
+ for (var i = 1; i <= chunk_amount; i++) {
+ var col = $('
');
+ var progressBarWrapper = $('
");
+ progressBar.addClass("progress-bar progress-bar-info text-left")
+ .attr('role', 'progressbar')
+ .attr('aria-valuemax', 100)
+ .attr('aria-valuenow', 0)
+ .attr('aria-valuein', 0)
+ .width('0%')
+ .attr('id', this.file.id + '_' + i)
+ .text('');
+
+ var progressBarStatus = $(' ');
+ progressBarStatus.addClass('chunk-status').text();
+
+ progressBarWrapper.append(progressBar);
+ progressBarWrapper.append(progressBarStatus);
+
+ col.append(progressBarWrapper);
+ progressBarChunk.append(col);
+ }
+
+ if(!this.fileProgressWrapper.find('td:eq(2) .btn-default').length){
+ this.fileProgressWrapper.find('td>div').append(viewProgress);
+ }
+ progressBarChunkTr.hide().find('td').append(progressBarChunk);
+ progressBarChunkTr.insertAfter(this.fileProgressWrapper);
+
+};
+
+FileProgress.prototype.setProgress = function(percentage, speed, chunk_size) {
+ this.fileProgressWrapper.attr('class', "progressContainer green");
+
+ var file = this.file;
+ var uploaded = file.loaded;
+ var totalSize = plupload.formatSize(file.size).toUpperCase(),
+ size = plupload.formatSize(uploaded).toUpperCase();
+ var formatSpeed = plupload.formatSize(speed).toUpperCase();
+ var progressbar = this.fileProgressWrapper.find('div.progress').find('.progress-bar-info');
+ if (this.fileProgressWrapper.find('.status').text() === '取消上传') {
+ return;
+ }
+ this.fileProgressWrapper.find('.status').text("已上传: " + size + ' / ' + totalSize + " 上传速度: " + formatSpeed + "/s");
+ percentage = parseInt(percentage, 10);
+ if (file.status !== plupload.DONE && percentage === 100) {
+ percentage = 99;
+ }
+ progressbar.attr('aria-valuenow', percentage).css('width', percentage + '%');
+
+ if (chunk_size) {
+ var chunk_amount = Math.ceil(file.size / chunk_size);
+ if (chunk_amount === 1) {
+ return false;
+ }
+ var current_uploading_chunk = Math.ceil(uploaded / chunk_size);
+ var pre_chunk, text;
+
+ for (var index = 0; index < current_uploading_chunk; index++) {
+ pre_chunk = $('#' + file.id + "_" + index);
+ pre_chunk.width('100%').removeClass().addClass('alert-success').attr('aria-valuenow', 100);
+ text = "块" + index + "上传进度100%";
+ pre_chunk.next().html(text);
+ }
+
+ var currentProgessBar = $('#' + file.id + "_" + current_uploading_chunk);
+ var current_chunk_percent;
+ if (current_uploading_chunk < chunk_amount) {
+ if (uploaded % chunk_size) {
+ current_chunk_percent = ((uploaded % chunk_size) / chunk_size * 100).toFixed(2);
+ } else {
+ current_chunk_percent = 100;
+ currentProgessBar.removeClass().addClass('alert-success');
+ }
+ } else {
+ var last_chunk_size = file.size - chunk_size * (chunk_amount - 1);
+ var left_file_size = file.size - uploaded;
+ if (left_file_size % last_chunk_size) {
+ current_chunk_percent = ((uploaded % chunk_size) / last_chunk_size * 100).toFixed(2);
+ } else {
+ current_chunk_percent = 100;
+ currentProgessBar.removeClass().addClass('alert-success');
+ }
+ }
+ currentProgessBar.width(current_chunk_percent + '%');
+ currentProgessBar.attr('aria-valuenow', current_chunk_percent);
+ text = "块" + current_uploading_chunk + "上传进度" + current_chunk_percent + '%';
+ currentProgessBar.next().html(text);
+ }
+
+ this.appear();
+};
+
+FileProgress.prototype.setComplete = function(up, info) {
+ var td = this.fileProgressWrapper.find('td:eq(2)'),
+ tdProgress = td.find('.progress');
+ tdProgress.html('').removeClass().next().next('.status').hide();
+ td.find('.progressCancel').hide();
+};
+FileProgress.prototype.setError = function() {
+ this.fileProgressWrapper.find('td:eq(2)').attr('class', 'text-warning');
+ this.fileProgressWrapper.find('td:eq(2) .progress').css('width', 0).hide();
+ this.fileProgressWrapper.find('button').hide();
+ this.fileProgressWrapper.next('.chunk-status-tr').hide();
+};
+
+FileProgress.prototype.setCancelled = function(manual) {
+ var progressContainer = 'progressContainer';
+ if (!manual) {
+ progressContainer += ' red';
+ }
+ this.fileProgressWrapper.attr('class', progressContainer);
+ this.fileProgressWrapper.find('td .progress').remove();
+ this.fileProgressWrapper.find('td:eq(2) .btn-default').hide();
+ this.fileProgressWrapper.find('td:eq(2) .progressCancel').hide();
+};
+
+FileProgress.prototype.setStatus = function(status, isUploading) {
+ if (!isUploading) {
+ this.fileProgressWrapper.find('.status').text(status).attr('class', 'status text-left');
+ }
+};
+
+// 绑定取消上传事件
+FileProgress.prototype.bindUploadCancel = function(up) {
+ var self = this;
+ if (up) {
+ self.fileProgressWrapper.find('td:eq(2) .progressCancel').on('click', function(){
+ self.setCancelled(false);
+ self.setStatus("取消上传");
+ self.fileProgressWrapper.find('.status').css('left', '0');
+ up.removeFile(self.file);
+ });
+ }
+
+};
+
+FileProgress.prototype.appear = function() {
+ if (this.getTimer() !== null) {
+ clearTimeout(this.getTimer());
+ this.setTimer(null);
+ }
+
+ if (this.fileProgressWrapper[0].filters) {
+ try {
+ this.fileProgressWrapper[0].filters.item("DXImageTransform.Microsoft.Alpha").opacity = 100;
+ } catch (e) {
+ // If it is not set initially, the browser will throw an error. This will set it if it is not set yet.
+ this.fileProgressWrapper.css('filter', "progid:DXImageTransform.Microsoft.Alpha(opacity=100)");
+ }
+ } else {
+ this.fileProgressWrapper.css('opacity', 1);
+ }
+
+ this.fileProgressWrapper.css('height', '');
+
+ this.height = this.fileProgressWrapper.offset().top;
+ this.opacity = 100;
+ this.fileProgressWrapper.show();
+
+};
diff --git a/qiniu_fields/static/qiniu_fields/qiniu/ui.min.js b/qiniu_fields/static/qiniu_fields/qiniu/ui.min.js
new file mode 100644
index 0000000..11131d1
--- /dev/null
+++ b/qiniu_fields/static/qiniu_fields/qiniu/ui.min.js
@@ -0,0 +1,2 @@
+function FileProgress(c,b){this.fileProgressID=c.id;this.file=c;this.opacity=100;this.height=0;this.fileProgressWrapper=$("#"+this.fileProgressID);if(!this.fileProgressWrapper.length){this.fileProgressWrapper=$("
");var e=this.fileProgressWrapper;e.attr("id",this.fileProgressID).addClass("progressContainer");var d=$("
");d.addClass("info");var h=$("
");h.addClass("progress progress-striped");h.attr("style","width: 200px");var g=$("
");g.addClass("progress-bar progress-bar-info").attr("role","progressbar").attr("aria-valuemax",100).attr("aria-valuenow",0).attr("aria-valuein",0).width("0%");h.append(g);d.append(h);var a=$(' ');d.append(a);var f=$(" ");f.show().addClass("progressCancel ml15").text("×");d.append(f);e.append(d);$("#"+b).append(e)}else{this.reset()}this.height=this.fileProgressWrapper.offset().top;this.setTimer(null)}FileProgress.prototype.setTimer=function(a){this.fileProgressWrapper.FP_TIMER=a};FileProgress.prototype.getTimer=function(a){return this.fileProgressWrapper.FP_TIMER||null};FileProgress.prototype.reset=function(){this.fileProgressWrapper.attr("class","progressContainer");this.fileProgressWrapper.find("td .progress .progress-bar-info").attr("aria-valuenow",0).width("0%").find("span").text("");this.appear()};FileProgress.prototype.setChunkProgress=function(j){var k=Math.ceil(this.file.size/j);if(k===1){return false}var f=$('查看分块上传进度 ');var e=$(' ');var g=$("
");for(var c=1;c<=k;c++){var b=$('
');var a=$('
");d.addClass("progress-bar progress-bar-info text-left").attr("role","progressbar").attr("aria-valuemax",100).attr("aria-valuenow",0).attr("aria-valuein",0).width("0%").attr("id",this.file.id+"_"+c).text("");var h=$(" ");h.addClass("chunk-status").text();a.append(d);a.append(h);b.append(a);g.append(b)}if(!this.fileProgressWrapper.find("td:eq(2) .btn-default").length){this.fileProgressWrapper.find("td>div").append(f)}e.hide().find("td").append(g);e.insertAfter(this.fileProgressWrapper)};FileProgress.prototype.setProgress=function(i,o,n){this.fileProgressWrapper.attr("class","progressContainer green");var q=this.file;var r=q.loaded;var k=plupload.formatSize(q.size).toUpperCase(),m=plupload.formatSize(r).toUpperCase();var e=plupload.formatSize(o).toUpperCase();var d=this.fileProgressWrapper.find("div.progress").find(".progress-bar-info");if(this.fileProgressWrapper.find(".status").text()==="取消上传"){return}this.fileProgressWrapper.find(".status").text("已上传: "+m+" / "+k+" 上传速度: "+e+"/s");i=parseInt(i,10);if(q.status!==plupload.DONE&&i===100){i=99}d.attr("aria-valuenow",i).css("width",i+"%");if(n){var f=Math.ceil(q.size/n);if(f===1){return false}var h=Math.ceil(r/n);var b,j;for(var c=0;c
+ {{ current_label }} {{ widget.value }}
+ 选择文件
+
+
+
+
+
diff --git a/qiniu_fields/templates/file_list.html b/qiniu_fields/templates/file_list.html
new file mode 100644
index 0000000..b4882ba
--- /dev/null
+++ b/qiniu_fields/templates/file_list.html
@@ -0,0 +1,107 @@
+
+
+ 选择文件
+
+
+
diff --git a/qiniu_fields/widgets.py b/qiniu_fields/widgets.py
new file mode 100644
index 0000000..e486009
--- /dev/null
+++ b/qiniu_fields/widgets.py
@@ -0,0 +1,55 @@
+#! -*- coding: utf-8 -*-
+from django import forms
+from django.conf import settings
+from django.utils.html import smart_urlquote
+
+
+class QiniuFileWidget(forms.URLInput):
+ input_type = 'file'
+ template_name = 'file.html'
+
+ def __init__(self, attrs=None):
+ final_attrs = {
+ 'domain': settings.QINIU_DOMAIN,
+ 'uptoken_url': settings.QINIU_UPTOKEN_URL,
+ }
+ if attrs is not None:
+ final_attrs.update(attrs)
+ super(QiniuFileWidget, self).__init__(attrs=final_attrs)
+
+ def get_context(self, name, value, attrs):
+ context = super(QiniuFileWidget, self).get_context(name, value, attrs)
+ context['current_label'] = '当前:'
+ context['widget']['href'] = smart_urlquote(context['widget']['value']) if value else ''
+ return context
+
+ @property
+ def media(self):
+ return forms.Media(js=('qiniu_fields/plupload/plupload.full.min.js', 'qiniu_fields/plupload/i18n/zh_CN.js',
+ 'qiniu_fields/qiniu/qiniu.min.js', 'qiniu_fields/qiniu/ui.min.js'))
+
+ # class Media:
+ # js = ('qiniu_fields/plupload/plupload.full.min.js', 'qiniu_fields/plupload/i18n/zh_CN.js',
+ # 'qiniu_fields/qiniu/qiniu.min.js', 'qiniu_fields/qiniu/ui.min.js')
+
+
+class QiniuFileListWidget(forms.Textarea):
+ template_name = 'file_list.html'
+
+ def __init__(self, attrs=None):
+ final_attrs = {
+ 'domain': settings.QINIU_DOMAIN,
+ 'uptoken_url': settings.QINIU_UPTOKEN_URL,
+ }
+ if attrs is not None:
+ final_attrs.update(attrs)
+ super(QiniuFileListWidget, self).__init__(attrs=final_attrs)
+
+ @property
+ def media(self):
+ return forms.Media(js=('qiniu_fields/plupload/plupload.full.min.js', 'qiniu_fields/plupload/i18n/zh_CN.js',
+ 'qiniu_fields/qiniu/qiniu.min.js', 'qiniu_fields/qiniu/ui.min.js'))
+
+ # class Media:
+ # js = ('qiniu_fields/plupload/plupload.full.min.js', 'qiniu_fields/plupload/i18n/zh_CN.js',
+ # 'qiniu_fields/qiniu/qiniu.min.js', 'qiniu_fields/qiniu/ui.min.js')
diff --git a/qiniu_fields_demo/__init__.py b/qiniu_fields_demo/__init__.py
new file mode 100644
index 0000000..063cd2c
--- /dev/null
+++ b/qiniu_fields_demo/__init__.py
@@ -0,0 +1,2 @@
+import pymysql
+pymysql.install_as_MySQLdb()
diff --git a/qiniu_fields_demo/settings.py b/qiniu_fields_demo/settings.py
new file mode 100644
index 0000000..fc738e4
--- /dev/null
+++ b/qiniu_fields_demo/settings.py
@@ -0,0 +1,141 @@
+"""
+Django settings for qiniu_fields_demo project.
+
+Generated by 'django-admin startproject' using Django 1.11.5.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.11/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.11/ref/settings/
+"""
+
+import os
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'b(2kyt&=@kb!te4394*o4z**%7w9yi#back++rv2r@2=(iu+um'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = ['*']
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+
+ 'xadmin',
+ 'crispy_forms',
+ 'reversion',
+ 'qiniu_fields',
+ 'demo',
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'qiniu_fields_demo.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'qiniu_fields_demo.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.mysql',
+ 'USER': 'root',
+ 'PASSWORD': '123456',
+ 'HOST': '127.0.0.1',
+ 'PORT': '3306',
+ 'NAME': 'qiniu_fields',
+ },
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.11/topics/i18n/
+
+LANGUAGE_CODE = 'zh-hans'
+
+TIME_ZONE = 'Asia/Shanghai'
+
+USE_I18N = True
+
+USE_L10N = False
+
+USE_TZ = False
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.11/howto/static-files/
+
+STATIC_URL = '/static/'
+
+# date and datetime field formats
+DATE_FORMAT = 'Y-m-d'
+DATETIME_FORMAT = 'Y-m-d H:i:s'
+
+# 七牛云存储
+QINIU_ACCESS_KEY = 'qiniu-access-key' # your own
+QINIU_SECRET_KEY = 'qiniu-secret-key' # your own
+QINIU_BUCKET = 'bucket-name' # your own
+QINIU_DOMAIN = 'qiniu-domain-or-your-own-domain' # your own
+QINIU_UPTOKEN_URL = '/console/api/get_qiniu_token'
diff --git a/qiniu_fields_demo/urls.py b/qiniu_fields_demo/urls.py
new file mode 100644
index 0000000..7501f40
--- /dev/null
+++ b/qiniu_fields_demo/urls.py
@@ -0,0 +1,37 @@
+"""prizeclaw URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/1.11/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.conf.urls import url, include
+ 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
+"""
+from django.conf.urls import url
+from django.conf import settings
+
+from demo.views import get_qiniu_token
+
+import xadmin
+from xadmin.plugins import xversion
+
+from reversion.models import Revision
+xadmin.site.unregister(Revision)
+
+xadmin.autodiscover()
+xversion.register_models()
+
+urlpatterns = [
+ url(r'^console/', xadmin.site.urls),
+ url(r'^console/api/get_qiniu_token$', get_qiniu_token, name='get_qiniu_token'),
+]
+
+if settings.DEBUG:
+ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
+ urlpatterns += staticfiles_urlpatterns()
diff --git a/qiniu_fields_demo/wsgi.py b/qiniu_fields_demo/wsgi.py
new file mode 100644
index 0000000..c8560bf
--- /dev/null
+++ b/qiniu_fields_demo/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for qiniu_fields_demo project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "qiniu_fields_demo.settings")
+
+application = get_wsgi_application()
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..f2d2d3d
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+django==1.11.5
+pymysql==0.7.11
+django-reversion
+git+git://github.com/WuXianglong/xadmin.git
+qiniu