diff --git a/.htaccess b/.htaccess
index e29b143e..d9ee23c9 100644
--- a/.htaccess
+++ b/.htaccess
@@ -6,4 +6,3 @@
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
-SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
\ No newline at end of file
diff --git a/application/config.php b/application/config.php
index a7d2ce8a..30b42d7b 100644
--- a/application/config.php
+++ b/application/config.php
@@ -18,7 +18,7 @@ return [
// 应用命名空间
'app_namespace' => 'app',
// 应用调试模式
- 'app_debug' => false,
+ 'app_debug' => true,
// 应用Trace
'app_trace' => false,
// 应用模式状态
diff --git a/application/index/model/FileManage.php b/application/index/model/FileManage.php
index b256641e..b6ed25e0 100644
--- a/application/index/model/FileManage.php
+++ b/application/index/model/FileManage.php
@@ -824,18 +824,23 @@ class FileManage extends Model{
$speedLimit = Db::name('groups')->where('id',$this->userData["user_group"])->find();
$rangeTransfer = $speedLimit["range_transfer"];
$speedLimit = $speedLimit["speed"];
- if($isAdmin){
- $speedLimit="";
- }
- if($speedLimit == "0"){
- exit();
- }else if(empty($speedLimit)){
- header("Cache-Control: max-age=10800");
- $this->outputWithoutLimit(false,$rangeTransfer);
- exit();
- }else if((int)$speedLimit > 0){
- header("Cache-Control: max-age=10800");
- $this->outputWithLimit($speedLimit);
+ $sendFileOptions = Option::getValues(["download"]);
+ if($sendFileOptions["sendfile"] == "1"){
+ $this->sendFile($speedLimit,$rangeTransfer,false,$sendFileOptions["header"]);
+ }else{
+ if($isAdmin){
+ $speedLimit="";
+ }
+ if($speedLimit == "0"){
+ exit();
+ }else if(empty($speedLimit)){
+ header("Cache-Control: max-age=10800");
+ $this->outputWithoutLimit(false,$rangeTransfer);
+ exit();
+ }else if((int)$speedLimit > 0){
+ header("Cache-Control: max-age=10800");
+ $this->outputWithLimit($speedLimit);
+ }
}
}
@@ -843,16 +848,38 @@ class FileManage extends Model{
$speedLimit = Db::name('groups')->where('id',$this->userData["user_group"])->find();
$rangeTransfer = $speedLimit["range_transfer"];
$speedLimit = $speedLimit["speed"];
- if($isAdmin){
- $speedLimit = "";
- }
- if($speedLimit == "0"){
- exit();
- }else if(empty($speedLimit)){
- $this->outputWithoutLimit(true,$rangeTransfer);
- exit();
- }else if((int)$speedLimit > 0){
- $this->outputWithLimit($speedLimit,true);
+ $sendFileOptions = Option::getValues(["download"]);
+ if($sendFileOptions["sendfile"] == "1"){
+ $this->sendFile($speedLimit,$rangeTransfer,true,$sendFileOptions["header"]);
+ }else{
+ if($isAdmin){
+ $speedLimit = "";
+ }
+ if($speedLimit == "0"){
+ exit();
+ }else if(empty($speedLimit)){
+ $this->outputWithoutLimit(true,$rangeTransfer);
+ exit();
+ }else if((int)$speedLimit > 0){
+ $this->outputWithLimit($speedLimit,true);
+ }
+ }
+ }
+
+ private function sendFile($speed,$range,$download=false,$header="X-Sendfile"){
+ if($download){
+ $filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"];
+ header('Content-Disposition: attachment; filename="' . str_replace(",","",$this->fileData["orign_name"]) . '"');
+ header("Content-type: application/octet-stream");
+ $filePath = str_replace("\\","/",$filePath);
+ header($header.": ".str_replace('%2F', '/', rawurlencode($filePath)));
+ }else{
+ $filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"];
+ $filePath = str_replace("\\","/",$filePath);
+ header('Content-Type: '.self::getMimetype($filePath));
+ header($header.": ".str_replace('%2F', '/', rawurlencode($filePath)));
+ ob_flush();
+ flush();
}
}
diff --git a/application/index/view/header_home.html b/application/index/view/header_home.html
index bcf1f5f9..11cf519a 100644
--- a/application/index/view/header_home.html
+++ b/application/index/view/header_home.html
@@ -1,27 +1,17 @@
-
- {block name="title"}{/block}
-
-
+ {block name="title"}{/block}
-
-
-
{block name="content"}{/block}
\ No newline at end of file
diff --git a/static/js/instantclick.min.js b/static/js/instantclick.min.js
new file mode 100644
index 00000000..a50a6e2e
--- /dev/null
+++ b/static/js/instantclick.min.js
@@ -0,0 +1,693 @@
+/* InstantClick 3.0.1 | (C) 2014 Alexandre Dieulot | http://instantclick.io/license.html */
+
+var InstantClick = function(document, location) {
+ // Internal variables
+ var $ua = navigator.userAgent,
+ $hasTouch = 'createTouch' in document,
+ $currentLocationWithoutHash,
+ $urlToPreload,
+ $preloadTimer,
+
+ // Preloading-related variables
+ $history = {},
+ $xhr,
+ $url = false,
+ $title = false,
+ $mustRedirect = false,
+ $body = false,
+ $timing = {},
+ $isPreloading = false,
+ $isWaitingForCompletion = false,
+ $trackedAssets = [],
+
+ // Variables defined by public functions
+ $useWhitelist,
+ $preloadOnMousedown,
+ $delayBeforePreload,
+ $eventsCallbacks = {
+ fetch: [],
+ receive: [],
+ wait: [],
+ change: []
+ }
+
+
+ ////////// HELPERS //////////
+
+
+ function removeHash(url) {
+ var index = url.indexOf('#')
+ if (index < 0) {
+ return url
+ }
+ return url.substr(0, index)
+ }
+
+ function getLinkTarget(target) {
+ while (target.nodeName != 'A') {
+ target = target.parentNode
+ }
+ return target
+ }
+
+ function isBlacklisted(elem) {
+ do {
+ if (!elem.hasAttribute) { // Parent of
+ break
+ }
+ if (elem.hasAttribute('data-instant')) {
+ return false
+ }
+ if (elem.hasAttribute('data-no-instant')) {
+ return true
+ }
+ }
+ while (elem = elem.parentNode);
+ return false
+ }
+
+ function isWhitelisted(elem) {
+ do {
+ if (!elem.hasAttribute) { // Parent of
+ break
+ }
+ if (elem.hasAttribute('data-no-instant')) {
+ return false
+ }
+ if (elem.hasAttribute('data-instant')) {
+ return true
+ }
+ }
+ while (elem = elem.parentNode);
+ return false
+ }
+
+ function triggerPageEvent(eventType, arg1) {
+ for (var i = 0; i < $eventsCallbacks[eventType].length; i++) {
+ $eventsCallbacks[eventType][i](arg1)
+ }
+
+ /* The `change` event takes one boolean argument: "isInitialLoad" */
+ }
+
+ function changePage(title, body, newUrl, scrollY) {
+ document.title = title
+
+ document.documentElement.replaceChild(body, document.body)
+ /* We cannot just use `document.body = doc.body`, it causes Safari (tested
+ 5.1, 6.0 and Mobile 7.0) to execute script tags directly.
+ */
+
+ if (newUrl) {
+ history.pushState(null, null, newUrl)
+
+ var hashIndex = newUrl.indexOf('#'),
+ hashElem = hashIndex > -1
+ && document.getElementById(newUrl.substr(hashIndex + 1)),
+ offset = 0
+
+ if (hashElem) {
+ while (hashElem.offsetParent) {
+ offset += hashElem.offsetTop
+
+ hashElem = hashElem.offsetParent
+ }
+ }
+ scrollTo(0, offset)
+
+ $currentLocationWithoutHash = removeHash(newUrl)
+ }
+ else {
+ scrollTo(0, scrollY)
+ }
+ instantanize()
+ bar.done()
+ triggerPageEvent('change', false)
+ }
+
+ function setPreloadingAsHalted() {
+ $isPreloading = false
+ $isWaitingForCompletion = false
+ }
+
+
+ ////////// EVENT HANDLERS //////////
+
+
+ function mousedown(e) {
+ preload(getLinkTarget(e.target).href)
+ }
+
+ function mouseover(e) {
+ var a = getLinkTarget(e.target)
+ a.addEventListener('mouseout', mouseout)
+
+ if (!$delayBeforePreload) {
+ preload(a.href)
+ }
+ else {
+ $urlToPreload = a.href
+ $preloadTimer = setTimeout(preload, $delayBeforePreload)
+ }
+ }
+
+ function touchstart(e) {
+ var a = getLinkTarget(e.target)
+ if ($preloadOnMousedown) {
+ a.removeEventListener('mousedown', mousedown)
+ }
+ else {
+ a.removeEventListener('mouseover', mouseover)
+ }
+ preload(a.href)
+ }
+
+ function click(e) {
+ if (e.which > 1 || e.metaKey || e.ctrlKey) { // Opening in new tab
+ return
+ }
+ e.preventDefault()
+ display(getLinkTarget(e.target).href)
+ }
+
+ function mouseout() {
+ if ($preloadTimer) {
+ clearTimeout($preloadTimer)
+ $preloadTimer = false
+ return
+ }
+
+ if (!$isPreloading || $isWaitingForCompletion) {
+ return
+ }
+ $xhr.abort()
+ setPreloadingAsHalted()
+ }
+
+ function readystatechange() {
+ if ($xhr.readyState < 4) {
+ return
+ }
+ if ($xhr.status == 0) {
+ /* Request aborted */
+ return
+ }
+
+ $timing.ready = +new Date - $timing.start
+ triggerPageEvent('receive')
+
+ if ($xhr.getResponseHeader('Content-Type').match(/\/(x|ht|xht)ml/)) {
+ var doc = document.implementation.createHTMLDocument('')
+ doc.documentElement.innerHTML = $xhr.responseText
+ $title = doc.title
+ $body = doc.body
+ var urlWithoutHash = removeHash($url)
+ $history[urlWithoutHash] = {
+ body: $body,
+ title: $title,
+ scrollY: urlWithoutHash in $history ? $history[urlWithoutHash].scrollY : 0
+ }
+
+ var elems = doc.head.children,
+ found = 0,
+ elem,
+ data
+
+ for (var i = elems.length - 1; i >= 0; i--) {
+ elem = elems[i]
+ if (elem.hasAttribute('data-instant-track')) {
+ data = elem.getAttribute('href') || elem.getAttribute('src') || elem.innerHTML
+ for (var j = $trackedAssets.length - 1; j >= 0; j--) {
+ if ($trackedAssets[j] == data) {
+ found++
+ }
+ }
+ }
+ }
+ if (found != $trackedAssets.length) {
+ $mustRedirect = true // Assets have changed
+ }
+ }
+ else {
+ $mustRedirect = true // Not an HTML document
+ }
+
+ if ($isWaitingForCompletion) {
+ $isWaitingForCompletion = false
+ display($url)
+ }
+ }
+
+
+ ////////// MAIN FUNCTIONS //////////
+
+
+ function instantanize(isInitializing) {
+ var as = document.getElementsByTagName('a'),
+ a,
+ domain = location.protocol + '//' + location.host
+
+ for (var i = as.length - 1; i >= 0; i--) {
+ a = as[i]
+ if (a.target // target="_blank" etc.
+ || a.hasAttribute('download')
+ || a.href.indexOf(domain + '/') != 0 // Another domain, or no href attribute
+ || (a.href.indexOf('#') > -1
+ && removeHash(a.href) == $currentLocationWithoutHash) // Anchor
+ || ($useWhitelist
+ ? !isWhitelisted(a)
+ : isBlacklisted(a))
+ ) {
+ continue
+ }
+ a.addEventListener('touchstart', touchstart)
+ if ($preloadOnMousedown) {
+ a.addEventListener('mousedown', mousedown)
+ }
+ else {
+ a.addEventListener('mouseover', mouseover)
+ }
+ a.addEventListener('click', click)
+ }
+ if (!isInitializing) {
+ var scripts = document.body.getElementsByTagName('script'),
+ script,
+ copy,
+ parentNode,
+ nextSibling
+
+ for (i = 0, j = scripts.length; i < j; i++) {
+ script = scripts[i]
+ if (script.hasAttribute('data-no-instant')) {
+ continue
+ }
+ copy = document.createElement('script')
+ if (script.src) {
+ copy.src = script.src
+ }
+ if (script.innerHTML) {
+ copy.innerHTML = script.innerHTML
+ }
+ parentNode = script.parentNode
+ nextSibling = script.nextSibling
+ parentNode.removeChild(script)
+ parentNode.insertBefore(copy, nextSibling)
+ }
+ }
+ }
+
+ function preload(url) {
+ if (!$preloadOnMousedown
+ && 'display' in $timing
+ && +new Date - ($timing.start + $timing.display) < 100) {
+ /* After a page is displayed, if the user's cursor happens to be above
+ a link a mouseover event will be in most browsers triggered
+ automatically, and in other browsers it will be triggered when the
+ user moves his mouse by 1px.
+
+ Here are the behavior I noticed, all on Windows:
+ - Safari 5.1: auto-triggers after 0 ms
+ - IE 11: auto-triggers after 30-80 ms (depends on page's size?)
+ - Firefox: auto-triggers after 10 ms
+ - Opera 18: auto-triggers after 10 ms
+
+ - Chrome: triggers when cursor moved
+ - Opera 12.16: triggers when cursor moved
+
+ To remedy to this, we do not start preloading if last display
+ occurred less than 100 ms ago. If they happen to click on the link,
+ they will be redirected.
+ */
+
+ return
+ }
+ if ($preloadTimer) {
+ clearTimeout($preloadTimer)
+ $preloadTimer = false
+ }
+
+ if (!url) {
+ url = $urlToPreload
+ }
+
+ if ($isPreloading && (url == $url || $isWaitingForCompletion)) {
+ return
+ }
+ $isPreloading = true
+ $isWaitingForCompletion = false
+
+ $url = url
+ $body = false
+ $mustRedirect = false
+ $timing = {
+ start: +new Date
+ }
+ triggerPageEvent('fetch')
+ $xhr.open('GET', url)
+ $xhr.send()
+ }
+
+ function display(url) {
+ if (!('display' in $timing)) {
+ $timing.display = +new Date - $timing.start
+ }
+ if ($preloadTimer) {
+ /* Happens when there’s a delay before preloading and that delay
+ hasn't expired (preloading didn't kick in).
+ */
+
+ if ($url && $url != url) {
+ /* Happens when the user clicks on a link before preloading
+ kicks in while another link is already preloading.
+ */
+
+ location.href = url
+ return
+ }
+ preload(url)
+ bar.start(0, true)
+ triggerPageEvent('wait')
+ $isWaitingForCompletion = true
+ return
+ }
+ if (!$isPreloading || $isWaitingForCompletion) {
+ /* If the page isn't preloaded, it likely means the user has focused
+ on a link (with his Tab key) and then pressed Return, which
+ triggered a click.
+ Because very few people do this, it isn't worth handling this case
+ and preloading on focus (also, focusing on a link doesn't mean it's
+ likely that you'll "click" on it), so we just redirect them when
+ they "click".
+ It could also mean the user hovered over a link less than 100 ms
+ after a page display, thus we didn't start the preload (see
+ comments in `preload()` for the rationale behind this.)
+
+ If the page is waiting for completion, the user clicked twice while
+ the page was preloading. Either on the same link or on another
+ link. If it's the same link something might have gone wrong (or he
+ could have double clicked), so we send him to the page the old way.
+ If it's another link, it hasn't been preloaded, so we redirect the
+ user the old way.
+ */
+
+ location.href = url
+ return
+ }
+ if ($mustRedirect) {
+ location.href = $url
+ return
+ }
+ if (!$body) {
+ bar.start(0, true)
+ triggerPageEvent('wait')
+ $isWaitingForCompletion = true
+ return
+ }
+ $history[$currentLocationWithoutHash].scrollY = pageYOffset
+ setPreloadingAsHalted()
+ changePage($title, $body, $url)
+ }
+
+
+ ////////// PROGRESS BAR FUNCTIONS //////////
+
+
+ var bar = function() {
+ var $barContainer,
+ $barElement,
+ $barTransformProperty,
+ $barProgress,
+ $barTimer
+
+ function init() {
+ $barContainer = document.createElement('div')
+ $barContainer.id = 'instantclick'
+ $barElement = document.createElement('div')
+ $barElement.id = 'instantclick-bar'
+ $barElement.className = 'instantclick-bar'
+ $barContainer.appendChild($barElement)
+
+ var vendors = ['Webkit', 'Moz', 'O']
+
+ $barTransformProperty = 'transform'
+ if (!($barTransformProperty in $barElement.style)) {
+ for (var i = 0; i < 3; i++) {
+ if (vendors[i] + 'Transform' in $barElement.style) {
+ $barTransformProperty = vendors[i] + 'Transform'
+ }
+ }
+ }
+
+ var transitionProperty = 'transition'
+ if (!(transitionProperty in $barElement.style)) {
+ for (var i = 0; i < 3; i++) {
+ if (vendors[i] + 'Transition' in $barElement.style) {
+ transitionProperty = '-' + vendors[i].toLowerCase() + '-' + transitionProperty
+ }
+ }
+ }
+
+ var style = document.createElement('style')
+ style.innerHTML = '#instantclick{position:' + ($hasTouch ? 'absolute' : 'fixed') + ';top:0;left:0;width:100%;pointer-events:none;z-index:2147483647;' + transitionProperty + ':opacity .25s .1s}'
+ + '.instantclick-bar{background:#29d;width:100%;margin-left:-100%;height:2px;' + transitionProperty + ':all .25s}'
+ /* We set the bar's background in `.instantclick-bar` so that it can be
+ overriden in CSS with `#instantclick-bar`, as IDs have higher priority.
+ */
+ document.head.appendChild(style)
+
+ if ($hasTouch) {
+ updatePositionAndScale()
+ addEventListener('resize', updatePositionAndScale)
+ addEventListener('scroll', updatePositionAndScale)
+ }
+
+ }
+
+ function start(at, jump) {
+ $barProgress = at
+ if (document.getElementById($barContainer.id)) {
+ document.body.removeChild($barContainer)
+ }
+ $barContainer.style.opacity = '1'
+ if (document.getElementById($barContainer.id)) {
+ document.body.removeChild($barContainer)
+ /* So there's no CSS animation if already done once and it goes from 1 to 0 */
+ }
+ update()
+ if (jump) {
+ setTimeout(jumpStart, 0)
+ /* Must be done in a timer, otherwise the CSS animation doesn't happen. */
+ }
+ clearTimeout($barTimer)
+ $barTimer = setTimeout(inc, 500)
+ }
+
+ function jumpStart() {
+ $barProgress = 10
+ update()
+ }
+
+ function inc() {
+ $barProgress += 1 + (Math.random() * 2)
+ if ($barProgress >= 98) {
+ $barProgress = 98
+ }
+ else {
+ $barTimer = setTimeout(inc, 500)
+ }
+ update()
+ }
+
+ function update() {
+ $barElement.style[$barTransformProperty] = 'translate(' + $barProgress + '%)'
+ if (!document.getElementById($barContainer.id)) {
+ document.body.appendChild($barContainer)
+ }
+ }
+
+ function done() {
+ if (document.getElementById($barContainer.id)) {
+ clearTimeout($barTimer)
+ $barProgress = 100
+ update()
+ $barContainer.style.opacity = '0'
+ /* If you're debugging, setting this to 0.5 is handy. */
+ return
+ }
+
+ /* The bar container hasn't been appended: It's a new page. */
+ start($barProgress == 100 ? 0 : $barProgress)
+ /* $barProgress is 100 on popstate, usually. */
+ setTimeout(done, 0)
+ /* Must be done in a timer, otherwise the CSS animation doesn't happen. */
+ }
+
+ function updatePositionAndScale() {
+ /* Adapted from code by Sam Stephenson and Mislav Marohnić
+ http://signalvnoise.com/posts/2407
+ */
+
+ $barContainer.style.left = pageXOffset + 'px'
+ $barContainer.style.width = innerWidth + 'px'
+ $barContainer.style.top = pageYOffset + 'px'
+
+ var landscape = 'orientation' in window && Math.abs(orientation) == 90,
+ scaleY = innerWidth / screen[landscape ? 'height' : 'width'] * 2
+ /* We multiply the size by 2 because the progress bar is harder
+ to notice on a mobile device.
+ */
+ $barContainer.style[$barTransformProperty] = 'scaleY(' + scaleY + ')'
+ }
+
+ return {
+ init: init,
+ start: start,
+ done: done
+ }
+ }()
+
+
+ ////////// PUBLIC VARIABLE AND FUNCTIONS //////////
+
+ var supported = 'pushState' in history
+ && (!$ua.match('Android') || $ua.match('Chrome/'))
+ && location.protocol != "file:"
+
+ /* The state of Android's AOSP browsers:
+
+ 2.3.7: pushState appears to work correctly, but
+ `doc.documentElement.innerHTML = body` is buggy.
+ See details here: http://stackoverflow.com/q/21918564
+ Note an issue anymore, but it may fail where 3.0 do, this needs
+ testing again.
+
+ 3.0: pushState appears to work correctly (though the URL bar is only
+ updated on focus), but
+ `document.documentElement.replaceChild(doc.body, document.body)`
+ throws DOMException: WRONG_DOCUMENT_ERR.
+
+ 4.0.2: Doesn't support pushState.
+
+ 4.0.4,
+ 4.1.1,
+ 4.2,
+ 4.3: pushState is here, but it doesn't update the URL bar.
+ (Great logic there.)
+
+ 4.4: Works correctly. Claims to be 'Chrome/30.0.0.0'.
+
+ All androids tested with Android SDK's Emulator.
+ Version numbers are from the browser's user agent.
+
+ Because of this mess, the only whitelisted browser on Android is Chrome.
+ */
+
+ function init() {
+ if ($currentLocationWithoutHash) {
+ /* Already initialized */
+ return
+ }
+ if (!supported) {
+ triggerPageEvent('change', true)
+ return
+ }
+ for (var i = arguments.length - 1; i >= 0; i--) {
+ var arg = arguments[i]
+ if (arg === true) {
+ $useWhitelist = true
+ }
+ else if (arg == 'mousedown') {
+ $preloadOnMousedown = true
+ }
+ else if (typeof arg == 'number') {
+ $delayBeforePreload = arg
+ }
+ }
+ $currentLocationWithoutHash = removeHash(location.href)
+ $history[$currentLocationWithoutHash] = {
+ body: document.body,
+ title: document.title,
+ scrollY: pageYOffset
+ }
+
+ var elems = document.head.children,
+ elem,
+ data
+ for (var i = elems.length - 1; i >= 0; i--) {
+ elem = elems[i]
+ if (elem.hasAttribute('data-instant-track')) {
+ data = elem.getAttribute('href') || elem.getAttribute('src') || elem.innerHTML
+ /* We can't use just `elem.href` and `elem.src` because we can't
+ retrieve `href`s and `src`s from the Ajax response.
+ */
+ $trackedAssets.push(data)
+ }
+ }
+
+ $xhr = new XMLHttpRequest()
+ $xhr.addEventListener('readystatechange', readystatechange)
+
+ instantanize(true)
+
+ bar.init()
+
+ triggerPageEvent('change', true)
+
+ addEventListener('popstate', function() {
+ var loc = removeHash(location.href)
+ if (loc == $currentLocationWithoutHash) {
+ return
+ }
+
+ if (!(loc in $history)) {
+ location.href = location.href
+ /* Reloads the page while using cache for scripts, styles and images,
+ unlike `location.reload()` */
+ return
+ }
+
+ $history[$currentLocationWithoutHash].scrollY = pageYOffset
+ $currentLocationWithoutHash = loc
+ changePage($history[loc].title, $history[loc].body, false, $history[loc].scrollY)
+ })
+ }
+
+ function on(eventType, callback) {
+ $eventsCallbacks[eventType].push(callback)
+ }
+
+
+ /* The debug function isn't included by default to reduce file size.
+ To enable it, add a slash at the beginning of the comment englobing
+ the debug function, and uncomment "debug: debug," in the return
+ statement below the function. */
+
+ /*
+ function debug() {
+ return {
+ currentLocationWithoutHash: $currentLocationWithoutHash,
+ history: $history,
+ xhr: $xhr,
+ url: $url,
+ title: $title,
+ mustRedirect: $mustRedirect,
+ body: $body,
+ timing: $timing,
+ isPreloading: $isPreloading,
+ isWaitingForCompletion: $isWaitingForCompletion
+ }
+ }
+ //*/
+
+
+ ////////////////////
+
+
+ return {
+ // debug: debug,
+ supported: supported,
+ init: init,
+ on: on
+ }
+
+}(document, location);
\ No newline at end of file