diff options
-rw-r--r-- | 3rdparty/js/jquery.timeago.js (renamed from js/jquery.timeago.js) | 0 | ||||
-rw-r--r-- | ajax/loadfeed.php | 2 | ||||
-rw-r--r-- | index.php | 93 | ||||
-rw-r--r-- | js/cache.js | 34 | ||||
-rw-r--r-- | js/items.js | 65 | ||||
-rw-r--r-- | js/menu.js | 27 | ||||
-rw-r--r-- | js/test.js | 1 | ||||
-rw-r--r-- | templates/javascript.tests.php | 6 | ||||
-rw-r--r-- | tests/js/menuTests.js | 250 | ||||
-rw-r--r-- | tests/js/qunit/jquery-1.8.0.min.js | 2 | ||||
-rw-r--r-- | tests/js/qunit/jquery-ui-1.8.23.custom.min.js | 125 | ||||
-rw-r--r-- | tests/js/qunit/qunit-1.9.0.css | 231 | ||||
-rw-r--r-- | tests/js/qunit/qunit-1.9.0.js | 1932 | ||||
-rw-r--r-- | tests/js/testSuite.html | 18 |
14 files changed, 126 insertions, 2660 deletions
diff --git a/js/jquery.timeago.js b/3rdparty/js/jquery.timeago.js index bc2e368be..bc2e368be 100644 --- a/js/jquery.timeago.js +++ b/3rdparty/js/jquery.timeago.js diff --git a/ajax/loadfeed.php b/ajax/loadfeed.php index 2c03fc889..4248796a4 100644 --- a/ajax/loadfeed.php +++ b/ajax/loadfeed.php @@ -20,8 +20,6 @@ $userid = OCP\USER::getUser(); $feedId = $_POST['id']; $feedType = $_POST['type']; -$mostRecentItemId = $_POST['mostRecentItemId']; -$mostRecentItemTimestamp = $_POST['mostRecentItemTimestamp']; OCP\Config::setUserValue(OCP\USER::getUser(), 'news', 'lastViewedFeed', $feedId); @@ -29,51 +29,54 @@ $folderforest = $foldermapper->childrenOf(0); //retrieve all the folders $feedid = 0; $feedtype = 0; -if ($allfeeds) { - - OCP\Util::addScript('news','main'); - OCP\Util::addScript('news','news'); - OCP\Util::addScript('news','menu'); - OCP\Util::addScript('news','items'); - OCP\Util::addScript('news','jquery.timeago'); - - OCP\Util::addStyle('news','news'); - OCP\Util::addStyle('news','settings'); - - $feedid = isset( $_GET['feedid'] ) ? $_GET['feedid'] : null; - if ($feedid == null) { - $feedmapper = new OCA\News\FeedMapper(OCP\USER::getUser($userid)); - $lastViewedId = OCP\Config::getUserValue($userid, 'news', 'lastViewedFeed'); - $lastViewedType = OCP\Config::getUserValue($userid, 'news', 'lastViewedFeedType'); - if( $lastViewedId == null || $lastViewedType == null) { - $feedid = $feedmapper->mostRecent(); - } else { - $feedid = $lastViewedId; - $feedtype = $lastViewedType; - // check if feed exists in table - if($feedmapper->findById($feedid) === null) { - $feedid = $feedmapper->mostRecent(); - } - } - } - $tmpl = new OCP\Template( 'news', 'main', 'user' ); - $tmpl->assign('allfeeds', $allfeeds); - $tmpl->assign('folderforest', $folderforest); - $tmpl->assign('feedid', $feedid); - $tmpl->assign('feedtype', $feedtype); +if(isset($_GET['jstest'])){ + OCP\Util::addScript('news/3rdparty', 'jasmine-1.2.0/jasmine.js'); + OCP\Util::addScript('news/3rdparty', 'jasmine-1.2.0/jasmine-html.js'); + OCP\Util::addStyle('news/3rdparty','jasmine-1.2.0/jasmine.css'); + $tmpl = new OCP\Template('news', 'javascript.tests'); $tmpl->printPage(); - -} -else { - - OCP\Util::addScript('news','news'); - OCP\Util::addScript('news','firstrun'); +} else { + + if ($allfeeds) { + + OCP\Util::addScript('news','main'); + OCP\Util::addScript('news','news'); + OCP\Util::addScript('news','menu'); + OCP\Util::addScript('news','items'); + OCP\Util::addScript('news/3rdparty', 'jquery.timeago'); + + OCP\Util::addStyle('news','news'); + OCP\Util::addStyle('news','settings'); + + $feedid = isset( $_GET['feedid'] ) ? $_GET['feedid'] : null; + if ($feedid == null) { + $feedmapper = new OCA\News\FeedMapper(OCP\USER::getUser($userid)); + $lastViewedId = OCP\Config::getUserValue($userid, 'news', 'lastViewedFeed'); + $lastViewedType = OCP\Config::getUserValue($userid, 'news', 'lastViewedFeedType'); + if( $lastViewedId == null || $lastViewedType == null) { + $feedid = $feedmapper->mostRecent(); + } else { + $feedid = $lastViewedId; + $feedtype = $lastViewedType; + // check if feed exists in table + if($feedmapper->findById($feedid) === null) { + $feedid = $feedmapper->mostRecent(); + } + } + } + $tmpl = new OCP\Template( 'news', 'main', 'user' ); + $tmpl->assign('allfeeds', $allfeeds); + $tmpl->assign('folderforest', $folderforest); + $tmpl->assign('feedid', $feedid); + $tmpl->assign('feedtype', $feedtype); + $tmpl->printPage(); + + } else { - OCP\Util::addStyle('news','firstrun'); - - $tmpl = new OCP\Template( 'news', 'firstrun', 'user' ); - $tmpl->printPage(); - + OCP\Util::addScript('news','news'); + OCP\Util::addScript('news','firstrun'); + OCP\Util::addStyle('news','firstrun'); + $tmpl = new OCP\Template( 'news', 'firstrun', 'user' ); + $tmpl->printPage(); + } } - - diff --git a/js/cache.js b/js/cache.js new file mode 100644 index 000000000..08353bae8 --- /dev/null +++ b/js/cache.js @@ -0,0 +1,34 @@ +/** +* ownCloud - News app +* +* @author Bernhard Posselt +* Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> +* +* This file is licensed under the Affero General Public License version 3 or later. +* See the COPYING-README file +* +*/ + +/** + * The cache is used to cache items and tell the program which items have been + * loaded + */ + + (function(exports) { + "use strict"; + + var Cache = function(){ + this.reset(); + }; + + + + Cache.prototype.reset = function(){ + this.items = []; + }; + + exports.Cache = Cache; + + }(typeof exports === "undefined" ? (this.moduleName = {}): exports)); + + diff --git a/js/items.js b/js/items.js index 76b6df5d9..8541b0031 100644 --- a/js/items.js +++ b/js/items.js @@ -70,7 +70,7 @@ var News = News || {}; * @param item the dom item */ Items.prototype._markItemAsReadTimeout = function(item) { - var itemId = parseInt($(item).data('id'), 10); + var itemId = parseInt($(item).data('id')); var itemOffset = $(item).position().top; var cachedItem = this._itemCache.getItem(itemId); if(itemOffset < 0){ @@ -96,8 +96,7 @@ var News = News || {}; var data = { id: id, type: type, - mostRecentItemId: this._itemCache.getMostRecentItemId(), - mostRecentItemTimestamp: this._itemCache.getMostRecentItemTimestamp() + mostRecentItemId: this._itemCache.getMostRecentItemId(type, id) }; this._$articleList.addClass('loading'); @@ -134,7 +133,7 @@ var News = News || {}; var notJumped = true; $('.feed_item').each(function(){ if(notJumped && $(this).position().top > 1){ - var id = parseInt($(this).data('id'), 10); + var id = parseInt($(this).data('id')); self._jumpToElemenId(id); notJumped = false; } @@ -151,7 +150,7 @@ var News = News || {}; if(notJumped && $(this).position().top >= 0){ var previous = $(this).prev(); if(previous.length > 0){ - var id = parseInt(previous.data('id'), 10); + var id = parseInt(previous.data('id')); self._jumpToElemenId(id); } notJumped = false; @@ -162,7 +161,7 @@ var News = News || {}; if(notJumped){ var $items = $('.feed_item'); if($items.length > 0){ - var id = parseInt($items.last().data('id'), 10); + var id = parseInt($items.last().data('id')); self._jumpToElemenId(id); } } @@ -221,7 +220,7 @@ var News = News || {}; * @return the jquery node */ Items.prototype._findNodeById = function(id) { - id = parseInt(id, 10); + id = parseInt(id); return this._$articleList.find('.feed_item[data-id="' + id + '"]'); }; @@ -253,15 +252,13 @@ var News = News || {}; var ItemCache = function() { this._items = {}; this._feeds = {}; - this._itemIds = []; - this._itemTimestamps = []; }; /** * Returns an item from the cache */ ItemCache.prototype.getItem = function(itemId) { - itemId = parseInt(itemId, 10); + itemId = parseInt(itemId); return this._items[itemId]; }; @@ -292,8 +289,6 @@ var News = News || {}; self._items[item.getId()] = item; self._feeds[item.getFeedId()] = self._feeds[item.getFeedId()] || {}; self._feeds[item.getFeedId()][item.getId()] = item; - self._itemIds.push(item.getId()); - self._itemTimestamps.push(item.getTimeStamp()); }); }; @@ -303,8 +298,6 @@ var News = News || {}; ItemCache.prototype.empty = function() { this._items = {}; this._feeds = {}; - this._itemIds = []; - this._itemTimestamps = []; }; @@ -350,13 +343,12 @@ var News = News || {}; return pairs; }; - /** - * Returns all the ids of feeds for a type sorted by timestamp ascending - * @param type the type (MenuNodeType) - * @param id the id - * @return all the ids of feeds for a type sorted by timestamp ascending - */ + * Returns all the ids of feeds for a type sorted by timestamp ascending + * @param type the type (MenuNodeType) + * @param id the id + * @return all the ids of feeds for a type sorted by timestamp ascending + */ ItemCache.prototype._getSortedItemIds = function(type, id) { var pairs = this._getItemIdTimestampPairs(type, id); @@ -371,32 +363,21 @@ var News = News || {}; return itemIds; }; - /** - * @return the most recent id that is loaded on the page or 0 if no ids are there - */ - ItemCache.prototype.getMostRecentItemId = function() { - if(this._itemIds.length === 0){ - return 0; - } else { - this.itemIds = this._itemIds.sort(); - return this.itemIds[this.itemIds.length-1]; - } - }; - - /** - * @return the most recent timestamp that is loaded on the page or 0 if no ids are there + * Returns the most recent id of a feed + * @param type the type (MenuNodeType) + * @param id the id + * @return the most recent id that is loaded on the page or 0 */ - ItemCache.prototype.getMostRecentItemTimestamp = function() { - if(this._itemTimestamps.length === 0){ + ItemCache.prototype.getMostRecentItemId = function(type, id) { + var itemIds = this._getSortedItemIds(type, id); + if(itemIds.length === 0){ return 0; } else { - this._itemTimestamps = this._itemTimestamps.sort(); - return this._itemTimestamps[this._itemTimestamps.length-1]; + return itemIds[itemIds.length-1]; } }; - /** * Returns the html for a specific feed * @param type the type (MenuNodeType) @@ -431,14 +412,14 @@ var News = News || {}; var Item = function(html){ this._starred = false; this._$html = $(html); - this._id = parseInt(this._$html.data('id'), 10); - this._feedId = parseInt(this._$html.data('feedid'), 10); + this._id = parseInt(this._$html.data('id')); + this._feedId = parseInt(this._$html.data('feedid')); this._read = this._$html.hasClass('read'); this._locked = false; this._important = this._$html.find('li.star').hasClass('important'); // get timestamp for sorting var $stamp = this._$html.find('.timestamp'); - this._timestamp = parseInt($stamp.html(), 10); + this._timestamp = parseInt($stamp.html()); $stamp.remove(); // open all links in new tabs this._$html.find('.body a').attr('target', '_blank'); diff --git a/js/menu.js b/js/menu.js index bdb8e8442..90c623f6f 100644 --- a/js/menu.js +++ b/js/menu.js @@ -135,7 +135,7 @@ var News = News || {}; * @param html the html to add */ Menu.prototype.addNode = function(parentId, html){ - parentId = parseInt(parentId, 10); + parentId = parseInt(parentId); var $parentNode; var $html = $(html); @@ -172,7 +172,7 @@ var News = News || {}; */ Menu.prototype.updateNode = function(type, id, data){ var $node = this._getNodeFromTypeAndId(type, id); - id = parseInt(id, 10); + id = parseInt(id); if(data.title !== undefined){ // prevent xss @@ -188,10 +188,10 @@ var News = News || {}; /** * Removes a node and its subnodes from the menu * @param type the type (MenuNodeType) - * @param id the id + * @param id the id */ Menu.prototype.removeNode = function(type, id){ - id = parseInt(id, 10); + id = parseInt(id); var $node = this._getNodeFromTypeAndId(type, id); $node.remove(); }; @@ -276,9 +276,9 @@ var News = News || {}; */ Menu.prototype.getFeedIdsOfFolder = function(folderId) { $folder = this._getNodeFromTypeAndId(MenuNodeType.Folder, folderId); - var ids = []; + var ids = new Array(); $folder.children('ul').children('li').each(function(){ - ids.push(parseInt($(this).data('id'), 10)); + ids.push(parseInt($(this).data('id'))); }); return ids; }; @@ -546,6 +546,7 @@ var News = News || {}; Menu.prototype._edit = function(type, id){ var $node = this._getNodeFromTypeAndId(type, id); var name = $node.children('.title').html(); + var id = $node.data('id'); $('#changefolder_dialog').find('input[type=text]').val(name); $('#changefolder_dialog').find('input[type=hidden]').val(id); $('#changefolder_dialog').dialog('open'); @@ -589,7 +590,7 @@ var News = News || {}; $.post(OC.filePath('news', 'ajax', 'setallitemsread.php'), data, function(jsonData) { if(jsonData.status == 'success'){ - self._setUnreadCount(type, id, parseInt(jsonData.data.unreadCount, 10)); + self._setUnreadCount(type, id, parseInt(jsonData.data.unreadCount)); } else { OC.dialogs.alert(jsonData.data.message, t('news', 'Error')); } @@ -691,7 +692,7 @@ var News = News || {}; */ Menu.prototype._getAndRemoveUnreadCount = function($listItem){ var $unreadCounter = $listItem.children('.unread_items_counter'); - var unreadCount = parseInt($unreadCounter.html(), 10); + var unreadCount = parseInt($unreadCounter.html()); $unreadCounter.remove(); return unreadCount; }; @@ -719,7 +720,7 @@ var News = News || {}; */ Menu.prototype._getIdAndTypeFromNode = function($listItem) { return { - id: parseInt($listItem.data('id'), 10), + id: parseInt($listItem.data('id')), type: this._listItemToMenuNodeType($listItem) }; }; @@ -781,7 +782,7 @@ var News = News || {}; * @param unreadCount the count of unread items */ Menu.prototype._setUnreadCount = function(type, id, unreadCount){ - unreadCount = parseInt(unreadCount, 10); + unreadCount = parseInt(unreadCount); if(unreadCount < 0){ unreadCount = 0; } @@ -864,9 +865,9 @@ var News = News || {}; var $dropped = $(this); var $dragged = $(ui.draggable); - var feedId = parseInt($dragged.data('id'), 10); - var folderId = parseInt($dropped.data('id'), 10); - var fromFolderId = parseInt($dragged.parent().data('id'), 10); + var feedId = parseInt($dragged.data('id')); + var folderId = parseInt($dropped.data('id')); + var fromFolderId = parseInt($dragged.parent().data('id')); // ignore when dragged to the same folder if(folderId === fromFolderId){ diff --git a/js/test.js b/js/test.js new file mode 100644 index 000000000..3fe07a7a9 --- /dev/null +++ b/js/test.js @@ -0,0 +1 @@ +alert('hi')
\ No newline at end of file diff --git a/templates/javascript.tests.php b/templates/javascript.tests.php new file mode 100644 index 000000000..163e3cb0a --- /dev/null +++ b/templates/javascript.tests.php @@ -0,0 +1,6 @@ +<?php + + +?> + +<div>hi</div>
\ No newline at end of file diff --git a/tests/js/menuTests.js b/tests/js/menuTests.js deleted file mode 100644 index f2b7e8a09..000000000 --- a/tests/js/menuTests.js +++ /dev/null @@ -1,250 +0,0 @@ -/** -* ownCloud - News app -* -* @author Bernhard Posselt -* Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> -* -* This file is licensed under the Affero General Public License version 3 or later. -* See the COPYING-README file -* -*/ - -var News = News || {}; -var NewsTests = NewsTests || {}; - -// variables with are used again -NewsTests.jsonStruct = [ - { - id: 1, - title: 'hi', - type: News.MenuNodeType.Folder, - unreadCount: 1, - children: [ - { - id: 2, - title: 'hi too', - type: News.MenuNodeType.Feed, - unreadCount: 4, - children: [], - icon: 'img/testing.png' - }, - { - id: 3, - title: 'hi 3', - type: News.MenuNodeType.Feed, - children: [], - unreadCount: 3, - }, - { - id: 2, - title: 'hi 3', - type: News.MenuNodeType.Folder, - children: [], - unreadCount: 13, - }, - ] - }, - { - id: 4, - title: 'hi 4', - type: News.MenuNodeType.Feed, - children: [], - unreadCount: 1, - }, - { - id: 5, - title: 'hi 4', - type: News.MenuNodeType.Feed, - children: [], - unreadCount: 50, - }, -]; - - -QUnit.testStart(function(){ - NewsTests.menu = new News.Menu('feed_menu'); - NewsTests.popMenu = new News.Menu('feed_menu'); - NewsTests.popMenu.populateFromJSON(NewsTests.jsonStruct, NewsTests.popMenu); - // empty menu - NewsTests.$menuContainer = $('<div>'); - NewsTests.$menuContainer.append(NewsTests.menu.render()); - NewsTests.$menuDomElem = NewsTests.$menuContainer.children('ul'); - // populated menu - NewsTests.$popMenuContainer = $('<div>'); - NewsTests.$popMenuContainer.append(NewsTests.popMenu.render()); - NewsTests.$popMenuDomElem = NewsTests.$popMenuContainer.children('ul'); - var menuData = { - title: 'this is rad', - unreadCount: 111, - }; - NewsTests.node = new News.MenuNode(News.MenuNodeType.Feed, 6, menuData); -}); - - -/** - * Empty menu tests - */ -test('Empty menu should have certain variables', function(){ - equal(NewsTests.menu._children.length, 0); - equal(NewsTests.menu._class, 'feed_menu'); - equal(NewsTests.menu._parent, false); - equal(NewsTests.menu.getSize(), 0); -}); - - -test('Empty menu dom should have certain dom elements', function(){ - equal(NewsTests.$menuContainer.length, 1); - ok(NewsTests.$menuDomElem.hasClass('feed_menu')); - equal(NewsTests.$menuDomElem.children().length, 0); -}); - - -/** - * Find node tests - */ -test('Finding a folder node should succeed', function(){ - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 1); - ok(node !== undefined); -}); - - -test('Finding a nested folder node should succeed', function(){ - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 2); - ok(node !== undefined); -}); - - -test('Finding a folder node that doesnt exist should fail', function(){ - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 10); - ok(node === undefined); -}); - - -test('Finding a feed node should succeed', function(){ - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Feed, 4); - ok(node !== undefined); -}); - - -test('Finding a feed node that doesnt exist should fail', function(){ - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Feed, 10); - ok(node === undefined); -}); - - -/** - * Adding nodes test - */ -test('Adding a node should set children and parent correctly', function(){ - NewsTests.menu._addChildNode(NewsTests.node); - equal(NewsTests.node._parent, NewsTests.menu); - ok(NewsTests.menu._children.indexOf(NewsTests.node) !== -1); - equal(NewsTests.menu.getSize(), 1); -}); - - -/** - * Creating nodes tests - */ -test('Adding a new node should create the correct dom', function(){ - NewsTests.menu.createNode(News.MenuNodeType.Folder, 0, NewsTests.node); - equal(NewsTests.$menuDomElem.children().length, 1); -}); - - -/** - * Removing nodes tests - */ -test('Removing a feed node should remove the correct dom', function(){ - equal(NewsTests.$popMenuDomElem.children().length, 3); - - var child = NewsTests.popMenu.removeNode(News.MenuNodeType.Feed, 2, true); - ok(child !== undefined); - - // top length should stay the same - equal(NewsTests.$popMenuDomElem.children().length, 3); - equal(NewsTests.popMenu._children.length, 3); - // but size should have been reduced by 1 - equal(NewsTests.popMenu.getSize(), 5); - -}); - -test('Removing a non existent node should not change anything', function(){ - var child = NewsTests.popMenu.removeNode(News.MenuNodeType.Feed, 12, true); - ok(child === undefined); - - // top length should stay the same - equal(NewsTests.$popMenuDomElem.children().length, 3); - equal(NewsTests.popMenu._children.length, 3); - equal(NewsTests.popMenu.getSize(), 6); - -}); - -test('Removing a parent node should remove its children', function(){ - var child = NewsTests.popMenu.removeNode(News.MenuNodeType.Folder, 1, true); - ok(child !== undefined); - equal(NewsTests.$popMenuDomElem.children().length, 2); - equal(NewsTests.popMenu._children.length, 2); - equal(NewsTests.popMenu.getSize(), 2); - -}); - - -/** - * Updating nodes tests - */ -test('Updating a node should update the object', function(){ - var data = { - unreadCount: 112, - title: 'no way', - icon: 'test.png' - }; - - NewsTests.popMenu.updateNode(News.MenuNodeType.Feed, 2, data); - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Feed, 2); - equal(node._unreadCount, data.unreadCount); - equal(node._title, data.title); - equal(node._icon, data.icon); -}); - - -test('Updating a node should update the dom', function(){ - var data = { - unreadCount: 112, - title: 'no way', - icon: 'test.png' - }; - - NewsTests.popMenu.updateNode(News.MenuNodeType.Feed, 2, data); - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Feed, 2); - equal(node._$htmlElement.children('.title').html(), data.title); - //equal(node._$htmlElement.css('background-image'), data.icon); this fails in firefox, dunno why -}); - - -/** - * Unread count tests - */ -test('Setting an unread count of 0 should add the all_read class', function(){ - NewsTests.popMenu.updateNode(News.MenuNodeType.Folder, 1, {unreadCount: 0}); - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 1); - equal(node._unreadCount, 0); - ok(node._$htmlElement.hasClass('all_read')); -}); - -test('Setting an unread count of 0 and then 12 should remove the all_read and hidden class', function(){ - NewsTests.popMenu.updateNode(News.MenuNodeType.Folder, 1, {unreadCount: 0}); - NewsTests.popMenu.triggerHideRead(); - NewsTests.popMenu.updateNode(News.MenuNodeType.Folder, 1, {unreadCount: 12}); - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 1); - equal(node._unreadCount, 12); - ok(!node._$htmlElement.hasClass('all_read')); - ok(!node._$htmlElement.hasClass('hidden')); -}); - -test('Setting an unread count of 0 and triggering the hiding of read feeds should add the hidden class', function(){ - NewsTests.popMenu.updateNode(News.MenuNodeType.Folder, 1, {unreadCount: 0}); - NewsTests.popMenu.triggerHideRead(); - var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 1); - ok(node._$htmlElement.hasClass('hidden')); -});
\ No newline at end of file diff --git a/tests/js/qunit/jquery-1.8.0.min.js b/tests/js/qunit/jquery-1.8.0.min.js deleted file mode 100644 index f121291c4..000000000 --- a/tests/js/qunit/jquery-1.8.0.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v@1.8.0 jquery.com | jquery.org/license */
-(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bX(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bV.length;while(e--){b=bV[e]+c;if(b in a)return b}return d}function bY(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function bZ(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bY(c)&&(e[f]=p._data(c,"olddisplay",cb(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b$(a,b,c){var d=bO.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function b_(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bU[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bU[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bU[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bU[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bU[e]+"Width"))||0));return f}function ca(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bP.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+b_(a,b,c||(f?"border":"content"),e)+"px"}function cb(a){if(bR[a])return bR[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bR[a]=c,c}function ch(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||cd.test(a)?d(a,e):ch(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ch(a+"["+e+"]",b[e],c,d);else d(a,b)}function cy(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cz(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cu;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cz(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cz(a,c,d,e,"*",g)),h}function cA(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cB(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cC(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={}, |