Affinity_Items - Version 1.0.0

Version Notes

No notes

Download this release

Release Info

Developer Mathieu
Extension Affinity_Items
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (99) hide show
  1. app/code/local/AffinityEngine/AffinityItems/Block/Adminhtml/Affinityitems.php +21 -0
  2. app/code/local/AffinityEngine/AffinityItems/Block/Adminhtml/Affinityitems/Grid.php +50 -0
  3. app/code/local/AffinityEngine/AffinityItems/Block/Adminhtml/Affinityitemsbackend.php +5 -0
  4. app/code/local/AffinityEngine/AffinityItems/Block/Index.php +112 -0
  5. app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Classes.php +23 -0
  6. app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Imagesize.php +22 -0
  7. app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Ipblacklist.php +105 -0
  8. app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Serverlist.php +105 -0
  9. app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Siteinfo.php +24 -0
  10. app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Version.php +9 -0
  11. app/code/local/AffinityEngine/AffinityItems/Helper/Aeadapter.php +85 -0
  12. app/code/local/AffinityEngine/AffinityItems/Helper/Data.php +283 -0
  13. app/code/local/AffinityEngine/AffinityItems/Model/Action.php +9 -0
  14. app/code/local/AffinityEngine/AffinityItems/Model/Cart.php +28 -0
  15. app/code/local/AffinityEngine/AffinityItems/Model/CatProdRepo.php +19 -0
  16. app/code/local/AffinityEngine/AffinityItems/Model/Config.php +17 -0
  17. app/code/local/AffinityEngine/AffinityItems/Model/Cron.php +160 -0
  18. app/code/local/AffinityEngine/AffinityItems/Model/Log.php +15 -0
  19. app/code/local/AffinityEngine/AffinityItems/Model/Observer.php +342 -0
  20. app/code/local/AffinityEngine/AffinityItems/Model/Resource/Action.php +9 -0
  21. app/code/local/AffinityEngine/AffinityItems/Model/Resource/Action/Collection.php +8 -0
  22. app/code/local/AffinityEngine/AffinityItems/Model/Resource/Cart.php +9 -0
  23. app/code/local/AffinityEngine/AffinityItems/Model/Resource/Cart/Collection.php +8 -0
  24. app/code/local/AffinityEngine/AffinityItems/Model/Resource/CatProdRepo.php +9 -0
  25. app/code/local/AffinityEngine/AffinityItems/Model/Resource/CatProdRepo/Collection.php +8 -0
  26. app/code/local/AffinityEngine/AffinityItems/Model/Resource/Log.php +9 -0
  27. app/code/local/AffinityEngine/AffinityItems/Model/Resource/Log/Collection.php +8 -0
  28. app/code/local/AffinityEngine/AffinityItems/Model/Resource/Syncrotate.php +9 -0
  29. app/code/local/AffinityEngine/AffinityItems/Model/Resource/Syncrotate/Collection.php +8 -0
  30. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Abtesting/Abtesting.php +75 -0
  31. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Core/AbstractRequest.php +71 -0
  32. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Core/Curl.php +106 -0
  33. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Recommendation/Recommendation.php +74 -0
  34. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/ActionRequest.php +31 -0
  35. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/CategoryRequest.php +31 -0
  36. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/CustomerRequest.php +40 -0
  37. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/DisableRequest.php +28 -0
  38. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/GuestRequest.php +31 -0
  39. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/HostRequest.php +28 -0
  40. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/LinkGuestToMemberRequest.php +28 -0
  41. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/MemberRequest.php +32 -0
  42. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/NotificationRequest.php +26 -0
  43. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/OrderRequest.php +32 -0
  44. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/ProductRequest.php +31 -0
  45. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/RecommendationRequest.php +30 -0
  46. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/ResynchronizeRequest.php +27 -0
  47. app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/SiteRequest.php +28 -0
  48. app/code/local/AffinityEngine/AffinityItems/Model/Source/Enviroment.php +13 -0
  49. app/code/local/AffinityEngine/AffinityItems/Model/Source/Imagesize.php +15 -0
  50. app/code/local/AffinityEngine/AffinityItems/Model/Source/Loglevel.php +15 -0
  51. app/code/local/AffinityEngine/AffinityItems/Model/Source/Recoconfig.php +82 -0
  52. app/code/local/AffinityEngine/AffinityItems/Model/Sync/ActionSync.php +91 -0
  53. app/code/local/AffinityEngine/AffinityItems/Model/Sync/CartActionSync.php +98 -0
  54. app/code/local/AffinityEngine/AffinityItems/Model/Sync/CategorySync.php +146 -0
  55. app/code/local/AffinityEngine/AffinityItems/Model/Sync/MemberSync.php +34 -0
  56. app/code/local/AffinityEngine/AffinityItems/Model/Sync/OrderSync.php +110 -0
  57. app/code/local/AffinityEngine/AffinityItems/Model/Sync/ProductSync.php +266 -0
  58. app/code/local/AffinityEngine/AffinityItems/Model/Sync/Sync.php +77 -0
  59. app/code/local/AffinityEngine/AffinityItems/Model/Syncrotate.php +21 -0
  60. app/code/local/AffinityEngine/AffinityItems/bin/manual-run.php +11 -0
  61. app/code/local/AffinityEngine/AffinityItems/controllers/ActionController.php +73 -0
  62. app/code/local/AffinityEngine/AffinityItems/controllers/Adminhtml/AffinityitemsbackendController.php +17 -0
  63. app/code/local/AffinityEngine/AffinityItems/controllers/Adminhtml/AffinityitemslogController.php +18 -0
  64. app/code/local/AffinityEngine/AffinityItems/controllers/Adminhtml/AjaxController.php +84 -0
  65. app/code/local/AffinityEngine/AffinityItems/etc/adminhtml.xml +23 -0
  66. app/code/local/AffinityEngine/AffinityItems/etc/config.xml +399 -0
  67. app/code/local/AffinityEngine/AffinityItems/etc/system.xml +1639 -0
  68. app/code/local/AffinityEngine/AffinityItems/sql/affinityitems_setup/mysql4-install-1.0.0.php +247 -0
  69. app/code/local/AffinityEngine/AffinityItems/uninstall.sql +9 -0
  70. app/design/adminhtml/default/default/layout/affinityitems.xml +27 -0
  71. app/design/adminhtml/default/default/template/affinityitems/affinityitems_login.phtml +117 -0
  72. app/design/adminhtml/default/default/template/affinityitems/affinityitems_sync.phtml +123 -0
  73. app/design/frontend/base/default/layout/affinityengine/affinityitems.xml +71 -0
  74. app/design/frontend/base/default/template/affinityengine/ae_css.phtml +3 -0
  75. app/design/frontend/base/default/template/affinityengine/ae_js.phtml +27 -0
  76. app/design/frontend/base/default/template/affinityengine/horizontal.phtml +38 -0
  77. app/design/frontend/base/default/template/affinityengine/pricehtml.phtml +1 -0
  78. app/design/frontend/base/default/template/affinityengine/vertical.phtml +46 -0
  79. app/etc/modules/AffinityEngine_AffinityItems.xml +10 -0
  80. app/locale/fr_FR/AffinityEngine_AffinityItems.csv +58 -0
  81. package.xml +52 -0
  82. skin/adminhtml/default/default/affinityengine/img/aeboard.jpg +0 -0
  83. skin/adminhtml/default/default/affinityengine/img/aemoney.jpg +0 -0
  84. skin/adminhtml/default/default/affinityengine/img/aestart.jpg +0 -0
  85. skin/adminhtml/default/default/affinityengine/img/ailogo.png +0 -0
  86. skin/adminhtml/default/default/affinityengine/img/checked.png +0 -0
  87. skin/adminhtml/default/default/affinityengine/img/disabled.png +0 -0
  88. skin/adminhtml/default/default/affinityengine/img/enabled.png +0 -0
  89. skin/adminhtml/default/default/affinityengine/img/error.png +0 -0
  90. skin/adminhtml/default/default/affinityengine/img/index.php +35 -0
  91. skin/adminhtml/default/default/affinityengine/img/loading.gif +0 -0
  92. skin/adminhtml/default/default/affinityengine/img/logo.png +0 -0
  93. skin/adminhtml/default/default/affinityengine/img/pdf.png +0 -0
  94. skin/adminhtml/default/default/affinityengine/img/unchecked.png +0 -0
  95. skin/adminhtml/default/default/affinityengine/jquery-noconflict.js +9791 -0
  96. skin/adminhtml/default/default/affinityengine/main.css +1887 -0
  97. skin/frontend/base/default/css/affinityitems/affinityitems.css +25 -0
  98. skin/frontend/base/default/js/affinityitems/affinityitems.js +175 -0
  99. skin/frontend/base/default/js/affinityitems/jquery-noconflict.js +9791 -0
app/code/local/AffinityEngine/AffinityItems/Block/Adminhtml/Affinityitems.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class AffinityEngine_AffinityItems_Block_Adminhtml_Affinityitems extends Mage_Adminhtml_Block_Widget_Grid_Container{
5
+
6
+ public function __construct()
7
+ {
8
+
9
+ $this->_controller = "adminhtml_affinityitems";
10
+ $this->_blockGroup = "affinityitems";
11
+ $this->_headerText = Mage::helper("affinityitems")->__("Affinityitems Log Manager");
12
+ $this->_addButton('save_and_continue', array(
13
+ 'label' => Mage::helper('adminhtml')->__('Clear Log'),
14
+ 'onclick' => "setLocation('" . $this->getUrl('*/*/deleteall') . "')",
15
+ 'class' => 'save',
16
+ ), -100);
17
+ parent::__construct();
18
+ $this->_removeButton('add');
19
+ }
20
+
21
+ }
app/code/local/AffinityEngine/AffinityItems/Block/Adminhtml/Affinityitems/Grid.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Adminhtml_Affinityitems_Grid extends Mage_Adminhtml_Block_Widget_Grid {
4
+
5
+ public function __construct() {
6
+ parent::__construct();
7
+ $this->setId("affinityitemsGrid");
8
+ $this->setDefaultSort("id_log");
9
+ $this->setDefaultDir("DESC");
10
+ $this->setSaveParametersInSession(true);
11
+ }
12
+
13
+ protected function _prepareCollection() {
14
+
15
+ $collection = Mage::getModel("affinityitems/log")->getCollection();
16
+ $this->setCollection($collection);
17
+ return parent::_prepareCollection();
18
+ }
19
+
20
+ protected function _prepareColumns() {
21
+ $this->addColumn("id_log", array(
22
+ "header" => Mage::helper("affinityitems")->__("ID"),
23
+ "align" => "right",
24
+ "width" => "50px",
25
+ "type" => "number",
26
+ "index" => "id_log",
27
+ ));
28
+
29
+ $this->addColumn('date_add', array(
30
+ 'header' => Mage::helper('affinityitems')->__('Date Added'),
31
+ 'index' => 'date_add',
32
+ 'type' => 'datetime',
33
+ ));
34
+ $this->addColumn("severity", array(
35
+ "header" => Mage::helper("affinityitems")->__("Severity"),
36
+ "index" => "severity",
37
+ ));
38
+ $this->addColumn("message", array(
39
+ "header" => Mage::helper("affinityitems")->__("Message"),
40
+ "index" => "message",
41
+ ));
42
+
43
+ return parent::_prepareColumns();
44
+ }
45
+
46
+ public function getRowUrl($row) {
47
+ //return '#';
48
+ }
49
+
50
+ }
app/code/local/AffinityEngine/AffinityItems/Block/Adminhtml/Affinityitemsbackend.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Adminhtml_Affinityitemsbackend extends Mage_Adminhtml_Block_Template {
4
+
5
+ }
app/code/local/AffinityEngine/AffinityItems/Block/Index.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Index extends Mage_Core_Block_Template {
4
+
5
+ public function getProductCollection($block = false) {
6
+ // $context = "recoAll";
7
+
8
+ $recoId = $this->helper('affinityitems')->getConfig('recommendation_config');
9
+
10
+ $no_prod = $this->helper('affinityitems')->getConfig('number_products');
11
+ if ($block && $block == "ae_vertical_right") {
12
+ $area = "RIGHT";
13
+ $no_prod = $this->helper('affinityitems')->getRightNOP('number_products');
14
+ } elseif ($block && $block == "ae_vertical_left") {
15
+ $area = "LEFT";
16
+ $no_prod = $this->helper('affinityitems')->getLeftNOP('number_products');
17
+ } elseif (!$block) {
18
+ $path = $this->helper('affinityitems')->getXmlPath();
19
+ if (strpos($path, 'home')) {
20
+ $area = "HOME";
21
+ } elseif (strpos($path, 'cart')) {
22
+ $refs = $this->getCartOrderLines();
23
+ $refType = "product";
24
+ // $orderLines = $this->getCartOrderLines();
25
+ // $context = "recoCart";
26
+ } elseif (strpos($path, 'category')) {
27
+ $refs = (Mage::registry('current_category')) ? Mage::registry('current_category')->getId() : false;
28
+ $refType = "category";
29
+ //$category_id = (Mage::registry('current_category')) ? Mage::registry('current_category')->getId() : false;
30
+ // $context = "recoCategory";
31
+ } elseif (strpos($path, 'search')) {
32
+ $refType = "keywords";
33
+ $expr = Mage::app()->getRequest()->getParam('q');
34
+ // $context = "recoSearch";
35
+ } elseif (strpos($path, 'product')) {
36
+ $refs = (Mage::registry('current_product')) ? Mage::registry('current_product')->getId() : false;
37
+ $refType = "product";
38
+ //$product = (Mage::registry('current_product')) ? Mage::registry('current_product')->getId() : false;
39
+ //$context = "recoSimilar";
40
+ }
41
+ } else {
42
+ return;
43
+ }
44
+
45
+ $aecontext = new stdClass();
46
+ //$aecontext->context = $context;
47
+
48
+ $aecontext->recoId = $recoId;
49
+
50
+ if (isset($area))
51
+ $aecontext->area = $area;
52
+ $aecontext->size = (int) $no_prod;
53
+ /*if (isset($product))
54
+ $aecontext->productId = (string) $product;
55
+ if (isset($category_id))
56
+ $aecontext->categoryId = (string) $category_id;
57
+ if (isset($orderLines))
58
+ $aecontext->orderLines = $orderLines;*/
59
+ if(isset($refs)) {
60
+ if(!is_array($refs))
61
+ $refs = array($refs);
62
+ $aecontext->refs = $refs;
63
+ }
64
+ if(isset($refType))
65
+ $aecontext->refType = $refType;
66
+ if (isset($expr))
67
+ $aecontext->keywords = (string) $expr;
68
+ $recomemendation = new AffinityEngine_AffinityItems_Model_Sdk_Recommendation_Recommendation($aecontext, false);
69
+ $products = $recomemendation->getRecommendation();
70
+
71
+ if ($products && isset($products['recommend'])) {
72
+ return $this->loadProductsById($products['recommend']);
73
+ }
74
+ return;
75
+ }
76
+
77
+ public function loadProductsById($ids) {
78
+ //$ids = array(877,875);
79
+ $products = Mage::getModel('catalog/product')->getCollection()
80
+ ->addAttributeToFilter('entity_id', array('in' => $ids));
81
+ $products->getSelect()->order("find_in_set(entity_id,'" . implode(',', $ids) . "')");
82
+ return $products;
83
+ }
84
+
85
+ public function getCartOrderLines() {
86
+ $order_lines = array();
87
+ $quote = Mage::getSingleton('checkout/session')->getQuote()->getAllItems();
88
+ if ($quote) {
89
+ foreach ($quote as $item) {
90
+ $order_line = new stdClass();
91
+ $order_line->productId = $item->getProductId();
92
+ $order_line->attributeIds = $this->getCartsProductAttributes($item);
93
+ $order_line->quantity = $item->getQty();
94
+ array_push($order_lines, $order_line);
95
+ }
96
+ }
97
+ return $order_lines;
98
+ }
99
+
100
+ public function getCartsProductAttributes($item) {
101
+ $attribute_ids = array();
102
+ $options = $item->getProduct()->getTypeInstance(true)->getOrderOptions($item->getProduct());
103
+
104
+ if (isset($options['info_buyRequest']['super_attribute']) && $ai = $options['info_buyRequest']['super_attribute']) {
105
+ foreach ($ai as $key => $val) {
106
+ array_push($attribute_ids, $key);
107
+ }
108
+ }
109
+ return $attribute_ids;
110
+ }
111
+
112
+ }
app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Classes.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Renderer_Config_Classes extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+
6
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
7
+ {
8
+ $element->setStyle('width:110px;')
9
+ ->setName($element->getName() . '[]');
10
+
11
+ if ($element->getValue()) {
12
+ $values = explode(',', $element->getValue());
13
+ } else {
14
+ $values = array();
15
+ }
16
+
17
+ $id = $element->setValue(isset($values[0]) ? $values[0] : null)->getElementHtml();
18
+ $class = $element->setValue(isset($values[1]) ? $values[1] : null)->getElementHtml();
19
+ $html = "id " . $id . "&nbsp;class " . $class;
20
+ return $html;
21
+
22
+ }
23
+ }
app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Imagesize.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Renderer_Config_ImageSize extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+
6
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
7
+ {
8
+ $element->setStyle('width:70px;')
9
+ ->setName($element->getName() . '[]');
10
+
11
+ if ($element->getValue()) {
12
+ $values = explode(',', $element->getValue());
13
+ } else {
14
+ $values = array();
15
+ }
16
+
17
+ $width = $element->setValue(isset($values[0]) ? $values[0] : null)->getElementHtml();
18
+ $height = $element->setValue(isset($values[1]) ? $values[1] : null)->getElementHtml();
19
+ return Mage::helper('adminhtml')->__('W') . ' ' . $width . ' x ' . $height . ' ' . Mage::helper('adminhtml')->__('H');
20
+ }
21
+ }
22
+
app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Ipblacklist.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Renderer_Config_Ipblacklist extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+
6
+ protected $_addRowButtonHtml = array();
7
+ protected $_removeRowButtonHtml = array();
8
+
9
+ /**
10
+ * Returns html part of the setting
11
+ *
12
+ * @param Varien_Data_Form_Element_Abstract $element
13
+ * @return string
14
+ */
15
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
16
+ {
17
+ $this->setElement($element);
18
+ $html = '<div id="blacklist_ip_header" style="width:480px;">';
19
+ $html .= '<div style="width:209px;float: left;"><b>' . $this->__("Blacklisted IP's") . '</div>';
20
+ $html .= '<div style="clear:both;"></div>';
21
+ $html .= '</div>';
22
+
23
+ $html .= '<div id="blacklist_ip_template" style="display:none">';
24
+ $html .= $this->_getRowTemplateHtml();
25
+ $html .= '</div>';
26
+
27
+ $html .= '<ul id="blacklist_ip_container" style="width:480px;">';
28
+ if ($this->_getValue('ab_blacklist_ip')) {
29
+ foreach ($this->_getValue('ab_blacklist_ip') as $i => $f) {
30
+ if ($i) {
31
+ $html .= $this->_getRowTemplateHtml($i);
32
+ }
33
+ }
34
+ }
35
+ $html .= '</ul>';
36
+ $html .= $this->_getAddRowButtonHtml('blacklist_ip_container',
37
+ 'blacklist_ip_template', $this->__('Add New'));
38
+
39
+ return $html;
40
+ }
41
+
42
+ /**
43
+ * Retrieve html template for setting
44
+ *
45
+ * @param int $rowIndex
46
+ * @return string
47
+ */
48
+ protected function _getRowTemplateHtml($rowIndex = 0)
49
+ {
50
+ $html = '<li>';
51
+ $html .= '<div>';
52
+ $html .= '<input name="'
53
+ . $this->getElement()->getName() . '[ab_blacklist_ip][]" value="'
54
+ . $this->_getValue('ab_blacklist_ip/' . $rowIndex) . '" ' . $this->_getDisabled() . '/> ';
55
+ $html .= $this->_getRemoveRowButtonHtml();
56
+ $html .= '</div>';
57
+ $html .= '</li>';
58
+
59
+ return $html;
60
+ }
61
+
62
+ protected function _getDisabled()
63
+ {
64
+ return $this->getElement()->getDisabled() ? ' disabled' : '';
65
+ }
66
+
67
+ protected function _getValue($key)
68
+ {
69
+ return $this->getElement()->getData('value/' . $key);
70
+ }
71
+
72
+ protected function _getSelected($key, $value)
73
+ {
74
+ return $this->getElement()->getData('value/' . $key) == $value ? 'selected="selected"' : '';
75
+ }
76
+
77
+ protected function _getAddRowButtonHtml($container, $template, $title='Add')
78
+ {
79
+ if (!isset($this->_addRowButtonHtml[$container])) {
80
+ $this->_addRowButtonHtml[$container] = $this->getLayout()->createBlock('adminhtml/widget_button')
81
+ ->setType('button')
82
+ ->setClass('add ' . $this->_getDisabled())
83
+ ->setLabel($this->__($title))
84
+ ->setOnClick("Element.insert($('" . $container . "'), {bottom: $('" . $template . "').innerHTML})")
85
+ ->setDisabled($this->_getDisabled())
86
+ ->toHtml();
87
+ }
88
+ return $this->_addRowButtonHtml[$container];
89
+ }
90
+
91
+ protected function _getRemoveRowButtonHtml($selector = 'li', $title = 'Delete')
92
+ {
93
+ if (!$this->_removeRowButtonHtml) {
94
+ $this->_removeRowButtonHtml = $this->getLayout()->createBlock('adminhtml/widget_button')
95
+ ->setType('button')
96
+ ->setClass('delete v-middle ' . $this->_getDisabled())
97
+ ->setLabel($this->__($title))
98
+ ->setOnClick("Element.remove($(this).up('" . $selector . "'))")
99
+ ->setDisabled($this->_getDisabled())
100
+ ->toHtml();
101
+ }
102
+ return $this->_removeRowButtonHtml;
103
+ }
104
+
105
+ }
app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Serverlist.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Renderer_Config_Serverlist extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+
6
+ protected $_addRowButtonHtml = array();
7
+ protected $_removeRowButtonHtml = array();
8
+
9
+ /**
10
+ * Returns html part of the setting
11
+ *
12
+ * @param Varien_Data_Form_Element_Abstract $element
13
+ * @return string
14
+ */
15
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
16
+ {
17
+ $this->setElement($element);
18
+ $html = '<div id="server_ip_header" style="width:480px;">';
19
+ $html .= '<div style="width:209px;float: left;"><b>'. $this->__("Server IP's") . '</div>';
20
+ $html .= '<div style="clear:both;"></div>';
21
+ $html .= '</div>';
22
+
23
+ $html .= '<div id="server_ip_template" style="display:none">';
24
+ $html .= $this->_getRowTemplateHtml();
25
+ $html .= '</div>';
26
+
27
+ $html .= '<ul id="server_ip_container" style="width:480px;">';
28
+ if ($this->_getValue('server_ip')) {
29
+ foreach ($this->_getValue('server_ip') as $i => $f) {
30
+ if ($i) {
31
+ $html .= $this->_getRowTemplateHtml($i);
32
+ }
33
+ }
34
+ }
35
+ $html .= '</ul>';
36
+ $html .= $this->_getAddRowButtonHtml('server_ip_container',
37
+ 'server_ip_template', $this->__('Add New'));
38
+
39
+ return $html;
40
+ }
41
+
42
+ /**
43
+ * Retrieve html template for setting
44
+ *
45
+ * @param int $rowIndex
46
+ * @return string
47
+ */
48
+ protected function _getRowTemplateHtml($rowIndex = 0)
49
+ {
50
+ $html = '<li>';
51
+ $html .= '<div>';
52
+ $html .= '<input name="'
53
+ . $this->getElement()->getName() . '[server_ip][]" value="'
54
+ . $this->_getValue('server_ip/' . $rowIndex) . '" ' . $this->_getDisabled() . '/> ';
55
+ $html .= $this->_getRemoveRowButtonHtml();
56
+ $html .= '</div>';
57
+ $html .= '</li>';
58
+
59
+ return $html;
60
+ }
61
+
62
+ protected function _getDisabled()
63
+ {
64
+ return $this->getElement()->getDisabled() ? ' disabled' : '';
65
+ }
66
+
67
+ protected function _getValue($key)
68
+ {
69
+ return $this->getElement()->getData('value/' . $key);
70
+ }
71
+
72
+ protected function _getSelected($key, $value)
73
+ {
74
+ return $this->getElement()->getData('value/' . $key) == $value ? 'selected="selected"' : '';
75
+ }
76
+
77
+ protected function _getAddRowButtonHtml($container, $template, $title='Add')
78
+ {
79
+ if (!isset($this->_addRowButtonHtml[$container])) {
80
+ $this->_addRowButtonHtml[$container] = $this->getLayout()->createBlock('adminhtml/widget_button')
81
+ ->setType('button')
82
+ ->setClass('add ' . $this->_getDisabled())
83
+ ->setLabel($this->__($title))
84
+ ->setOnClick("Element.insert($('" . $container . "'), {bottom: $('" . $template . "').innerHTML})")
85
+ ->setDisabled($this->_getDisabled())
86
+ ->toHtml();
87
+ }
88
+ return $this->_addRowButtonHtml[$container];
89
+ }
90
+
91
+ protected function _getRemoveRowButtonHtml($selector = 'li', $title = 'Delete')
92
+ {
93
+ if (!$this->_removeRowButtonHtml) {
94
+ $this->_removeRowButtonHtml = $this->getLayout()->createBlock('adminhtml/widget_button')
95
+ ->setType('button')
96
+ ->setClass('delete v-middle ' . $this->_getDisabled())
97
+ ->setLabel($this->__($title))
98
+ ->setOnClick("Element.remove($(this).up('" . $selector . "'))")
99
+ ->setDisabled($this->_getDisabled())
100
+ ->toHtml();
101
+ }
102
+ return $this->_removeRowButtonHtml;
103
+ }
104
+
105
+ }
app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Siteinfo.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Renderer_Config_Siteinfo extends Mage_Adminhtml_Block_System_Config_Form_Field {
4
+
5
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) {
6
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_SiteRequest(array());
7
+ $data = $request->get();
8
+ $html = '<div style="width:90%;">';
9
+ if (strpos($element->getName(), 'monthly_recommendations') && $data['_ok']) {
10
+ $html .= $data['recommendation'] . ' ' . $this->__('recos');
11
+ } elseif (strpos($element->getName(), 'sales_impact') && $data['_ok']) {
12
+ $html .= $this->__('Impact statistics under construction');
13
+ // if (isset($data['statistics'])) {
14
+ // $statistics = Mage::helper('core')->jsonDecode($data['statistics']);
15
+ // if ($statistics['salesImpactByPercentage'] > 0) {
16
+ // $html .= $statistics['salesImpactByPercentage'] . '%';
17
+ // }
18
+ // }
19
+ }
20
+ $html .= '</div>';
21
+ return $html;
22
+ }
23
+
24
+ }
app/code/local/AffinityEngine/AffinityItems/Block/Renderer/Config/Version.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Block_Renderer_Config_Version extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
6
+ {
7
+ return (string) Mage::helper('affinityitems')->getExtensionVersion();
8
+ }
9
+ }
app/code/local/AffinityEngine/AffinityItems/Helper/Aeadapter.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Helper_Aeadapter extends Mage_Core_Helper_Abstract {
4
+
5
+ public function authentication($email, $password, $site_id, $security_key) {
6
+ $ae_config = new Mage_Core_Model_Config();
7
+ $ae_config->saveConfig('affinityitems/security/login', $email, 'default', 0);
8
+ $ae_config->saveConfig('affinityitems/security/password', 'empty', 'default', 0);
9
+ $ae_config->saveConfig('affinityitems/security/site_id', $site_id, 'default', 0);
10
+ $ae_config->saveConfig('affinityitems/security/key', $security_key, 'default', 0);
11
+ }
12
+
13
+ public function getTestHost() {
14
+ return $this->getConfigFromDb('affinityitems/security/conf_test_host');
15
+ }
16
+
17
+ public function getProdHost() {
18
+ return $this->getConfigFromDb('affinityitems/security/conf_prod_host');
19
+ }
20
+
21
+ public function getPort() {
22
+ return $this->getConfigFromDb('affinityitems/security/conf_port');
23
+ }
24
+
25
+ public function getSiteId() {
26
+ return $this->getConfigFromDb('affinityitems/security/site_id');
27
+ }
28
+
29
+ public function getLogin() {
30
+ return $this->getConfigFromDb('affinityitems/security/login');
31
+ }
32
+
33
+ public function getPassowrd() {
34
+ return $this->getConfigFromDb('affinityitems/security/password');
35
+ }
36
+
37
+ public function getSecurityKey() {
38
+ return $this->getConfigFromDb('affinityitems/security/key');
39
+ }
40
+
41
+ public function getRegisterUrl() {
42
+ return Mage::helper("adminhtml")->getUrl("affinityitems/adminhtml_ajax/register");
43
+ }
44
+
45
+ public function getLoginUrl() {
46
+ return Mage::helper("adminhtml")->getUrl("affinityitems/adminhtml_ajax/login");
47
+ }
48
+
49
+ public function isRegistered() {
50
+ return ($this->getLogin() && $this->getPassowrd() && $this->getSiteId() && $this->getSecurityKey()) ? true : false;
51
+ }
52
+
53
+ public function checkSync($value = false) {
54
+ if (!$value) return false;
55
+ switch ($value) {
56
+ case 'categories':
57
+ return (count(Mage::getModel('affinityitems/sync_sync')->getCategoriesForSync()) > 0 || count(Mage::getModel('affinityitems/sync_sync')->getDeletedCategoriesForSync()) > 0) ? false : true;
58
+ break;
59
+ case 'products':
60
+ return (count(Mage::getModel('affinityitems/sync_sync')->getProductsForSync()) > 0 || count(Mage::getModel('affinityitems/sync_sync')->getDeletedProductsForSync()) > 0) ? false : true;
61
+ break;
62
+ case 'orders':
63
+ return (count(Mage::getModel('affinityitems/sync_sync')->getOrdersForSync()) > 0) ? false : true;
64
+ break;
65
+ case 'cart':
66
+ return (count(Mage::getModel('affinityitems/sync_sync')->getCartForSync()) > 0) ? false : true;
67
+ break;
68
+ case 'actions':
69
+ return (count(Mage::getModel('affinityitems/sync_sync')->getActionsForSync()) > 0) ? false : true;
70
+ break;
71
+ default:
72
+ return false;
73
+ break;
74
+ }
75
+ }
76
+
77
+ public function getHost() {
78
+ return ($this->getConfigFromDb('affinityitems/general/dev_prod')) ? $this->getProdHost() : $this->getTestHost();
79
+ }
80
+
81
+ public function getConfigFromDb($path = false) {
82
+ return ($path) ? Mage::getModel('affinityitems/config')->getValue($path) : false;
83
+ }
84
+
85
+ }
app/code/local/AffinityEngine/AffinityItems/Helper/Data.php ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Helper_Data extends Mage_Core_Helper_Abstract {
4
+
5
+ const XML_PATH = 'affinityitems/';
6
+ const ENABLE = '/enable';
7
+
8
+ public function isEnabled() {
9
+ return (bool) ($this->isAeEnabled() && Mage::getStoreConfig(self::XML_PATH . $this->getXmlPath() . self::ENABLE));
10
+ }
11
+
12
+ public function isLeftEnabled() {
13
+ return (bool) ($this->isAeEnabled() && Mage::getStoreConfig(self::XML_PATH . 'items_left' . self::ENABLE));
14
+ }
15
+
16
+ public function isRightEnabled() {
17
+ return (bool) ($this->isAeEnabled() && Mage::getStoreConfig(self::XML_PATH . 'items_right' . self::ENABLE));
18
+ }
19
+
20
+ public function isSideEnabled() {
21
+ return ($this->isRightEnabled() || $this->isLeftEnabled());
22
+ }
23
+
24
+ public function isAeEnabled() {
25
+ return (bool) Mage::getStoreConfig(self::XML_PATH . 'general/enable');
26
+ }
27
+
28
+ public function getXmlPath() {
29
+ return 'items_' . $this->getCurrentPage();
30
+ }
31
+
32
+ public function getCurrentPage() {
33
+ $path = Mage::app()->getRequest()->getRouteName() . Mage::app()->getRequest()->getControllerName();
34
+ switch ($path) {
35
+ case 'cmsindex':
36
+ return "home";
37
+ break;
38
+ case 'catalogcategory':
39
+ return "category";
40
+ break;
41
+ case 'catalogproduct':
42
+ return "product";
43
+ break;
44
+ case 'checkoutcart':
45
+ return "cart";
46
+ break;
47
+ case 'catalogsearchresult':
48
+ return "search";
49
+ break;
50
+ }
51
+ return 'category';
52
+ }
53
+
54
+
55
+ public function getExtensionVersion()
56
+ {
57
+ return (string) Mage::getConfig()->getNode()->modules->AffinityEngine_AffinityItems->version;
58
+ }
59
+
60
+ public function getConfig($endPath = false) {
61
+ if (!$endPath)
62
+ return;
63
+ $value = Mage::getStoreConfig(self::XML_PATH . $this->getXmlPath() . '/' . $endPath);
64
+ return (strpos($value, ',') !== false) ? explode(",", $value) : $value;
65
+ }
66
+
67
+ public function getGeneral($endPath = false) {
68
+ if (!$endPath)
69
+ return;
70
+ $value = Mage::getStoreConfig(self::XML_PATH . 'general/' . $endPath);
71
+ return $value;
72
+ }
73
+
74
+ public function getAdvanced($endPath = false) {
75
+ if (!$endPath)
76
+ return;
77
+ $value = Mage::getStoreConfig(self::XML_PATH . 'advanced/' . $endPath);
78
+ return $value;
79
+ }
80
+
81
+ public function getLeftNOP($endPath = false) {
82
+ if (!$endPath)
83
+ return;
84
+ $value = Mage::getStoreConfig(self::XML_PATH . 'items_left/' . $endPath);
85
+ return (strpos($value, ',') !== false) ? explode(",", $value) : $value;
86
+ }
87
+
88
+ public function getRightNOP($endPath = false) {
89
+ if (!$endPath)
90
+ return;
91
+ $value = Mage::getStoreConfig(self::XML_PATH . 'items_right/' . $endPath);
92
+ return (strpos($value, ',') !== false) ? explode(",", $value) : $value;
93
+ }
94
+
95
+ public function getId($endPath = false) {
96
+ if (!$endPath)
97
+ return;
98
+ $value = $this->getConfig($endPath);
99
+ if (is_array($value) && array_key_exists(0, $value))
100
+ return $value[0];
101
+ return $value;
102
+ }
103
+
104
+ public function getClass($endPath = false) {
105
+ if (!$endPath)
106
+ return;
107
+ $value = $this->getConfig($endPath);
108
+ if (is_array($value) && array_key_exists(1, $value))
109
+ return $value[1];
110
+ return $value;
111
+ }
112
+
113
+ public function getImageSize() {
114
+ $i_type = $this->getImageType();
115
+ $value = Mage::getStoreConfig(self::XML_PATH . 'image_size/' . $i_type[$this->getConfig('image_size')]);
116
+ return (strpos($value, ',') !== false) ? explode(",", $value) : $value;
117
+ }
118
+
119
+ public function getLImageSize() {
120
+ $i_type = $this->getImageType();
121
+ $conf = Mage::getStoreConfig(self::XML_PATH . 'items_left/image_size');
122
+ $value = Mage::getStoreConfig(self::XML_PATH . 'image_size/' . $i_type[$conf]);
123
+ return (strpos($value, ',') !== false) ? explode(",", $value) : $value;
124
+ }
125
+
126
+ public function getRImageSize() {
127
+ $i_type = $this->getImageType();
128
+ $conf = Mage::getStoreConfig(self::XML_PATH . 'items_right/image_size');
129
+ $value = Mage::getStoreConfig(self::XML_PATH . 'image_size/' . $i_type[$conf]);
130
+ return (strpos($value, ',') !== false) ? explode(",", $value) : $value;
131
+ }
132
+
133
+ public function getImageType() {
134
+ return Array(0 => 'default', 1 => 'large', 2 => 'medium', 3 => 'small');
135
+ }
136
+
137
+ public function getSideTitle($side = false) {
138
+ if (!$side)
139
+ return;
140
+ return ($side == 'ae_vertical_left') ? Mage::getStoreConfig(self::XML_PATH . 'items_left/recommendation_label') : Mage::getStoreConfig(self::XML_PATH . 'items_right/recommendation_label');
141
+ }
142
+
143
+ public function getFullProductUrl($product) {
144
+ if (is_object($product) && $product->getSku()) {
145
+ // first try SQL approach
146
+ try {
147
+ $cats = $product->getCategoryIds();
148
+ $query = "
149
+ SELECT `request_path`
150
+ FROM `".Mage::getSingleton('core/resource')->getTableName('core_url_rewrite')."`
151
+ WHERE `product_id`='" . $product->getEntityId() . "'
152
+ AND `category_id`='" . end($cats) . "'
153
+ AND `store_id`='" . Mage::app()->getStore()->getId() . "';
154
+ ";
155
+ $read = Mage::getSingleton('core/resource')->getConnection('affinityitems_read');
156
+ $result = $read->fetchRow($query);
157
+ if(!$result) throw new Exception('no record in db');
158
+ return Mage::getUrl('') . $result['request_path'];
159
+ }
160
+ // if it fails, than use failsafe way with category object loading
161
+ catch (Exception $e) {
162
+ $allCategoryIds = $product->getCategoryIds();
163
+ $lastCategoryId = end($allCategoryIds);
164
+ $lastCategory = Mage::getModel('catalog/category')->load($lastCategoryId);
165
+ $lastCategoryUrl = $lastCategory->getUrl();
166
+ $fullProductUrl = str_replace(Mage::getStoreConfig('catalog/seo/category_url_suffix'), '/', $lastCategoryUrl) . basename($product->getUrlKey()) . Mage::getStoreConfig('catalog/seo/product_url_suffix');
167
+ if (strpos($fullProductUrl, 'catalog/category/view')) {
168
+ $fullProductUrl = basename($product->getUrlKey()) . Mage::getStoreConfig('catalog/seo/product_url_suffix');
169
+ }
170
+ return $fullProductUrl;
171
+ }
172
+ }
173
+ return;
174
+ }
175
+
176
+ public function getFormatedPrice($product) {
177
+ $blockname = (Mage::registry('current_product')) ? 'view' : 'list';
178
+ return $this->getLayout()->createBlock('catalog/product_' . $blockname)->setProd($product)->setTemplate('affinityengine/pricehtml.phtml')->toHtml();
179
+ }
180
+
181
+ public function log($severity, $message) {
182
+ Mage::getModel('affinityitems/log')->log($severity, $message);
183
+ return;
184
+ }
185
+
186
+ public function isAdmin() {
187
+ if (Mage::app()->getStore()->isAdmin()) {
188
+ return true;
189
+ }
190
+
191
+ if (Mage::getDesign()->getArea() == 'adminhtml') {
192
+ return true;
193
+ }
194
+ return false;
195
+ }
196
+
197
+ public function generateGuest() {
198
+ $aeguest = str_replace('.', '', uniqid('ae', true));
199
+ Mage::getModel('core/cookie')->set('aeguest', $aeguest, 630720000);
200
+ return;
201
+ }
202
+
203
+ public function isModuleEnabledAndRegistered() {
204
+ return (bool) Mage::helper('affinityitems/aeadapter')->isRegistered() && $this->getGeneral('enable');
205
+ }
206
+
207
+ public function canDisplayProduct($product) {
208
+ $stock = Mage::getModel('cataloginventory/stock_item')->loadByProduct($product);
209
+ return (bool) (!$product->getStatus() == 2 || $product->getVisibility() == 1 || $stock->getIsInStock() == 0 || count($product->getCategoryIds()) == 0 );
210
+ }
211
+
212
+ public function getIp() {
213
+ return long2ip(Mage::helper('core/http')->getRemoteAddr(true));
214
+ }
215
+
216
+ public function getMemberId() {
217
+ if(Mage::getSingleton('customer/session')->isLoggedIn()) {
218
+ $customerData = Mage::getSingleton('customer/session')->getCustomer();
219
+ return $customerData->getId();
220
+ } else {
221
+ return '';
222
+ }
223
+ }
224
+
225
+ public function getLang() {
226
+ return substr(Mage::app()->getLocale()->getLocaleCode(), 0, 2);
227
+ }
228
+
229
+ public function deleteCategorySync() {
230
+ $categories = Mage::getModel('catalog/category')->getCollection();
231
+ $categories->addIsActiveFilter()
232
+ ->addAttributeToFilter(
233
+ array(
234
+ array('attribute' => 'ae_sync', 'null' => false),
235
+ array('attribute' => 'ae_sync', 'eq' => 1),
236
+ ), '', 'left');
237
+ $categories->setDataToAll('ae_sync', 0)->setDataToAll('observer', true)->setDataToAll('ae_sync_date', null)->save();
238
+ }
239
+
240
+ public function deleteProductSync() {
241
+ $products = Mage::getModel('catalog/product')->getCollection();
242
+ $products->addStoreFilter(0)
243
+ ->addAttributeToFilter(
244
+ array(
245
+ array('attribute' => 'ae_sync', 'null' => false),
246
+ array('attribute' => 'ae_sync', 'eq' => 1),
247
+ ), '', 'left');
248
+ $products->addFieldToFilter('visibility', Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH);
249
+ $products->setDataToAll('ae_sync', 0)->setDataToAll('observer', true)->setDataToAll('ae_sync_date', null)->save();
250
+ }
251
+
252
+ public function deleteOrderSync() {
253
+ $orders = Mage::getModel('sales/order')->getCollection();
254
+ $orders->addFieldToFilter('state', array('in' => array('new', 'pending_payment', 'processing', 'complete', 'payment_review')))
255
+ ->addFieldToFilter('ae_sync', array('in' => array(1)));
256
+ $orders->setDataToAll('ae_sync', 0)->setDataToAll('observer', true)->save();
257
+ }
258
+
259
+ public function deleteMemberSync() {
260
+ $members = Mage::getModel('customer/customer')->getCollection();
261
+ $members->addAttributeToFilter(
262
+ array(
263
+ array('attribute' => 'ae_sync', 'null' => false),
264
+ array('attribute' => 'ae_sync', 'eq' => 1),
265
+ ), '', 'left');
266
+ $members->setDataToAll('ae_sync', 0)->save();
267
+ }
268
+
269
+ public function deleteCartSync() {
270
+ $carts = Mage::getModel("affinityitems/cart")->getCollection();
271
+ foreach ($carts as $cart) {
272
+ $cart->delete();
273
+ }
274
+ }
275
+
276
+ public function deleteActionSync() {
277
+ $actions = Mage::getModel("affinityitems/action")->getCollection();
278
+ foreach ($actions as $action) {
279
+ $action->delete();
280
+ }
281
+ }
282
+
283
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Action.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Action extends Mage_Core_Model_Abstract
4
+ {
5
+ protected function _construct()
6
+ {
7
+ $this->_init('affinityitems/action');
8
+ }
9
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Cart.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Cart extends Mage_Core_Model_Abstract {
4
+
5
+ protected function _construct() {
6
+ $this->_init('affinityitems/cart');
7
+ }
8
+
9
+ public function cartrepo($id_cart, $id_product, $quantity, $action, $attributes = array(), $aeguestId, $aegroup, $ip, $aememberId = '', $language = '') {
10
+
11
+ $test=$this->setData(
12
+ array(
13
+ 'id_cart' => $id_cart,
14
+ 'date_add' => new Zend_Db_Expr('NOW()'),
15
+ 'id_product' => $id_product,
16
+ 'id_product_attribute' => (string) serialize($attributes),
17
+ 'quantity' => $quantity,
18
+ 'action' => $action,
19
+ 'aeguestid' => $aeguestId,
20
+ 'aememberid' => $aememberId,
21
+ 'aegroup' => $aegroup,
22
+ 'language' => $language,
23
+ 'ip' => $ip
24
+ )
25
+ )->save();
26
+ }
27
+
28
+ }
app/code/local/AffinityEngine/AffinityItems/Model/CatProdRepo.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_CatProdRepo extends Mage_Core_Model_Abstract {
4
+
5
+ protected function _construct() {
6
+ $this->_init('affinityitems/catProdRepo');
7
+ }
8
+
9
+ public function addToCatProdRepo($obj_id, $obj_type) {
10
+
11
+ $test=$this->setData(
12
+ array(
13
+ 'obj_id' => $obj_id,
14
+ 'obj_type' => $obj_type
15
+ )
16
+ )->save();
17
+ }
18
+
19
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Config.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Config extends Mage_Core_Model_Abstract {
4
+
5
+ public function getValue($path, $storeId = 0) {
6
+ $query = "
7
+ SELECT `value`
8
+ FROM `" . Mage::getSingleton('core/resource')->getTableName('core_config_data') . "`
9
+ WHERE `scope_id`='" . $storeId . "'
10
+ AND `path` = '" . $path . "' ;";
11
+ $read = Mage::getSingleton('core/resource')->getConnection('affinityitems_read');
12
+ $result = $read->fetchRow($query);
13
+ if (!$result) return false;
14
+ return $result['value'];
15
+ }
16
+
17
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Cron.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Cron {
4
+
5
+ const PROCESS_ID = 'Affinity_Sync';
6
+
7
+ private $indexProcess;
8
+
9
+ public function __construct() {
10
+ $this->indexProcess = new Mage_Index_Model_Process();
11
+ $this->indexProcess->setId(self::PROCESS_ID);
12
+ $this->isShell = Mage::registry('run_from_shell');
13
+ $this->helper = Mage::helper('affinityitems');
14
+ $this->logger = Mage::getModel('affinityitems/log');
15
+ }
16
+
17
+ public function Sync() {
18
+ if (!$this->helper->isModuleEnabledAndRegistered()) {
19
+ $this->logger->log("[INFO]", "You are not logged in to Affinity, or extension is not enabled ! [" . time() . "]");
20
+ if ($this->isShell)
21
+ echo "You are not logged in to Affinity, or extension is not enabled !" . "\n";
22
+ return false;
23
+ }
24
+ if ($this->indexProcess->isLocked()) {
25
+ $this->logger->log("[INFO]", "Another AE Sync process is running! [" . time() . "]");
26
+ if ($this->isShell)
27
+ echo "Another AE Sync process is running!" . "\n";
28
+ return false;
29
+ }
30
+ if ($this->isShell)
31
+ echo "Setting locks" . "\n";
32
+
33
+ $this->indexProcess->lockAndBlock();
34
+
35
+ $sync_model = Mage::getModel('affinityitems/sync_sync');
36
+ $syncrotate_model = Mage::getModel('affinityitems/syncrotate');
37
+ $last_sync = (count($syncrotate_model->getCollection())) ? $syncrotate_model->getCollection()->getFirstItem()->getData('last_sync') : 'actions';
38
+ $initialsync = (count($syncrotate_model->getCollection())) ? (bool) $syncrotate_model->getCollection()->getFirstItem()->getData('initial_sync') : true;
39
+ $sync_count = $this->helper->getAdvanced('sync_count');
40
+
41
+ if ($initialsync) {
42
+ if ($this->isShell)
43
+ echo " - Initial sync in progress..." . "\n";
44
+ $this->logger->log("[INFO]", "Initial sync in progress...! [" . time() . "]");
45
+ }
46
+
47
+ $resyncRequest = new AffinityEngine_AffinityItems_Model_Sdk_Request_ResynchronizeRequest(array());
48
+ $elementList = $resyncRequest->get();
49
+ if(isset($elementList['synchro'])) {
50
+ if(is_array($elementList['synchro'])) {
51
+ foreach ($elementList['synchro'] as $element) {
52
+ if ($this->isShell)
53
+ echo " - Resync process " . ucfirst(strtolower($element)) . "..." . "\n";
54
+ switch ($element) {
55
+ case 'CATEGORY':
56
+ $this->helper->deleteCategorySync();
57
+ break;
58
+ case 'PRODUCT':
59
+ $this->helper->deleteProductSync();
60
+ break;
61
+ case 'MEMBER':
62
+ $this->helper->deleteMemberSync();
63
+ break;
64
+ case 'CART':
65
+ $this->helper->deleteCartSync();
66
+ break;
67
+ case 'ORDER':
68
+ $this->helper->deleteOrderSync();
69
+ break;
70
+ case 'ACTION':
71
+ $this->helper->deleteActionSync();
72
+ break;
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ if(isset($elementList['abRatio'])) {
79
+ Mage::getModel('core/config')->saveConfig('affinityitems/general/guest_percentage', ($elementList['abRatio']*100));
80
+ }
81
+
82
+ if(isset($elementList['trackingJs'])) {
83
+ Mage::getModel('core/config')->saveConfig('affinityitems/advanced/ae_tracking_js', (int)$elementList['trackingJs']);
84
+ }
85
+
86
+ if ((count($sync_model->getCategoriesForSync()) || count($sync_model->getDeletedCategoriesForSync())) && ($last_sync == 'actions' || $initialsync)) {
87
+ if ($this->isShell)
88
+ echo " - Syncing categories..." . "\n";
89
+ $syncrotate_model->upd('categories');
90
+ Mage::getModel('affinityitems/sync_categorySync')->syncCategories($sync_count, true); //new
91
+ Mage::getModel('affinityitems/sync_categorySync')->syncCategories($sync_count, false); //old
92
+ Mage::getModel('affinityitems/sync_categorySync')->syncDeletedCategories($sync_count);
93
+
94
+ } elseif ((count($sync_model->getProductsForSync()) || count($sync_model->getDeletedProductsForSync())) && ($last_sync == 'categories' || $initialsync)) {
95
+ if ($this->isShell)
96
+ echo " - Syncing products..." . "\n";
97
+ $syncrotate_model->upd('products');
98
+ Mage::getModel('affinityitems/sync_productSync')->syncProducts($sync_count, true); //new
99
+ Mage::getModel('affinityitems/sync_productSync')->syncProducts($sync_count, false); //old
100
+ Mage::getModel('affinityitems/sync_productSync')->syncDeletedProducts($sync_count);
101
+
102
+ } elseif((count($sync_model->getMembersForSync())) && ($last_sync == 'products' || $initialsync)) {
103
+ if ($this->isShell)
104
+ echo " - Syncing members..." . "\n";
105
+ $syncrotate_model->upd('members');
106
+ Mage::getModel('affinityitems/sync_memberSync')->syncMember($sync_count);
107
+ } elseif (count($sync_model->getOrdersForSync()) && ($last_sync == 'members' || $initialsync)) {
108
+ if ($this->isShell)
109
+ echo " - Syncing orders..." . "\n";
110
+ $syncrotate_model->upd('orders');
111
+ Mage::getModel('affinityitems/sync_orderSync')->syncOrders($sync_count);
112
+ } elseif (count($sync_model->getCartForSync()) && ($last_sync == 'orders' || $initialsync)) {
113
+ if ($this->isShell)
114
+ echo " - Syncing cart actions..." . "\n";
115
+ $syncrotate_model->upd('cart');
116
+ Mage::getModel('affinityitems/sync_CartActionSync')->syncCartActions($sync_count);
117
+
118
+ } elseif (count($sync_model->getActionsForSync()) && ($last_sync == 'cart' || $initialsync)) {
119
+ if ($this->isShell)
120
+ echo " - Syncing actions..." . "\n";
121
+ $syncrotate_model->upd('actions');
122
+ Mage::getModel('affinityitems/sync_ActionSync')->syncActions($sync_count);
123
+
124
+ } else {
125
+ if ($initialsync) {
126
+ $syncrotate_model->updInitial(0);
127
+ if ($this->isShell)
128
+ echo " - Initial sync finished..." . "\n";
129
+ $this->logger->log("[INFO]", "Initial sync finished...! [" . time() . "]");
130
+ }
131
+ if ($this->isShell)
132
+ echo " - Tried to sync " . $last_sync . "..." . "\n";
133
+ switch ($last_sync) {
134
+ case 'actions':
135
+ $syncrotate_model->upd('categories');
136
+ break;
137
+ case 'categories':
138
+ $syncrotate_model->upd('products');
139
+ break;
140
+ case 'products':
141
+ $syncrotate_model->upd('members');
142
+ break;
143
+ case 'members':
144
+ $syncrotate_model->upd('orders');
145
+ break;
146
+ case 'orders':
147
+ $syncrotate_model->upd('cart');
148
+ break;
149
+ case 'cart':
150
+ $syncrotate_model->upd('actions');
151
+ break;
152
+ }
153
+ }
154
+ if ($this->isShell)
155
+ echo "Removing locks" . "\n";
156
+ // Remove the lock.
157
+ $this->indexProcess->unlock();
158
+ }
159
+
160
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Log.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Log extends Mage_Core_Model_Abstract {
4
+
5
+ protected function _construct() {
6
+ $this->_init('affinityitems/log');
7
+ }
8
+
9
+ public function log($severity, $message) {
10
+ $log_level = Mage::getStoreConfig('affinityitems/developer/log_level');
11
+ if ($log_level == '0' || ($log_level == '1' && $severity != "[INFO]") || ($log_level == '2' && $severity != "[ERROR]")) return;
12
+ $this->setData(array('date_add' => new Zend_Db_Expr('NOW()'), 'severity' => $severity, 'message' => $message))->save();
13
+ }
14
+
15
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Observer.php ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Observer {
4
+
5
+ public function __construct() {
6
+ $this->logger = Mage::getModel('affinityitems/log');
7
+ $this->cookie = Mage::getModel('core/cookie');
8
+ $this->helper = Mage::helper('affinityitems');
9
+ $this->aegroups = array("A", "B");
10
+ }
11
+
12
+ public function addToCart($observer) {
13
+ if ($this->helper->isModuleEnabledAndRegistered()) {
14
+ if ($this->cookie->get('aeguest') && in_array($this->cookie->get('aegroup'), $this->aegroups)) {
15
+ $cart_repo_model = Mage::getModel("affinityitems/cart");
16
+ $options = $observer->getProduct()->getTypeInstance(true)->getOrderOptions($observer->getProduct());
17
+ $attribute_ids = array();
18
+
19
+ if (isset($options['info_buyRequest']['super_attribute']) && $ai = $options['info_buyRequest']['super_attribute']) {
20
+ foreach ($ai as $key => $val) {
21
+ array_push($attribute_ids, $key);
22
+ }
23
+ }
24
+
25
+ $action = new Varien_Object();
26
+ $action->setIdCart(Mage::helper('checkout')->getQuote()->getId());
27
+ $action->setAction('addToCart');
28
+ $action->setQuantity($observer->getData('product')->getData('cart_qty'));
29
+ $action->setAegroup($this->cookie->get('aegroup'));
30
+ $action->setAeguestid($this->cookie->get('aeguest'));
31
+ $action->setAememberid($this->helper->getMemberId());
32
+ $action->setDateAdd(date("Y-m-d H:i:s"));
33
+ $action->setIdProduct($observer->getData('product')->getData('entity_id'));
34
+ $action->setIdProductAttribute(serialize($attribute_ids));
35
+ $action->setIp($this->helper->getIp());
36
+ $action->setLanguage($this->helper->getLang());
37
+
38
+ if (!Mage::getModel('affinityitems/sync_cartActionSync')->syncCartFromObserver($action)) {
39
+ $cart_repo_model->cartrepo(
40
+ $action->getIdCart(), $action->getIdProduct(), $action->getQuantity(), $action->getAction(), $attribute_ids, $action->getAeguestid(), $action->getAegroup(), $action->getIp(), $action->getAememberid(), $action->getLanguage());
41
+ }
42
+
43
+
44
+ // save to session current cart status
45
+ $quote = Mage::helper('checkout')->getQuote();
46
+ $i = 1;
47
+ foreach ($quote->getItemsCollection() as $item) {
48
+ $cart_before_update[$i]['product_id'] = $item->getProductId();
49
+ $cart_before_update[$i]['qty'] = $item->getQty();
50
+ $i++;
51
+ }
52
+ Mage::getSingleton('customer/session')->setData('cart_before_update', $cart_before_update);
53
+ }
54
+ }
55
+ }
56
+
57
+ public function updateCart($observer) {
58
+ if ($this->helper->isModuleEnabledAndRegistered()) {
59
+ if ($aeguestId = $this->cookie->get('aeguest') && in_array($this->cookie->get('aegroup'), $this->aegroups)) {
60
+ $cart = Mage::getModel('checkout/cart')->getQuote();
61
+ $cart_repo_model = Mage::getModel("affinityitems/cart");
62
+
63
+ foreach (Mage::getSingleton('customer/session')->getData('cart_before_update') as $prod) {
64
+ foreach ($cart->getAllItems() as $item) {
65
+ if ($item->getProductId() == $prod['product_id']) {
66
+ if ($item->getQty() != $prod['qty']) {
67
+
68
+ $options = $item->getProduct()->getTypeInstance(true)->getOrderOptions($item->getProduct());
69
+ $attribute_ids = array();
70
+
71
+ if (isset($options['info_buyRequest']['super_attribute']) && $ai = $options['info_buyRequest']['super_attribute']) {
72
+ foreach ($ai as $key => $val) {
73
+ array_push($attribute_ids, $key);
74
+ }
75
+ }
76
+
77
+ $action = new Varien_Object();
78
+ $action->setIdCart(Mage::helper('checkout')->getQuote()->getId());
79
+ $action->setAction('updateCart');
80
+ $action->setQuantity($item->getQty());
81
+ $action->setAegroup($this->cookie->get('aegroup'));
82
+ $action->setAeguestid($this->cookie->get('aeguest'));
83
+ $action->setAememberid($this->helper->getMemberId());
84
+ $action->setDateAdd(date("Y-m-d H:i:s"));
85
+ $action->setIdProduct($prod['product_id']);
86
+ $action->setIdProductAttribute(serialize($attribute_ids));
87
+ $action->setIp($this->helper->getIp());
88
+ $action->setLanguage($this->helper->getLang());
89
+
90
+ if (!Mage::getModel('affinityitems/sync_cartActionSync')->syncCartFromObserver($action)) {
91
+ $cart_repo_model->cartrepo(
92
+ $action->getIdCart(), $action->getIdProduct(), $action->getQuantity(), $action->getAction(), $attribute_ids, $action->getAeguestid(), $action->getAegroup(), $action->getIp(), $action->getAememberid(), $action->getLanguage());
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ // save new session current cart status
100
+ $quote = Mage::helper('checkout')->getQuote();
101
+ $i = 1;
102
+ foreach ($quote->getItemsCollection() as $item) {
103
+ $cart_before_update[$i]['product_id'] = $item->getProductId();
104
+ $cart_before_update[$i]['qty'] = $item->getQty();
105
+ $i++;
106
+ }
107
+ Mage::getSingleton('customer/session')->setData('cart_before_update', $cart_before_update);
108
+ }
109
+ }
110
+ }
111
+
112
+ public function updateProductCart($observer) {
113
+ if ($this->helper->isModuleEnabledAndRegistered()) {
114
+ if ($aeguestId = $this->cookie->get('aeguest') && in_array($this->cookie->get('aegroup'), $this->aegroups)) {
115
+ $cart_repo_model = Mage::getModel("affinityitems/cart");
116
+
117
+ foreach (Mage::getSingleton('customer/session')->getData('cart_before_update') as $prod) {
118
+ if ($observer->getData('quote_item')->getData('product_id') == $prod['product_id']) {
119
+ if ($observer->getData('quote_item')->getData('qty') != $prod['qty']) {
120
+
121
+ $options = $observer->getQuoteItem()->getProduct()->getTypeInstance(true)->getOrderOptions($observer->getQuoteItem()->getProduct());
122
+ $attribute_ids = array();
123
+
124
+ if (isset($options['info_buyRequest']['super_attribute']) && $ai = $options['info_buyRequest']['super_attribute']) {
125
+ foreach ($ai as $key => $val) {
126
+ array_push($attribute_ids, $key);
127
+ }
128
+ }
129
+
130
+ $action = new Varien_Object();
131
+ $action->setIdCart(Mage::helper('checkout')->getQuote()->getId());
132
+ $action->setAction('updateCart');
133
+ $action->setQuantity($observer->getData('quote_item')->getData('qty'));
134
+ $action->setAegroup($this->cookie->get('aegroup'));
135
+ $action->setAeguestid($this->cookie->get('aeguest'));
136
+ $action->setAememberid($this->helper->getMemberId());
137
+ $action->setDateAdd(date("Y-m-d H:i:s"));
138
+ $action->setIdProduct($prod['product_id']);
139
+ $action->setIdProductAttribute(serialize($attribute_ids));
140
+ $action->setIp($this->helper->getIp());
141
+ $action->setLanguage($this->helper->getLang());
142
+
143
+ if (!Mage::getModel('affinityitems/sync_cartActionSync')->syncCartFromObserver($action)) {
144
+ $cart_repo_model->cartrepo(
145
+ $action->getIdCart(), $action->getIdProduct(), $action->getQuantity(), $action->getAction(), $attribute_ids, $action->getAeguestid(), $action->getAegroup(), $action->getIp(), $action->getAememberid(), $action->getLanguage());
146
+ }
147
+ break;
148
+ }
149
+ }
150
+ }
151
+
152
+ // save new session current cart status
153
+ $quote = Mage::helper('checkout')->getQuote();
154
+ $i = 1;
155
+ foreach ($quote->getItemsCollection() as $item) {
156
+ $cart_before_update[$i]['product_id'] = $item->getProductId();
157
+ $cart_before_update[$i]['qty'] = $item->getQty();
158
+ $i++;
159
+ }
160
+ Mage::getSingleton('customer/session')->setData('cart_before_update', $cart_before_update);
161
+ }
162
+ }
163
+ }
164
+
165
+ public function removeFromCart($observer) {
166
+ if ($this->helper->isModuleEnabledAndRegistered()) {
167
+ if ($aeguestId = $this->cookie->get('aeguest') && in_array($this->cookie->get('aegroup'), $this->aegroups)) {
168
+ $options = $observer->getQuoteItem()->getProduct()->getTypeInstance(true)->getOrderOptions($observer->getQuoteItem()->getProduct());
169
+ $attribute_ids = array();
170
+
171
+ if (isset($options['info_buyRequest']['super_attribute']) && $ai = $options['info_buyRequest']['super_attribute']) {
172
+ foreach ($ai as $key => $val) {
173
+ array_push($attribute_ids, $key);
174
+ }
175
+ }
176
+ foreach ($session_cart = Mage::getSingleton('customer/session')->getData('cart_before_update') as $prod) {
177
+ if ($observer->getData('quote_item')->getData('product_id') == $prod['product_id']) {
178
+ $qty = $prod['qty'];
179
+ break;
180
+ }
181
+ }
182
+
183
+ $qty = (isset($qty)) ? $qty : 1;
184
+ $cart_repo_model = Mage::getModel("affinityitems/cart");
185
+
186
+ $action = new Varien_Object();
187
+ $action->setIdCart(Mage::helper('checkout')->getQuote()->getId());
188
+ $action->setAction('removeFromCart');
189
+ $action->setQuantity($qty);
190
+ $action->setAegroup($this->cookie->get('aegroup'));
191
+ $action->setAeguestid($this->cookie->get('aeguest'));
192
+ $action->setAememberid($this->helper->getMemberId());
193
+ $action->setDateAdd(date("Y-m-d H:i:s"));
194
+ $action->setIdProduct($observer->getData('quote_item')->getData('product_id'));
195
+ $action->setIdProductAttribute(serialize($attribute_ids));
196
+ $action->setIp($this->helper->getIp());
197
+ $action->setLanguage($this->helper->getLang());
198
+
199
+ if (!Mage::getModel('affinityitems/sync_cartActionSync')->syncCartFromObserver($action)) {
200
+ $cart_repo_model->cartrepo(
201
+ $action->getIdCart(), $action->getIdProduct(), $action->getQuantity(), $action->getAction(), $attribute_ids, $action->getAeguestid(), $action->getAegroup(), $action->getIp(), $action->getAememberid(), $action->getLanguage());
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ public function saveProduct($observer) {
208
+ if ($this->helper->isModuleEnabledAndRegistered()) {
209
+ if (!$observer->getData('data_object')->getData('observer')) {
210
+ if (!Mage::getModel('affinityitems/sync_productSync')->syncProductFromObserver($observer->getData('data_object')->getData('entity_id')))
211
+ $observer->getData('data_object')->setData('ae_sync', 0);
212
+ }
213
+ }
214
+ }
215
+
216
+ public function saveCategory($observer) {
217
+ if ($this->helper->isModuleEnabledAndRegistered()) {
218
+ if (!$observer->getData('data_object')->getData('observer')) {
219
+ if (!Mage::getModel('affinityitems/sync_categorySync')->syncCategoryFromObserver($observer->getData('data_object')->getData('entity_id')))
220
+ $observer->getData('data_object')->setData('ae_sync', 0);
221
+ }
222
+ }
223
+ }
224
+
225
+ public function saveOrder($observer) {
226
+ if ($this->helper->isModuleEnabledAndRegistered()) {
227
+ if (!$observer->getData('data_object')->getData('observer')) {
228
+ if (!Mage::getModel('affinityitems/sync_orderSync')->syncOrderFromObserver($observer->getData('data_object')->getData('entity_id'))) {
229
+ $observer->getData('data_object')->setData('ae_sync', 0);
230
+ if (!$observer->getData('data_object')->getData('ae_group')) {
231
+ $aeg = (Mage::getModel('core/cookie')->get('aegroup')) ? Mage::getModel('core/cookie')->get('aegroup') : NULL;
232
+ $observer->getData('data_object')->setData('ae_group', $aeg);
233
+ }
234
+ }
235
+ }
236
+ }
237
+ }
238
+
239
+ public function checkCookie($observer) {
240
+ if ($this->helper->isModuleEnabledAndRegistered()) {
241
+ if (!$this->helper->isAdmin()) {
242
+ if (!$this->cookie->get('aeguest') || $force = Mage::app()->getRequest()->getParam('aeabtesting')) {
243
+ $this->helper->generateGuest();
244
+ $ab = new AffinityEngine_AffinityItems_Model_Sdk_Abtesting_Abtesting();
245
+ if (isset($force)) {
246
+ $ab->forceGroup($force);
247
+ }
248
+ $ab->init();
249
+ }
250
+ }
251
+ }
252
+ }
253
+
254
+ public function login($params) {
255
+ if ($this->helper->isModuleEnabledAndRegistered()) {
256
+ if (!$this->helper->isAdmin()) {
257
+ if ($this->cookie->get('aeguest') && $customer = Mage::getSingleton('customer/session')->isLoggedIn()) {
258
+ try {
259
+ $mid = Mage::getSingleton('customer/session')->getCustomer()->getId();
260
+ $gid = $this->cookie->get('aeguest');
261
+ $data = new stdClass();
262
+ $data->guestId = (String) $gid;
263
+ $data->memberId = (String) $mid;
264
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_LinkGuestToMemberRequest($data);
265
+ if ($request->post()) {
266
+ $this->logger->log("[INFO]", "Link guest to member : " . $gid . " - " . $mid);
267
+ }
268
+ } catch (Exception $e) {
269
+ $this->logger->log('[ERROR]', $e->getMessage());
270
+ }
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ public function updateHosts(Varien_Event_Observer $observer) {
277
+ if ($this->helper->isModuleEnabledAndRegistered()) {
278
+ if ($this->detectEnviromentChange())
279
+ return false;
280
+ $ips = unserialize(Mage::getStoreConfig('affinityitems/advanced/server_ip'));
281
+ if (isset($ips['server_ip'])) {
282
+ $data = $ips['server_ip'];
283
+ if (count($data) > 1) {
284
+ $data[0] = "127.0.0.1";
285
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_HostRequest($data);
286
+ if ($request->post()) {
287
+ $this->logger->log("[INFO]", "Updated hosts: " . implode(', ', $data));
288
+ }
289
+ }
290
+ }
291
+ }
292
+ }
293
+
294
+ public function detectEnviromentChange() {
295
+ if (Mage::getStoreConfig('affinityitems/general/dev_prod') <> Mage::getStoreConfig('affinityitems/general/dev_prod_rel')) {
296
+ $ae_config = new Mage_Core_Model_Config();
297
+ $ae_config->saveConfig('affinityitems/general/dev_prod_rel', Mage::getStoreConfig('affinityitems/general/dev_prod'), 'default', 0);
298
+ Mage::helper('affinityitems/aeadapter')->authentication('', '', '', '');
299
+ $this->logger->log('[INFO]', 'Enviroment changed, login info removed, need to login again to AffinityEngine server');
300
+ Mage::getSingleton('adminhtml/session')->addSuccess('Enviroment changed, login info removed, need to login again to AffinityEngine server');
301
+ return true;
302
+ }
303
+ return false;
304
+ }
305
+
306
+ public function deleteCategory($observer) {
307
+ if ($this->helper->isModuleEnabledAndRegistered()) {
308
+ $cid = $observer->getData('category')->getData('entity_id');
309
+ $category = new stdClass();
310
+ $category->categoryId = $cid;
311
+
312
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_CategoryRequest($category);
313
+ $response = $request->delete();
314
+ if ($response) {
315
+ $this->logger->log('[INFO]', 'Delete category: (ID:' . $cid . ') [' . time() . ']');
316
+ } else {
317
+ $this->logger->log('[ERROR]', 'Delete category: (ID:' . $cid . ') [' . time() . ']');
318
+ Mage::getModel("affinityitems/catProdRepo")->addToCatProdRepo($cid, 'category');
319
+ }
320
+ }
321
+ }
322
+
323
+ public function deleteProduct($observer) {
324
+ if ($this->helper->isModuleEnabledAndRegistered()) {
325
+ $pid = $observer->getData('data_object')->getData('entity_id');
326
+ if ($observer->getData('data_object')->getData('type_id') == 'simple' && $observer->getData('data_object')->getData('visibility') == 1)
327
+ return;
328
+ $aeproduct = new stdClass();
329
+ $aeproduct->productId = $pid;
330
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_ProductRequest($aeproduct);
331
+ $response = $request->delete();
332
+
333
+ if ($response) {
334
+ $this->logger->log('[INFO]', 'Delete product: (ID:' . $pid . ') [' . time() . ']');
335
+ } else {
336
+ $this->logger->log('[ERROR]', 'Delete product: (ID:' . $pid . ') [' . time() . ']');
337
+ Mage::getModel("affinityitems/catProdRepo")->addToCatProdRepo($pid, 'product');
338
+ }
339
+ }
340
+ }
341
+
342
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/Action.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Resource_Action extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ protected function _construct()
6
+ {
7
+ $this->_init('affinityitems/ae_guest_action_repository', 'id');
8
+ }
9
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/Action/Collection.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class AffinityEngine_AffinityItems_Model_Resource_Action_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ $this->_init('affinityitems/action');
7
+ }
8
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/Cart.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Resource_Cart extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ protected function _construct()
6
+ {
7
+ $this->_init('affinityitems/ae_cart_repository', 'id');
8
+ }
9
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/Cart/Collection.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class AffinityEngine_AffinityItems_Model_Resource_Cart_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ $this->_init('affinityitems/cart');
7
+ }
8
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/CatProdRepo.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Resource_CatProdRepo extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ protected function _construct()
6
+ {
7
+ $this->_init('affinityitems/ae_cat_prod_repository', 'id');
8
+ }
9
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/CatProdRepo/Collection.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class AffinityEngine_AffinityItems_Model_Resource_CatProdRepo_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ $this->_init('affinityitems/catProdRepo');
7
+ }
8
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/Log.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Resource_Log extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ protected function _construct()
6
+ {
7
+ $this->_init('affinityitems/ae_log', 'id_log');
8
+ }
9
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/Log/Collection.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class AffinityEngine_AffinityItems_Model_Resource_Log_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ $this->_init('affinityitems/log');
7
+ }
8
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/Syncrotate.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Resource_Syncrotate extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ protected function _construct()
6
+ {
7
+ $this->_init('affinityitems/ae_sync_rotate', 'id');
8
+ }
9
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Resource/Syncrotate/Collection.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class AffinityEngine_AffinityItems_Model_Resource_Syncrotate_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
3
+ {
4
+ public function _construct()
5
+ {
6
+ $this->_init('affinityitems/syncrotate');
7
+ }
8
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Abtesting/Abtesting.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * 2014 Affinity-Engine
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * DISCLAIMER
9
+ *
10
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
11
+ * versions in the future. If you wish to customize AffinityItems for your
12
+ * needs please refer to http://www.affinity-engine.fr for more information.
13
+ *
14
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
15
+ * @copyright 2014 Affinity-Engine SARL
16
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
17
+ * International Registered Trademark & Property of Affinity Engine SARL
18
+ */
19
+ class AffinityEngine_AffinityItems_Model_Sdk_Abtesting_Abtesting {
20
+
21
+ public static $types = array('A', 'B', 'Z');
22
+
23
+ public function __construct() {
24
+ $this->logger = Mage::getModel('affinityitems/log');
25
+ $this->cookie = Mage::getModel('core/cookie');
26
+ $this->helper = Mage::helper('affinityitems');
27
+ }
28
+
29
+ public function init() {
30
+ if (!$this->getGuestGroup()) {
31
+ $this->setGuestGroup();
32
+ }
33
+ }
34
+
35
+ public function getGuestGroup() {
36
+ try {
37
+ self::filter();
38
+ return $this->cookie->get('aegroup');
39
+ } catch (Exception $e) {
40
+ $this->logger->log("[ERROR]", $e->getMessage());
41
+ }
42
+ }
43
+
44
+ public function setGuestGroup() {
45
+ try {
46
+ $rnd = (0 + lcg_value() * (abs(1)));
47
+ $group = ($rnd < ($this->helper->getGeneral('guest_percentage') / 100)) ? "A" : "B";
48
+ $this->cookie->set('aegroup', $group, 630720000);
49
+ } catch (Exception $e) {
50
+ $this->logger->log("[ERROR]", $e->getMessage());
51
+ }
52
+ }
53
+
54
+ public function filter() {
55
+ try {
56
+ $unsr = unserialize($this->helper->getAdvanced('ab_blacklist_ip'));
57
+ if (in_array(Mage::helper('core/http')->getRemoteAddr(false), $unsr['ab_blacklist_ip'])) {
58
+ $this->cookie->set('aegroup', 'Z', 630720000);
59
+ }
60
+ } catch (Exception $e) {
61
+ $this->logger->log("[ERROR]", $e->getMessage());
62
+ }
63
+ }
64
+
65
+ public function forceGroup($group) {
66
+ $groups = array('A', 'B', 'Z');
67
+ if (in_array($group, $groups)) {
68
+ $this->logger->log("[INFO]", "Forcing group : " . $group);
69
+ $this->cookie->set('aegroup', $group, 630720000);
70
+ }
71
+ }
72
+
73
+ }
74
+
75
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Core/AbstractRequest.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest extends Mage_Core_Model_Abstract {
4
+
5
+ protected $path;
6
+ protected $content;
7
+ protected $curl;
8
+
9
+ public function __construct($ppath, $pcontent) {
10
+ $this->path = $ppath;
11
+ $this->content = $pcontent;
12
+ $this->curl = new AffinityEngine_AffinityItems_Model_Sdk_Core_Curl(false);
13
+ }
14
+
15
+ public function getPath() {
16
+ return $this->path;
17
+ }
18
+
19
+ public function setPath($ppath) {
20
+ $this->path = $ppath;
21
+ }
22
+
23
+ public function getContent() {
24
+ return $this->content;
25
+ }
26
+
27
+ public function setContent($pcontent) {
28
+ $this->content = $pcontent;
29
+ }
30
+
31
+ public function getCurl() {
32
+ return $this->curl;
33
+ }
34
+
35
+ public function setCurl($pcurl) {
36
+ $this->curl = $pcurl;
37
+ }
38
+
39
+ public function post() {
40
+ if ($response = $this->curl->post($this->path, $this->content)) {
41
+ return $response;
42
+ }
43
+ return false;
44
+ }
45
+
46
+ public function put() {
47
+ if ($response = $this->curl->put($this->path, $this->content)) {
48
+ return $response;
49
+ }
50
+ return false;
51
+ }
52
+
53
+ public function delete() {
54
+ if ($response = $this->curl->delete($this->path, $this->content)) {
55
+ return $response;
56
+ }
57
+ return false;
58
+ }
59
+
60
+ public function get() {
61
+ if ($response = $this->curl->get($this->path)) {
62
+ return $response;
63
+ }
64
+ return false;
65
+ }
66
+
67
+ public function enableReturnErrors() {
68
+ $this->setCurl(new AffinityEngine_AffinityItems_Model_Sdk_Core_Curl(true));
69
+ }
70
+
71
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Core/Curl.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * 2014 Affinity-Engine
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * DISCLAIMER
9
+ *
10
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
11
+ * versions in the future. If you wish to customize AffinityItems for your
12
+ * needs please refer to http://www.affinity-engine.fr for more information.
13
+ *
14
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
15
+ * @copyright 2014 Affinity-Engine SARL
16
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
17
+ * International Registered Trademark & Property of Affinity Engine SARL
18
+ */
19
+ class AffinityEngine_AffinityItems_Model_Sdk_Core_Curl {
20
+
21
+ protected $returnErrors;
22
+
23
+ public function __construct($preturnErrors) {
24
+ $this->returnErrors = $preturnErrors;
25
+ }
26
+
27
+ public function head($url, $vars = array()) {
28
+ return $this->request('HEAD', $url, $vars);
29
+ }
30
+
31
+ public function post($url, $vars = array()) {
32
+ return $this->request('POST', $url, $vars);
33
+ }
34
+
35
+ public function put($url, $vars = array()) {
36
+ return $this->request('PUT', $url, $vars);
37
+ }
38
+
39
+ public function delete($url, $vars = array()) {
40
+ return $this->request('DELETE', $url, $vars);
41
+ }
42
+
43
+ public function get($url, $vars = array()) {
44
+ if (!empty($vars)) {
45
+ $url .= (stripos($url, '?') !== false) ? '&' : '?';
46
+ $url .= (is_string($vars)) ? $vars : http_build_query($vars, '', '&');
47
+ }
48
+ return $this->request('GET', $url);
49
+ }
50
+
51
+ public function getHeaders() {
52
+ $headers = array(
53
+ "Content-type: application/json; charset=utf-8");
54
+ $security = "securityKey: " . Mage::helper('affinityitems/aeadapter')->getSecurityKey();
55
+ array_push($headers, $security);
56
+ return $headers;
57
+ }
58
+
59
+ public function request($method, $url, $vars = array()) {
60
+ $helper = Mage::helper('affinityitems/aeadapter');
61
+ if (!($url == 'login' || $url == 'register') && !$helper->getSiteId())
62
+ return false;
63
+
64
+ $curl = curl_init();
65
+ $site_id = ($url == 'login' || $url == 'register') ? '' : $helper->getSiteId();
66
+ curl_setopt($curl, CURLOPT_URL, $helper->getHost() . ':' . $helper->getPort() . '/site/' . $site_id . $url);
67
+ curl_setopt($curl, CURLOPT_COOKIESESSION, true);
68
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
69
+ curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 1000);
70
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $this->getHeaders());
71
+ curl_setopt($curl, CURLOPT_ENCODING, 'gzip');
72
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
73
+ if (Mage::registry('curl_debug')) {
74
+ curl_setopt($curl, CURLOPT_VERBOSE, true); // for shell debugging only
75
+ }
76
+
77
+ if (!empty($vars)) {
78
+ curl_setopt($curl, CURLOPT_POSTFIELDS, Mage::helper('core')->jsonEncode($vars));
79
+ }
80
+
81
+ $return = curl_exec($curl);
82
+ if (Mage::registry('curl_debug')) {
83
+ var_dump($vars);
84
+ var_dump($return); // for shell debugging only
85
+ }
86
+
87
+ curl_close($curl);
88
+
89
+ try {
90
+ if ($ret = Mage::helper('core')->jsonDecode($return)) {
91
+ if ($ret['_ok'] == "true") {
92
+ return $ret;
93
+ } else {
94
+ Mage::getModel('affinityitems/log')->log("[ERROR]", $ret->_errorCode . " : " . $ret->_errorMessage);
95
+ if ($this->returnErrors) {
96
+ return $ret;
97
+ }
98
+ }
99
+ }
100
+ } catch (Exception $e) {
101
+ Mage::getModel('affinityitems/log')->log("[ERROR]", $e->getMessage());
102
+ }
103
+ return false;
104
+ }
105
+
106
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Recommendation/Recommendation.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * 2014 Affinity-Engine
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * DISCLAIMER
9
+ *
10
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
11
+ * versions in the future. If you wish to customize AffinityItems for your
12
+ * needs please refer to http://www.affinity-engine.fr for more information.
13
+ *
14
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
15
+ * @copyright 2014 Affinity-Engine SARL
16
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
17
+ * International Registered Trademark & Property of Affinity Engine SARL
18
+ */
19
+ class AffinityEngine_AffinityItems_Model_Sdk_Recommendation_Recommendation {
20
+
21
+ public $aecontext;
22
+ public $pscontext;
23
+ public $stack;
24
+ public $render;
25
+ public $langId;
26
+ public $actionSynchronize;
27
+ public $actionRepository;
28
+
29
+ public function __construct($paecontext, $ppscontext) {
30
+ $this->aecontext = $paecontext;
31
+ $this->pscontext = $ppscontext;
32
+ $this->logger = Mage::getModel('affinityitems/log');
33
+ $this->cookie = Mage::getModel('core/cookie');
34
+ $this->helper = Mage::helper('affinityitems');
35
+ }
36
+
37
+ public function getRecommendation() {
38
+ $products = array();
39
+ $productPool = array();
40
+ $select = '';
41
+ $tax = '';
42
+
43
+
44
+ if(!$this->cookie->get('aeguest')) {
45
+ return array();
46
+ } else {
47
+ $this->aecontext->guestId = $this->cookie->get('aeguest');
48
+ }
49
+
50
+ if ($group = $this->cookie->get('aegroup')) {
51
+ $this->aecontext->group = $group;
52
+ }
53
+
54
+ if($this->helper->getMemberId() != '') {
55
+ $this->aecontext->memberId = $this->helper->getMemberId();
56
+ }
57
+
58
+ $this->aecontext->ip = $this->helper->getIp();
59
+
60
+ $this->aecontext->language = $this->helper->getLang();
61
+
62
+ //sync action of guest id
63
+
64
+ $this->aecontext->person = $this->aecontext->guestId;
65
+
66
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_RecommendationRequest($this->aecontext);
67
+ $products = $request->post();
68
+
69
+ return $products;
70
+ }
71
+
72
+ }
73
+
74
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/ActionRequest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_ActionRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($pcontent) {
21
+ if(is_array($pcontent)) {
22
+ parent::__construct('/actions', array("actions" => $pcontent));
23
+ }
24
+ else if(is_object($pcontent)) {
25
+ parent::__construct('/action', $pcontent);
26
+ }
27
+ }
28
+
29
+ }
30
+
31
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/CategoryRequest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_CategoryRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($pcontent) {
21
+ if(is_array($pcontent)) {
22
+ parent::__construct('/categories', array("categories" => $pcontent));
23
+ }
24
+ else if(is_object($pcontent)) {
25
+ parent::__construct('/category/' . $pcontent->categoryId, $pcontent);
26
+ }
27
+ }
28
+
29
+ }
30
+
31
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/CustomerRequest.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_CustomerRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($content) {
21
+ if(is_object($content)) {
22
+ parent::__construct('', $content);
23
+ $this->enableReturnErrors();
24
+ }
25
+ }
26
+
27
+ public function registerCustomer() {
28
+ $this->setPath('register');
29
+ return $this->post();
30
+ }
31
+
32
+ public function loginCustomer() {
33
+
34
+ $this->setPath('login');
35
+ return $this->post();
36
+ }
37
+
38
+ }
39
+
40
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/DisableRequest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_DisableRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($pcontent) {
21
+ if(is_bool($pcontent)) {
22
+ parent::__construct('/disable', array('disable' => $pcontent));
23
+ }
24
+ }
25
+
26
+ }
27
+
28
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/GuestRequest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_GuestRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($pcontent) {
21
+ if(is_array($pcontent)) {
22
+ parent::__construct('/guests', array("guests" => $pcontent));
23
+ }
24
+ else if(is_object($pcontent)) {
25
+ parent::__construct('/guest/' . $pcontent->guestId, $pcontent);
26
+ }
27
+ }
28
+
29
+ }
30
+
31
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/HostRequest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_HostRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($content) {
21
+ if(is_array($content)) {
22
+ parent::__construct('/host', $content);
23
+ }
24
+ }
25
+
26
+ }
27
+
28
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/LinkGuestToMemberRequest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_LinkGuestToMemberRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($pcontent) {
21
+ if(is_object($pcontent)) {
22
+ parent::__construct('/linkGuestToMember', $pcontent);
23
+ }
24
+ }
25
+
26
+ }
27
+
28
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/MemberRequest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+
19
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_MemberRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
20
+
21
+ public function __construct($pcontent) {
22
+ if(is_array($pcontent)) {
23
+ parent::__construct('/members', array("members" => $pcontent));
24
+ }
25
+ else if(is_object($pcontent)) {
26
+ parent::__construct('/member/' . $pcontent->memberId, $pcontent);
27
+ }
28
+ }
29
+
30
+ }
31
+
32
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/NotificationRequest.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_NotificationRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($pcontent) {
21
+ parent::__construct('/notice', array('notices' => $pcontent));
22
+ }
23
+
24
+ }
25
+
26
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/OrderRequest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+
19
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_OrderRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
20
+
21
+ public function __construct($pcontent) {
22
+ if(is_array($pcontent)) {
23
+ parent::__construct('/orders', array("orders" => $pcontent));
24
+ }
25
+ else if(is_object($pcontent)) {
26
+ parent::__construct('/order/' . $pcontent->orderId, $pcontent);
27
+ }
28
+ }
29
+
30
+ }
31
+
32
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/ProductRequest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_ProductRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($pcontent) {
21
+ if(is_array($pcontent)) {
22
+ parent::__construct('/products', array("products" => $pcontent));
23
+ }
24
+ else if(is_object($pcontent)) {
25
+ parent::__construct('/product/' . $pcontent->productId, $pcontent);
26
+ }
27
+ }
28
+
29
+ }
30
+
31
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/RecommendationRequest.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_RecommendationRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($content) {
21
+ if(is_object($content)) {
22
+ if ($content->person) {
23
+ parent::__construct('/recommendation', $content);
24
+ }
25
+ }
26
+ }
27
+
28
+ }
29
+
30
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/ResynchronizeRequest.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+
19
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_ResynchronizeRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
20
+
21
+ public function __construct($pcontent) {
22
+ parent::__construct('/resynchro', $pcontent);
23
+ }
24
+
25
+ }
26
+
27
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sdk/Request/SiteRequest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2014 Affinity-Engine
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * DISCLAIMER
8
+ *
9
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
10
+ * versions in the future. If you wish to customize AffinityItems for your
11
+ * needs please refer to http://www.affinity-engine.fr for more information.
12
+ *
13
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
14
+ * @copyright 2014 Affinity-Engine SARL
15
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
16
+ * International Registered Trademark & Property of Affinity Engine SARL
17
+ */
18
+ class AffinityEngine_AffinityItems_Model_Sdk_Request_SiteRequest extends AffinityEngine_AffinityItems_Model_Sdk_Core_AbstractRequest {
19
+
20
+ public function __construct($content) {
21
+ if(is_array($content)) {
22
+ parent::__construct('/retrieveData', $content);
23
+ }
24
+ }
25
+
26
+ }
27
+
28
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Source/Enviroment.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Source_Enviroment
4
+ {
5
+ public function toOptionArray()
6
+ {
7
+ return array(
8
+ array('value'=>0, 'label'=>Mage::helper('affinityitems')->__('Test')),
9
+ array('value'=>1, 'label'=>Mage::helper('affinityitems')->__('Production'))
10
+ );
11
+ }
12
+
13
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Source/Imagesize.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Source_Imagesize
4
+ {
5
+ public function toOptionArray()
6
+ {
7
+ return array(
8
+ array('value'=>0, 'label'=>Mage::helper('affinityitems')->__('Default')),
9
+ array('value'=>1, 'label'=>Mage::helper('affinityitems')->__('Large')),
10
+ array('value'=>2, 'label'=>Mage::helper('affinityitems')->__('Medium')),
11
+ array('value'=>3, 'label'=>Mage::helper('affinityitems')->__('Small')),
12
+ );
13
+ }
14
+
15
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Source/Loglevel.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Source_Loglevel
4
+ {
5
+ public function toOptionArray()
6
+ {
7
+ return array(
8
+ array('value'=>0, 'label'=>Mage::helper('affinityitems')->__('Off')),
9
+ array('value'=>1, 'label'=>Mage::helper('affinityitems')->__('[INFO]')),
10
+ array('value'=>2, 'label'=>Mage::helper('affinityitems')->__('[ERROR]')),
11
+ array('value'=>3, 'label'=>Mage::helper('affinityitems')->__('[INFO] & [ERROR]')),
12
+ );
13
+ }
14
+
15
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Source/Recoconfig.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Source_Recoconfig
4
+ {
5
+ public static function getRecoIds()
6
+ {
7
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_SiteRequest(array());
8
+ $data = $request->get();
9
+ return isset($data['recoIds']) ? json_decode($data['recoIds']) : array();
10
+ }
11
+
12
+ public function home()
13
+ {
14
+ $recoIds = array();
15
+ $tmp = self::getRecoIds();
16
+ foreach ($tmp as $recoId) {
17
+ $recoIds[$recoId] = $recoId;
18
+ }
19
+ return $recoIds;
20
+ }
21
+
22
+ public function right()
23
+ {
24
+ $recoIds = array();
25
+ $tmp = self::getRecoIds();
26
+ foreach ($tmp as $recoId) {
27
+ $recoIds[$recoId] = $recoId;
28
+ }
29
+ return $recoIds;
30
+ }
31
+
32
+ public function left()
33
+ {
34
+ $recoIds = array();
35
+ $tmp = self::getRecoIds();
36
+ foreach ($tmp as $recoId) {
37
+ $recoIds[$recoId] = $recoId;
38
+ }
39
+ return $recoIds;
40
+ }
41
+
42
+ public function product()
43
+ {
44
+ $recoIds = array();
45
+ $tmp = self::getRecoIds();
46
+ foreach ($tmp as $recoId) {
47
+ $recoIds[$recoId] = $recoId;
48
+ }
49
+ return $recoIds;
50
+ }
51
+
52
+ public function cart()
53
+ {
54
+ $recoIds = array();
55
+ $tmp = self::getRecoIds();
56
+ foreach ($tmp as $recoId) {
57
+ $recoIds[$recoId] = $recoId;
58
+ }
59
+ return $recoIds;
60
+ }
61
+
62
+ public function category()
63
+ {
64
+ $recoIds = array();
65
+ $tmp = self::getRecoIds();
66
+ foreach ($tmp as $recoId) {
67
+ $recoIds[$recoId] = $recoId;
68
+ }
69
+ return $recoIds;
70
+ }
71
+
72
+ public function search()
73
+ {
74
+ $recoIds = array();
75
+ $tmp = self::getRecoIds();
76
+ foreach ($tmp as $recoId) {
77
+ $recoIds[$recoId] = $recoId;
78
+ }
79
+ return $recoIds;
80
+ }
81
+
82
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sync/ActionSync.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Sync_ActionSync extends AffinityEngine_AffinityItems_Model_Sync_Sync {
4
+
5
+ public function syncActions($sync_count = 300) {
6
+ $countActionsForSync = $this->getActionsForSync()->count();
7
+ $countPage = ceil($countActionsForSync / $sync_count);
8
+ for ($cPage = 0; $cPage <= ($countPage - 1); $cPage++) {
9
+ $actions = $this->getActionsForSync()->setPageSize($sync_count);
10
+ $aeactionsList = array();
11
+ foreach ($actions as $action) {
12
+ $aeaction = new stdClass();
13
+
14
+ if($action->getProductId() != 0)
15
+ $aeaction->productId = $action->getProductId();
16
+ if($action->getCategoryId() != 0)
17
+ $aeaction->categoryId = $action->getCategoryId();
18
+
19
+ $aeaction->ip = $action->getIp();
20
+ $aeaction->context = $action->getAeAction();
21
+ $aeaction->guestId = $action->getAeGuest();
22
+
23
+ if($action->getAeMember() != '') {
24
+ $aeaction->memberId = $action->getAeMember();
25
+ }
26
+
27
+ $aeaction->language = $action->getLanguage();
28
+
29
+ $aeaction->group = $action->getAeGroup();
30
+ if ($action->getRecType())
31
+ $aeaction->recoType = strtoupper($action->getRecType());
32
+ array_push($aeactionsList, $aeaction);
33
+ }
34
+
35
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_ActionRequest($aeactionsList);
36
+ if ($request->post()) {
37
+ foreach ($actions as $action) {
38
+ try {
39
+ Mage::getModel('affinityitems/action')->setId($action->getId())->delete();
40
+ $this->logger->log('[INFO]', 'Synchronize action : ' . $action->getAction() . '[' . time() . ']');
41
+ } catch (Exception $e) {
42
+ $this->logger->log('[ERROR]', $e->getMessage());
43
+ $this->logger->log('[ERROR]', 'Synchronize action : ' . $action->getAction() . '[' . time() . ']');
44
+ }
45
+ }
46
+ } else {
47
+ $this->logger->log('[ERROR]', 'Synchronize action failed');
48
+ }
49
+ }
50
+ }
51
+
52
+ public function syncActionFromObserver($action, $inRepo = false) {
53
+ $aeaction = new stdClass();
54
+
55
+ if(!is_null($action->productId))
56
+ $aeaction->productId = $action->getProductId();
57
+ if(!is_null($action->categoryId))
58
+ $aeaction->categoryId = $action->getCategoryId();
59
+
60
+ $aeaction->context = $action->getAeAction();
61
+ $aeaction->guestId = $action->getAeGuest();
62
+
63
+ if($action->getAeMember() != '') {
64
+ $aeaction->memberId = $action->getAeMember();
65
+ }
66
+
67
+ $aeaction->language = $action->getLanguage();
68
+ $aeaction->ip = $action->getIp();
69
+ $aeaction->group = $action->getAeGroup();
70
+ if ($action->getRecType())
71
+ $aeaction->recoType = strtoupper($action->getRecType());
72
+
73
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_ActionRequest($aeaction);
74
+ if ($request->post()) {
75
+ if ($inRepo) {
76
+ try {
77
+ Mage::getModel('affinityitems/action')->setId($action->getId())->delete();
78
+ } catch (Exception $e) {
79
+ $this->logger->log('[ERROR]', $e->getMessage());
80
+ }
81
+ }
82
+ $this->logger->log('[INFO]', 'Synchronize action: ' . $action->getAction() . '[' . time() . ']');
83
+ return true;
84
+ } else {
85
+ $this->logger->log('[ERROR]', 'Synchronize action: ' . $action->getAction() . '[' . time() . ']');
86
+ return false;
87
+ }
88
+ return false;
89
+ }
90
+
91
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sync/CartActionSync.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Sync_CartActionSync extends AffinityEngine_AffinityItems_Model_Sync_Sync {
4
+
5
+ public function syncCartActions($sync_count = 300) {
6
+ $countCartForSync = $this->getCartForSync()->count();
7
+ $countPage = ceil($countCartForSync / $sync_count);
8
+ for ($cPage = 0; $cPage <= ($countPage - 1); $cPage++) {
9
+ $cartaction = $this->getCartForSync()->setPageSize($sync_count);
10
+ $aecartList = array();
11
+ foreach ($cartaction as $action) {
12
+ $aecart = new stdClass();
13
+ $aecart->context = $action->getAction();
14
+ $aecart->id = $action->getIdCart();
15
+ $aecart->addDate = $action->getDateAdd();
16
+ $aecart->guestId = $action->getAeguestid();
17
+
18
+ if($action->getAememberid() != '') {
19
+ $aecart->memberId = $action->getAememberid();
20
+ }
21
+
22
+ $aecart->productAttributesId = $action->getIdProduct();
23
+ $aecart->ip = $action->getIp();
24
+ $aecart->language = $action->getLanguage();
25
+
26
+ $orderLine = new stdClass();
27
+ $orderLine->productId = $action->getIdProduct();
28
+ $orderLine->attributeIds = unserialize($action->getIdProductAttribute());
29
+ $orderLine->quantity = (int) $action->getQuantity();
30
+
31
+ $aecart->orderLine = $orderLine;
32
+ $aecart->group = $action->getAegroup();
33
+ array_push($aecartList, $aecart);
34
+ }
35
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_ActionRequest($aecartList);
36
+ if ($request->post()) {
37
+ foreach ($cartaction as $action) {
38
+ try {
39
+ Mage::getModel('affinityitems/cart')->setId($action->getId())->delete();
40
+ $this->logger->log('[INFO]', 'Synchronize action: ' . $action->getAction() . ' (Product ID:' . $action->getIdProduct() . ') [' . time() . ']');
41
+ } catch (Exception $e) {
42
+ $this->logger->log('[ERROR]', $e->getMessage());
43
+ $this->logger->log('[ERROR]', 'Synchronize action: ' . $action->getAction() . ' (Product ID: ' . $action->getIdProduct() . ') [' . time() . ']');
44
+ }
45
+ }
46
+ } else {
47
+ $ids = array();
48
+ foreach ($aecartList as $action) {
49
+ array_push($ids, $action->id);
50
+ }
51
+ $this->logger->log('[ERROR]', 'Synchronize of actions failed: (IDs: ' . implode(",", $ids) . ') [' . time() . ']');
52
+ }
53
+ }
54
+ }
55
+
56
+ public function syncCartFromObserver($action, $inRepo = false) {
57
+
58
+ $aecart = new stdClass();
59
+ $aecart->context = $action->getAction();
60
+ $aecart->id = $action->getIdCart();
61
+ $aecart->addDate = $action->getDateAdd();
62
+ $aecart->guestId = $action->getAeguestid();
63
+
64
+ if($action->getAememberid() != '') {
65
+ $aecart->memberId = $action->getAememberid();
66
+ }
67
+
68
+ $aecart->productAttributesId = $action->getIdProduct();
69
+ $aecart->ip = $action->getIp();
70
+ $aecart->language = $action->getLanguage();
71
+
72
+ $orderLine = new stdClass();
73
+ $orderLine->productId = $action->getIdProduct();
74
+ $orderLine->attributeIds = unserialize($action->getIdProductAttribute());
75
+ $orderLine->quantity = (int) $action->getQuantity();
76
+
77
+ $aecart->orderLine = $orderLine;
78
+ $aecart->group = $action->getAegroup();
79
+
80
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_ActionRequest($aecart);
81
+ if ($request->post()) {
82
+ if ($inRepo) {
83
+ try {
84
+ Mage::getModel('affinityitems/cart')->setId($action->getId())->delete();
85
+ } catch (Exception $e) {
86
+ $this->logger->log('[ERROR]', $e->getMessage());
87
+ }
88
+ }
89
+ $this->logger->log('[INFO]', 'Synchronize action: ' . $action->getAction() . ' (Product ID:' . $action->getIdProduct() . ') [' . time() . ']');
90
+ return true;
91
+ } else {
92
+ $this->logger->log('[ERROR]', 'Synchronize action: ' . $action->getAction() . ' (Product ID: ' . $action->getIdProduct() . ') [' . time() . ']');
93
+ return false;
94
+ }
95
+ return false;
96
+ }
97
+
98
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sync/CategorySync.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Sync_CategorySync extends AffinityEngine_AffinityItems_Model_Sync_Sync {
4
+
5
+ public function syncCategories($sync_count = 300, $new = true) {
6
+ $countCategory = $this->getCategoriesForSync()->count();
7
+ $countPage = ceil($countCategory / $sync_count);
8
+ for ($cPage = 0; $cPage <= ($countPage - 1); $cPage++) {
9
+ $categories = $this->getCategoriesForSync()->setPageSize($sync_count);
10
+
11
+ if ($new) {
12
+ $categories->addAttributeToFilter(
13
+ array(
14
+ array('attribute' => 'ae_sync_date', 'null' => true),
15
+ array('attribute' => 'ae_sync_date', 'eq' => 0),
16
+ ), '', 'left');
17
+ } else {
18
+ $categories->addAttributeToFilter(
19
+ array(
20
+ array('attribute' => 'ae_sync_date', 'null' => false),
21
+ array('attribute' => 'ae_sync_date', 'neq' => 0),
22
+ ), '', 'left');
23
+ }
24
+
25
+ $categoryList = array();
26
+ foreach ($categories as $cat) {
27
+ $category = new stdClass();
28
+ $category->categoryId = (int) $cat->getId();
29
+ $category->parentId = (int) $cat->getParentId();
30
+ $category->updateDate = $cat->getUpdatedAt();
31
+ $category->localizations = $this->getFeatureList($cat);
32
+ array_push($categoryList, $category);
33
+ }
34
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_CategoryRequest($categoryList);
35
+ if ($new && count($categoryList)) {
36
+ $response = $request->post();
37
+ } elseif (!$new && count($categoryList)) {
38
+ $response = $request->put();
39
+ } else {
40
+ return;
41
+ }
42
+
43
+ if ($response) {
44
+ foreach ($categoryList as $category) {
45
+ $cat = Mage::getModel('catalog/category')->setStoreId(0)->load($category->categoryId);
46
+ try {
47
+ $cat->setData('ae_sync', 1)->setData('observer', true)->setData('ae_sync_date', date("Y-m-d H:i:s"))->save();
48
+ $this->logger->log('[INFO]', 'Synchronize category: ' . $cat->getName() . ' (ID:' . $cat->getId() . ') [' . time() . ']');
49
+ } catch (Exception $e) {
50
+ $this->logger->log('[ERROR]', $e->getMessage());
51
+ $this->logger->log('[ERROR]', 'Synchronize category: ' . $cat->getName() . ' (ID:' . $cat->getId() . ') [' . time() . ']');
52
+ }
53
+ }
54
+ } else {
55
+ $ids = array();
56
+ foreach ($categoryList as $category) {
57
+ array_push($ids, $category->categoryId);
58
+ }
59
+ $this->logger->log('[ERROR]', 'Synchronize of categories failed: (IDs: ' . implode(",", $ids) . ') [' . time() . ']');
60
+ }
61
+ }
62
+ }
63
+
64
+ public function syncDeletedCategories($sync_count = 300) {
65
+ $countCategory = $this->getDeletedCategoriesForSync()->count();
66
+ $countPage = ceil($countCategory / $sync_count);
67
+ for ($cPage = 0; $cPage <= ($countPage - 1); $cPage++) {
68
+ $categories = $this->getDeletedCategoriesForSync()->setPageSize($sync_count);
69
+ $categoryList = array();
70
+ foreach ($categories as $cat) {
71
+ $category = new stdClass();
72
+ $category->categoryId = $cat->getObjId();
73
+ array_push($categoryList, $category);
74
+ }
75
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_CategoryRequest($categoryList);
76
+ $response = $request->delete();
77
+
78
+ if ($response) {
79
+ foreach ($categoryList as $category) {
80
+ try {
81
+ Mage::getModel('affinityitems/catProdRepo')->load($category->categoryId, 'obj_id')->delete();
82
+ $this->logger->log('[INFO]', 'Delete category: (ID:' . $category->categoryId . ') [' . time() . ']');
83
+ } catch (Exception $e) {
84
+ $this->logger->log('[ERROR]', $e->getMessage());
85
+ $this->logger->log('[ERROR]', 'Delete category: (ID:' . $category->categoryId . ') [' . time() . ']');
86
+ }
87
+ }
88
+ } else {
89
+ $ids = array();
90
+ foreach ($categoryList as $category) {
91
+ array_push($ids, $category->categoryId);
92
+ }
93
+ $this->logger->log('[ERROR]', 'Delete of categories failed: (IDs: ' . implode(",", $ids) . ') [' . time() . ']');
94
+ }
95
+ }
96
+ }
97
+
98
+ public function syncCategoryFromObserver($cat_id = false) {
99
+ if (!$cat_id)
100
+ return false;
101
+ $cat = Mage::getModel('catalog/category')->setStoreId(0)->load($cat_id);
102
+ $is_new = (bool) $cat->getAeSyncDate();
103
+ $category = new stdClass();
104
+ $category->categoryId = (int) $cat->getId();
105
+ $category->parentId = (int) $cat->getParentId();
106
+ $category->updateDate = $cat->getUpdatedAt();
107
+ $category->localizations = $this->getFeatureList($cat);
108
+
109
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_CategoryRequest($category);
110
+ if (!$is_new) {
111
+ $response = $request->post();
112
+ } else {
113
+ $response = $request->put();
114
+ }
115
+
116
+ if ($response) {
117
+ $cat = Mage::getModel('catalog/category')->setStoreId(0)->load($category->categoryId);
118
+ try {
119
+ $cat->setData('ae_sync', 1)->setData('observer', true)->setData('ae_sync_date', date("Y-m-d H:i:s"))->save();
120
+ $this->logger->log('[INFO]', 'Synchronize category: ' . $cat->getName() . ' (ID:' . $cat->getId() . ') [' . time() . ']');
121
+ return true;
122
+ } catch (Exception $e) {
123
+ $this->logger->log('[ERROR]', $e->getMessage());
124
+ $this->logger->log('[ERROR]', 'Synchronize category: ' . $cat->getName() . ' (ID:' . $cat->getId() . ') [' . time() . ']');
125
+ }
126
+ } else {
127
+ $this->logger->log('[ERROR]', 'Synchronize category: ' . $cat->getName() . ' (ID:' . $cat->getId() . ') [' . time() . ']');
128
+ }
129
+ return false;
130
+ }
131
+
132
+ public function getFeatureList($cat) {
133
+ $featureList = array();
134
+ foreach (parent::getAllStores() as $store) {
135
+ $cat = Mage::getModel('catalog/category')->setStoreId($store->getStoreId())->load($cat->getId());
136
+ $locale = new Zend_Locale(strtolower(Mage::getStoreConfig('general/locale/code', $store->getStoreId())));
137
+ array_push($featureList, array(
138
+ "language" => strtolower($locale->getLanguage()),
139
+ "name" => $cat->getName(),
140
+ "description" => $cat->getDescription()
141
+ ));
142
+ }
143
+ return $featureList;
144
+ }
145
+
146
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sync/MemberSync.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Sync_MemberSync extends AffinityEngine_AffinityItems_Model_Sync_Sync {
4
+
5
+ public function syncMember($sync_count = 300, $new = true) {
6
+ $countMember = $this->getMembersForSync()->count();
7
+ $countPage = ceil($countMember / $sync_count);
8
+ for ($cPage = 0; $cPage <= ($countPage - 1); $cPage++) {
9
+ $members = $this->getMembersForSync()->setPageSize($sync_count);
10
+ $memberList = array();
11
+ foreach ($members as $member) {
12
+ $aemember = new stdClass();
13
+ $aemember->memberId = $member->getId();
14
+ $aemember->firstname = $member->getFirstname();
15
+ $aemember->lastname = $member->getLastname();
16
+ $aemember->email = $member->getEmail();
17
+ $aemember->birthday = '';
18
+ array_push($memberList, $aemember);
19
+ }
20
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_MemberRequest($memberList);
21
+ if ($request->post()) {
22
+ foreach ($memberList as $member) {
23
+ $memb = Mage::getModel('customer/customer')->setStoreId(0)->load($member->memberId);
24
+ $memb->setData('ae_sync', 1)->save();
25
+ }
26
+ } else {
27
+ echo "bad connection";
28
+ }
29
+ }
30
+ }
31
+
32
+ }
33
+
34
+ ?>
app/code/local/AffinityEngine/AffinityItems/Model/Sync/OrderSync.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Sync_OrderSync extends AffinityEngine_AffinityItems_Model_Sync_Sync {
4
+
5
+ public function syncOrders($sync_count = 300) {
6
+
7
+ $countOrdersForSync = $this->getOrdersForSync()->count();
8
+ $countPage = ceil($countOrdersForSync / $sync_count);
9
+ for ($cPage = 0; $cPage <= ($countPage - 1); $cPage++) {
10
+ $orders = $this->getOrdersForSync()->setPageSize($sync_count);
11
+ $ordersList = array();
12
+
13
+ foreach ($orders as $order) {
14
+ $orderLines = $this->getOrderLines($order);
15
+ $aeorder = new stdClass();
16
+ $aeorder->orderId = $order->getEntityId();
17
+ $aeorder->addDate = $order->getCreatedAt();
18
+ $aeorder->currency = $order->getOrderCurrencyCode();
19
+ $aeorder->statusMessage = $order->getState();
20
+ $aeorder->paymentMode = $order->getPayment()->getMethodInstance()->getTitle();
21
+ $aeorder->updateDate = $order->getUpdatedAt();
22
+ $aeorder->memberId = ($order->getCustomerId()) ? $order->getCustomerId() : 0;
23
+ $aeorder->amount = $order->getBaseSubtotal();
24
+ $aeorder->group = ($order->getAeGroup()) ? $order->getAeGroup() : NULL;
25
+ $aeorder->ip = $order->getRemoteIp();
26
+ $aeorder->orderLines = $orderLines;
27
+ array_push($ordersList, $aeorder);
28
+ }
29
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_OrderRequest($ordersList);
30
+ if ($request->post()) {
31
+ foreach ($orders as $order) {
32
+ try {
33
+ $aeg = ($order->getAeGroup()) ? $order->getAeGroup() : NULL;
34
+ $order->setData('ae_sync', 1)->setData('observer', true)->setData('ae_group', $aeg)->save();
35
+ $this->logger->log('[INFO]', 'Synchronize order: ' . $order->getIncrimentId() . ' (ID:' . $order->getEntityId() . ') [' . time() . ']');
36
+ } catch (Exception $e) {
37
+ $this->logger->log('[ERROR]', $e->getMessage());
38
+ $this->logger->log('[ERROR]', 'Synchronize order: ' . $order->getIncrimentId() . ' (ID: ' . $order->getEntityId() . ') [' . time() . ']');
39
+ }
40
+ }
41
+ } else {
42
+ $ids = array();
43
+ foreach ($ordersList as $order) {
44
+ array_push($ids, $order->orderId);
45
+ }
46
+ $this->logger->log('[ERROR]', 'Synchronize of orders failed: (IDs: ' . implode(",", $ids) . ') [' . time() . ']');
47
+ }
48
+ }
49
+ }
50
+
51
+ public function syncOrderFromObserver($orderId = false) {
52
+ if (!$orderId)
53
+ return false;
54
+ $order = Mage::getModel('sales/order')->load($orderId);
55
+ $orderLines = $this->getOrderLines($order);
56
+ $aeorder = new stdClass();
57
+ $aeorder->orderId = $order->getEntityId();
58
+ $aeorder->addDate = $order->getCreatedAt();
59
+ $aeorder->currency = $order->getOrderCurrencyCode();
60
+ $aeorder->statusMessage = $order->getState();
61
+ $aeorder->paymentMode = $order->getPayment()->getMethodInstance()->getTitle();
62
+ $aeorder->updateDate = $order->getUpdatedAt();
63
+ $aeorder->memberId = ($order->getCustomerId()) ? $order->getCustomerId() : 0;
64
+ $aeorder->amount = $order->getBaseSubtotal();
65
+ $aeorder->group = (Mage::getModel('core/cookie')->get('aegroup')) ? Mage::getModel('core/cookie')->get('aegroup') : NULL;
66
+ $aeorder->ip = $order->getRemoteIp();
67
+ $aeorder->orderLines = $orderLines;
68
+
69
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_OrderRequest($aeorder);
70
+ if ($request->post()) {
71
+ try {
72
+ $order->setData('ae_sync', 1)->setData('observer', true)->setData('ae_group', $aeorder->group)->save();
73
+ $this->logger->log('[INFO]', 'Synchronize order: ' . $order->getIncrimentId() . ' (ID:' . $order->getEntityId() . ') [' . time() . ']');
74
+ return true;
75
+ } catch (Exception $e) {
76
+ $this->logger->log('[ERROR]', $e->getMessage());
77
+ $this->logger->log('[ERROR]', 'Synchronize order: ' . $order->getIncrimentId() . ' (ID: ' . $order->getEntityId() . ') [' . time() . ']');
78
+ }
79
+ } else {
80
+ $this->logger->log('[ERROR]', 'Synchronize order: ' . $order->getIncrimentId() . ' (ID: ' . $order->getEntityId() . ') [' . time() . ']');
81
+ }
82
+ return false;
83
+ }
84
+
85
+ public function getOrderLines($order) {
86
+ $orderLines = array();
87
+ $ordered_items = $order->getAllItems();
88
+ foreach ($ordered_items as $item) {
89
+ if ($item->getParentItemId()) continue;
90
+ $attributes = array();
91
+
92
+ $options = $item->getProductOptions();
93
+
94
+ if (isset($options['info_buyRequest']['super_attribute']) && $ai = $options['info_buyRequest']['super_attribute']) {
95
+ foreach ($ai as $key => $val) {
96
+ array_push($attributes, $key);
97
+ }
98
+ }
99
+
100
+ $orderLine = new stdClass();
101
+ $orderLine->productId = $item->getProductId();
102
+ $orderLine->attributeIds = $attributes;
103
+ $orderLine->quantity = (int) $item->getQtyOrdered();
104
+ array_push($orderLines, $orderLine);
105
+ }
106
+
107
+ return $orderLines;
108
+ }
109
+
110
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sync/ProductSync.php ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Sync_ProductSync extends AffinityEngine_AffinityItems_Model_Sync_Sync {
4
+
5
+ public function syncProducts($sync_count = 300, $new = true) {
6
+ $countProduct = $this->getProductsForSync()->count();
7
+ $countPage = ceil($countProduct / $sync_count);
8
+ for ($cPage = 0; $cPage <= ($countPage - 1); $cPage++) {
9
+ $products = $this->getProductsForSync()->setPageSize($sync_count);
10
+
11
+ if ($new) {
12
+ $products->addAttributeToFilter(
13
+ array(
14
+ array('attribute' => 'ae_sync_date', 'null' => true),
15
+ array('attribute' => 'ae_sync_date', 'eq' => 0),
16
+ ), '', 'left');
17
+ } else {
18
+ $products->addAttributeToFilter(
19
+ array(
20
+ array('attribute' => 'ae_sync_date', 'null' => false),
21
+ array('attribute' => 'ae_sync_date', 'neq' => 0),
22
+ ), '', 'left');
23
+ }
24
+
25
+ $aeproductList = array();
26
+ foreach ($products as $prod) {
27
+ $prod = Mage::getModel('catalog/product')->setStoreId(0)->load($prod->getId());
28
+ $aeproduct = new stdClass();
29
+ $aeproduct->productId = $prod->getId();
30
+ $aeproduct->updateDate = $prod->getUpdatedAt();
31
+ $aeproduct->categoryIds = $prod->getCategoryIds();
32
+ $aeproduct->recommendable = $this->isRecomendable($prod);
33
+ $aeproduct->localizations = $this->getLocalizations($prod);
34
+ $aeproduct->prices = $this->getProductPrices($prod);
35
+ array_push($aeproductList, $aeproduct);
36
+ }
37
+
38
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_ProductRequest($aeproductList);
39
+ if ($new && count($aeproductList)) {
40
+ $response = $request->post();
41
+ } elseif (!$new && count($aeproductList)) {
42
+ $response = $request->put();
43
+ } else {
44
+ return;
45
+ }
46
+
47
+ if ($response) {
48
+ Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); //fix for SQL error when saving product
49
+ foreach ($aeproductList as $product) {
50
+ $prod = Mage::getModel('catalog/product')->setStoreId(0)->load($product->productId);
51
+ try {
52
+ $prod->setData('ae_sync', 1)->setData('observer', true)->setData('ae_sync_date', date("Y-m-d H:i:s"))->save();
53
+ $this->logger->log('[INFO]', 'Synchronize product: ' . $prod->getName() . ' (ID:' . $prod->getId() . ') [' . time() . ']');
54
+ } catch (Exception $e) {
55
+ $this->logger->log('[ERROR]', $e->getMessage());
56
+ $this->logger->log('[ERROR]', 'Synchronize product: ' . $prod->getName() . ' (ID: ' . $prod->getId() . ') [' . time() . ']');
57
+ }
58
+ }
59
+ } else {
60
+ $ids = array();
61
+ foreach ($aeproductList as $product) {
62
+ array_push($ids, $product->productId);
63
+ }
64
+ $this->logger->log('[ERROR]', 'Synchronize of products failed: (IDs: ' . implode(",", $ids) . ') [' . time() . ']');
65
+ }
66
+ }
67
+ }
68
+
69
+ public function syncDeletedProducts($sync_count = 300) {
70
+ $countProduct = $this->getDeletedProductsForSync()->count();
71
+ $countPage = ceil($countProduct / $sync_count);
72
+ for ($cPage = 0; $cPage <= ($countPage - 1); $cPage++) {
73
+ $products = $this->getDeletedProductsForSync()->setPageSize($sync_count);
74
+
75
+ $aeproductList = array();
76
+ foreach ($products as $prod) {
77
+ $aeproduct = new stdClass();
78
+ $aeproduct->productId = $prod->getObjId();
79
+ array_push($aeproductList, $aeproduct);
80
+ }
81
+
82
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_ProductRequest($aeproductList);
83
+ $response = $request->delete();
84
+
85
+
86
+ if ($response) {
87
+ foreach ($aeproductList as $product) {
88
+ try {
89
+ Mage::getModel('affinityitems/catProdRepo')->load($product->productId, 'obj_id')->delete();
90
+ $this->logger->log('[INFO]', 'Delete product: (ID:' . $product->productId . ') [' . time() . ']');
91
+ } catch (Exception $e) {
92
+ $this->logger->log('[ERROR]', $e->getMessage());
93
+ $this->logger->log('[ERROR]', 'Delete product: (ID: ' . $product->productId . ') [' . time() . ']');
94
+ }
95
+ }
96
+ } else {
97
+ $ids = array();
98
+ foreach ($aeproductList as $product) {
99
+ array_push($ids, $product->productId);
100
+ }
101
+ $this->logger->log('[ERROR]', 'Delete of products failed: (IDs: ' . implode(",", $ids) . ') [' . time() . ']');
102
+ }
103
+ }
104
+ }
105
+
106
+ public function syncProductFromObserver($prod = false) {
107
+ if (!$prod)
108
+ return false;
109
+ $prod = Mage::getModel('catalog/product')->setStoreId(0)->load($prod);
110
+ if ($prod->getVisibility() == 1 && $prod->getTypeId() == 'simple')
111
+ return false;
112
+ $is_new = (bool) $prod->getAeSyncDate();
113
+ $aeproduct = new stdClass();
114
+ $aeproduct->productId = $prod->getId();
115
+ $aeproduct->updateDate = $prod->getUpdatedAt();
116
+ $aeproduct->categoryIds = $prod->getCategoryIds();
117
+ $aeproduct->recommendable = $this->isRecomendable($prod);
118
+ $aeproduct->localizations = $this->getLocalizations($prod);
119
+ $aeproduct->prices = $this->getProductPrices($prod);
120
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_ProductRequest($aeproduct);
121
+ if (!$is_new) {
122
+ $response = $request->post();
123
+ } else {
124
+ $response = $request->put();
125
+ }
126
+ Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); //fix for SQL error when saving product
127
+ $prod = Mage::getModel('catalog/product')->setStoreId(0)->load($aeproduct->productId);
128
+ if ($response) {
129
+ try {
130
+ $prod->setData('ae_sync', 1)->setData('observer', true)->setData('ae_sync_date', date("Y-m-d H:i:s"))->save();
131
+ $this->logger->log('[INFO]', 'Synchronize product: ' . $prod->getName() . ' (ID:' . $prod->getId() . ') [' . time() . ']');
132
+ return true;
133
+ } catch (Exception $e) {
134
+ $this->logger->log('[ERROR]', $e->getMessage());
135
+ $this->logger->log('[ERROR]', 'Synchronize product: ' . $prod->getName() . ' (ID: ' . $prod->getId() . ') [' . time() . ']');
136
+ }
137
+ } else {
138
+ $this->logger->log('[ERROR]', 'Synchronize product: ' . $prod->getName() . ' (ID: ' . $prod->getId() . ') [' . time() . ']');
139
+ try {
140
+ $prod->setData('ae_sync', 1)->setData('observer', true)->setData('ae_sync', 0)->save();
141
+ } catch (Exception $e) {
142
+
143
+ }
144
+ }
145
+ return false;
146
+ }
147
+
148
+ public function isRecomendable($prod) {
149
+ $reco = false;
150
+ $stock = Mage::getModel('cataloginventory/stock_item')->loadByProduct($prod);
151
+ // status must be enabled, visibility anything but NOT visible, product must be in stock, and must be assined to any category
152
+ if ($prod->getStatus() == 1 && $prod->getVisibility() != 1 && $stock->getIsInStock() != 0 && count($prod->getCategoryIds()) != 0)
153
+ $reco = true;
154
+ return $reco;
155
+ }
156
+
157
+ public function getLocalizations($p) {
158
+
159
+ $tagList = $this->getProductTags($p);
160
+ $attributeList = $this->getProductAttributes($p);
161
+ $featureList = $this->getProductAttributes($p);
162
+ $localizationList = array();
163
+ foreach ($this->getAllStores() as $store) {
164
+ $p = Mage::getModel('catalog/product')->setStoreId($store->getStoreId())->load($p->getId());
165
+ $plocalization = new stdClass();
166
+ $locale = new Zend_Locale(strtolower(Mage::getStoreConfig('general/locale/code', $store->getStoreId())));
167
+ $plocalization->language = $locale->getLanguage();
168
+ $plocalization->name = strip_tags(preg_replace("(\r\n|\n|\r)", '', $p->getName()));
169
+ $plocalization->shortDescription = strip_tags(preg_replace("(\r\n|\n|\r)", '', $p->getShortDescription()));
170
+ $plocalization->description = strip_tags(preg_replace("(\r\n|\n|\r)", '', $p->getDescription()));
171
+ $plocalization->tags = $tagList;
172
+ $plocalization->attributes = $attributeList;
173
+ $plocalization->features = array();
174
+
175
+ array_push($localizationList, $plocalization);
176
+ }
177
+ return $localizationList;
178
+ }
179
+
180
+ public function getProductTags($p) {
181
+ $listTag = array();
182
+ $model = Mage::getModel('tag/tag');
183
+ $tags = $model->getResourceCollection()
184
+ ->addPopularity()
185
+ ->addStatusFilter($model->getApprovedStatus())
186
+ ->addProductFilter($p->getId())
187
+ ->setFlag('relation', true)
188
+ ->setActiveFilter()
189
+ ->load();
190
+
191
+ if (isset($tags) && !empty($tags)) {
192
+ foreach ($tags as $tag) {
193
+ array_push($listTag, $tag->getName());
194
+ }
195
+ }
196
+
197
+ return $listTag;
198
+ }
199
+
200
+ public static function getProductPrices($p) {
201
+ $listPrice = array();
202
+ $iso_code = Mage::app()->getStore()->getCurrentCurrencyCode();
203
+ if ($p->getPrice()) {
204
+ $price = new stdClass();
205
+ $price->currency = $iso_code;
206
+ $price->amount = $p->getPrice();
207
+ array_push($listPrice, $price);
208
+ }
209
+ if ($p->getFinalPrice() && $p->getPrice() <> $p->getFinalPrice()) {
210
+ $price = new stdClass();
211
+ $price->currency = $iso_code;
212
+ $price->amount = $p->getFinalPrice();
213
+ array_push($listPrice, $price);
214
+ }
215
+ if ($p->getSpecialPrice() && $p->getPrice() <> $p->getSpecialPrice()) {
216
+ $price = new stdClass();
217
+ $price->currency = $iso_code;
218
+ $price->amount = $p->getSpecialPrice();
219
+ array_push($listPrice, $price);
220
+ }
221
+ return $listPrice;
222
+ }
223
+
224
+ public static function getProductAttributes($p) {
225
+ $listAttribute = array();
226
+ $attributes = $p->getAttributes();
227
+
228
+ // get all attributes of a product
229
+ foreach ($attributes as $attribute) {
230
+ if ($attribute->getIsVisibleOnFront()) {
231
+
232
+ $attributeCode = $attribute->getAttributeCode();
233
+ $label = $attribute->getFrontend()->getLabel($p);
234
+ $value = $attribute->getFrontend()->getValue($p);
235
+
236
+ $group = new stdClass();
237
+ $group->name = $label;
238
+ $group->values = array(array("characteristicId" => $attribute->getId(), "name" => $value));
239
+
240
+ array_push($listAttribute, $group);
241
+ }
242
+ }
243
+ if ($p->isConfigurable()) {
244
+ $productAttributeOptions = $p->getTypeInstance(true)->getConfigurableAttributesAsArray($p);
245
+ $attributeOptions = array();
246
+ foreach ($productAttributeOptions as $productAttribute) {
247
+ $group = new stdClass();
248
+ $group->name = $productAttribute['label'];
249
+ $tmpAttribute = array();
250
+ foreach ($productAttribute['values'] as $attribute) {
251
+ array_push($tmpAttribute, array("characteristicId" => $attribute['value_index'], "name" => $attribute['store_label']));
252
+ }
253
+ $group->values = $tmpAttribute;
254
+ array_push($listAttribute, $group);
255
+ }
256
+ }
257
+ return $listAttribute;
258
+ }
259
+
260
+ public static function getProductFeatures($p) {
261
+
262
+ $listFeature = array();
263
+ return $listFeature;
264
+ }
265
+
266
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Sync/Sync.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Sync_Sync extends Mage_Core_Model_Abstract {
4
+
5
+ public function __construct() {
6
+ $this->logger = Mage::getModel('affinityitems/log');
7
+ }
8
+
9
+ public function getProductsForSync() {
10
+ $collection = Mage::getModel('catalog/product')->getCollection();
11
+ $collection->addAttributeToSelect('entity_id')
12
+ ->addStoreFilter(0)
13
+ ->addAttributeToFilter(
14
+ array(
15
+ array('attribute' => 'ae_sync', 'null' => true),
16
+ array('attribute' => 'ae_sync', 'eq' => 0),
17
+ ), '', 'left');
18
+ $collection->addFieldToFilter('visibility', Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH);
19
+ return $collection;
20
+ }
21
+
22
+ public function getDeletedProductsForSync() {
23
+ $collection = Mage::getModel('affinityitems/catProdRepo')->getCollection()->addFieldToFilter('obj_type', 'product');
24
+ return $collection;
25
+ }
26
+
27
+ public function getCategoriesForSync() {
28
+ $collection = Mage::getModel('catalog/category')->getCollection();
29
+ $collection->addAttributeToSelect('entity_id')
30
+ ->addIsActiveFilter()
31
+ ->addAttributeToFilter(
32
+ array(
33
+ array('attribute' => 'ae_sync', 'null' => true),
34
+ array('attribute' => 'ae_sync', 'eq' => 0),
35
+ ), '', 'left');
36
+ return $collection;
37
+ }
38
+
39
+ public function getDeletedCategoriesForSync() {
40
+ $collection = Mage::getModel('affinityitems/catProdRepo')->getCollection()->addFieldToFilter('obj_type', 'category');
41
+ return $collection;
42
+ }
43
+
44
+ public function getMembersForSync() {
45
+ $collection = Mage::getModel('customer/customer')->getCollection();
46
+ $collection->addAttributeToSelect('entity_id')
47
+ ->addAttributeToFilter(
48
+ array(
49
+ array('attribute' => 'ae_sync', 'null' => true),
50
+ array('attribute' => 'ae_sync', 'eq' => 0),
51
+ ), '', 'left');
52
+
53
+ return $collection;
54
+ }
55
+
56
+ public function getOrdersForSync() {
57
+ $collection = Mage::getModel('sales/order')->getCollection();
58
+ $collection->addFieldToFilter('state', array('in' => array('new', 'pending_payment', 'processing', 'complete', 'payment_review')))
59
+ ->addFieldToFilter('ae_sync', array('in' => array(null, 0)));
60
+ return $collection;
61
+ }
62
+
63
+ public function getActionsForSync() {
64
+ $collection = Mage::getModel("affinityitems/action")->getCollection();
65
+ return $collection;
66
+ }
67
+
68
+ public function getCartForSync() {
69
+ $collection = Mage::getModel("affinityitems/cart")->getCollection();
70
+ return $collection;
71
+ }
72
+
73
+ public function getAllStores() {
74
+ return Mage::app()->getStores();
75
+ }
76
+
77
+ }
app/code/local/AffinityEngine/AffinityItems/Model/Syncrotate.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Model_Syncrotate extends Mage_Core_Model_Abstract {
4
+
5
+ protected function _construct() {
6
+ $this->_init('affinityitems/syncrotate');
7
+ }
8
+
9
+ public function upd($sync) {
10
+ $query = "UPDATE `" . Mage::getSingleton('core/resource')->getTableName('ae_sync_rotate') . "` SET `last_sync` = '" . $sync . "' WHERE `ae_sync_rotate`.`id` =0;";
11
+ $write = Mage::getSingleton('core/resource')->getConnection('affinityitems_write');
12
+ $result = $write->query($query);
13
+ }
14
+
15
+ public function updInitial($value) {
16
+ $query = "UPDATE `" . Mage::getSingleton('core/resource')->getTableName('ae_sync_rotate') . "` SET `initial_sync` = '" . $value . "' WHERE `ae_sync_rotate`.`id` =0;";
17
+ $write = Mage::getSingleton('core/resource')->getConnection('affinityitems_write');
18
+ $result = $write->query($query);
19
+ }
20
+
21
+ }
app/code/local/AffinityEngine/AffinityItems/bin/manual-run.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env php
2
+ <?php
3
+ $mageFilename = '/../../../../../Mage.php';
4
+ require_once dirname(__FILE__) . $mageFilename;
5
+ Mage::app();
6
+ Mage::register('run_from_shell', true); // for debugging only, disable if this file is used for production
7
+ Mage::register('curl_debug', false); // for CURL debugging only, disable if this file is used for production
8
+ Mage::getModel('affinityitems/cron')->sync();
9
+ Mage::unregister('run_from_shell');
10
+ Mage::unregister('curl_debug');
11
+ ?>
app/code/local/AffinityEngine/AffinityItems/controllers/ActionController.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_ActionController extends Mage_Core_Controller_Front_Action {
4
+
5
+ public function indexAction() {
6
+
7
+ $this->_redirect('/');
8
+ }
9
+
10
+ public function ajaxAction() {
11
+ if (Mage::helper('affinityitems')->isModuleEnabledAndRegistered()) {
12
+ $rec_type = $this->getRequest()->getPost('recoType');
13
+ $rec_type = isset($rec_type) ? $rec_type : '';
14
+
15
+ $action = new Varien_Object();
16
+
17
+ if(!is_null($this->getRequest()->getPost('productId'))) {
18
+ $action->setProductId($this->getRequest()->getPost('productId'));
19
+ }
20
+
21
+ if(!is_null($this->getRequest()->getPost('categoryId'))) {
22
+ $action->setCategoryId($this->getRequest()->getPost('categoryId'));
23
+ }
24
+
25
+ $action->setIp(Mage::helper('affinityitems')->getIp());
26
+ $action->setAeAction($this->getRequest()->getPost('action'));
27
+
28
+ $action->setLanguage(Mage::helper('affinityitems')->getLang());
29
+
30
+ $action->setAeGuest(($this->getRequest()->getPost('guestId') != "") ? $this->getRequest()->getPost('guestId') : Mage::getModel('core/cookie')->get('aeguest'));
31
+ $action->setAeMember(Mage::helper('affinityitems')->getMemberId());
32
+ $action->setAeGroup(($this->getRequest()->getPost('group') != "") ? $this->getRequest()->getPost('group') : Mage::getModel('core/cookie')->get('aegroup'));
33
+ $action->setRecType($this->getRequest()->getPost('recoType'));
34
+
35
+ if (!Mage::getModel('affinityitems/sync_actionSync')->syncActionFromObserver($action)) {
36
+
37
+ if(!is_null($this->getRequest()->getPost('productId'))) {
38
+ Mage::getModel("affinityitems/action")->setData(
39
+ array(
40
+ 'product_id' => $action->getProductId(),
41
+ 'category_id' => 0,
42
+ 'ae_action' => $action->getAeAction(),
43
+ 'ae_guest' => $action->getAeGuest(),
44
+ 'ae_member' => $action->getAeMember(),
45
+ 'language' => $action->getLanguage(),
46
+ 'ae_group' => $action->getAeGroup(),
47
+ 'rec_type' => $action->getRecType(),
48
+ 'ip' => $action->getIp()
49
+ )
50
+ )->save();
51
+ }
52
+
53
+ if(!is_null($this->getRequest()->getPost('categoryId'))) {
54
+ Mage::getModel("affinityitems/action")->setData(
55
+ array(
56
+ 'product_id' => 0,
57
+ 'category_id' => $action->getCategoryId(),
58
+ 'ae_action' => $action->getAeAction(),
59
+ 'ae_guest' => $action->getAeGuest(),
60
+ 'language' => $action->getLanguage(),
61
+ 'ae_member' => $action->getAeMember(),
62
+ 'ae_group' => $action->getAeGroup(),
63
+ 'rec_type' => $action->getRecType(),
64
+ 'ip' => $action->getIp()
65
+ )
66
+ )->save();
67
+ }
68
+
69
+ }
70
+ }
71
+ }
72
+
73
+ }
app/code/local/AffinityEngine/AffinityItems/controllers/Adminhtml/AffinityitemsbackendController.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Adminhtml_AffinityitemsbackendController extends Mage_Adminhtml_Controller_Action {
4
+
5
+ public function indexAction() {
6
+ $this->loadLayout();
7
+ $this->_title($this->__("AffinityItems"));
8
+ $this->_setActiveMenu('affinityengine/affinityitems');
9
+ if (Mage::helper('affinityitems/aeadapter')->isRegistered()) {
10
+ $this->_addContent($this->getLayout()->createBlock('adminhtml/template')->setTemplate('affinityitems/affinityitems_sync.phtml'));
11
+ } else {
12
+ $this->_addContent($this->getLayout()->createBlock('adminhtml/template')->setTemplate('affinityitems/affinityitems_login.phtml'));
13
+ }
14
+ $this->renderLayout();
15
+ }
16
+
17
+ }
app/code/local/AffinityEngine/AffinityItems/controllers/Adminhtml/AffinityitemslogController.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Adminhtml_AffinityitemslogController extends Mage_Adminhtml_Controller_Action {
4
+
5
+ public function indexAction() {
6
+ $this->loadLayout();
7
+ $this->_title($this->__("AffinityItems"));
8
+ $this->_setActiveMenu('affinityengine/affinityitems');
9
+ $this->renderLayout();
10
+ }
11
+
12
+ public function deleteallAction() {
13
+ $resource = Mage::getSingleton('core/resource')->getConnection('core_write');
14
+ $resource->query('TRUNCATE TABLE '.Mage::getSingleton('core/resource')->getTableName('ae_log'));
15
+ Mage::getSingleton('adminhtml/session')->addSuccess('Log cleared');
16
+ $this->_redirect('*/*/index');
17
+ }
18
+ }
app/code/local/AffinityEngine/AffinityItems/controllers/Adminhtml/AjaxController.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AffinityEngine_AffinityItems_Adminhtml_AjaxController extends Mage_Adminhtml_Controller_Action {
4
+
5
+ public function registerAction() {
6
+ if (Mage::app()->getRequest()->getParam('email') != '' && Mage::app()->getRequest()->getParam('password') != '') {
7
+ $customer = new stdClass();
8
+ $customer->siteName = Mage::app()->getStore()->getName();
9
+ $customer->email = Mage::app()->getRequest()->getParam('email');
10
+ $customer->password = Mage::app()->getRequest()->getParam('password');
11
+ $customer->domain = $_SERVER['HTTP_HOST'];
12
+ $customer->origin = 'magentoextension';
13
+ $customer->platform = 'Magento';
14
+ $customer->platformVersion = Mage::getVersion();
15
+ $customer->ip = $_SERVER['SERVER_ADDR'];
16
+
17
+ if(!is_null(Mage::app()->getRequest()->getParam('discountCode')))
18
+ $customer->code = Mage::app()->getRequest()->getParam('discountCode');
19
+ /*
20
+ $customer->firstname = Mage::app()->getRequest()->getParam('firstname');
21
+ $customer->lastname = Mage::app()->getRequest()->getParam('lastname');
22
+ $customer->activity = Mage::app()->getRequest()->getParam('activity');*/
23
+
24
+ // if (Mage::app()->getRequest()->getParam('password') == Mage::app()->getRequest()->getParam('confirmPassword')) {
25
+
26
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_CustomerRequest($customer);
27
+ $response = $request->registerCustomer();
28
+
29
+ /*} else {
30
+ $response = false;
31
+ }*/
32
+
33
+ if ($response) {
34
+ if ($response['_ok'] == 'true') {
35
+ Mage::helper('affinityitems/aeadapter')->authentication($response['email'], 'password', $response['siteId'], $response['securityKey']);
36
+ //addFirstHost();
37
+ } else {
38
+ $ret['_errorMessage'] = $response['_errorMessage'];
39
+ }
40
+ $ret['_ok'] = $response['_ok'];
41
+ } else {
42
+ $ret['_ok'] = "false";
43
+ }
44
+ } else {
45
+ $ret['_ok'] = "false";
46
+ }
47
+ $this->getResponse()->setHeader('Content-type', 'application/json')->setBody(Mage::helper('core')->jsonEncode($ret));
48
+ }
49
+
50
+ /*
51
+ public function loginAction() {
52
+ if (Mage::app()->getRequest()->getParam('email') != '' && Mage::app()->getRequest()->getParam('password') != '') {
53
+ $customer = new stdClass();
54
+ $customer->siteName = Mage::app()->getStore()->getName();
55
+ $customer->email = Mage::app()->getRequest()->getParam('email');
56
+ $customer->password = Mage::app()->getRequest()->getParam('password');
57
+ $customer->domain = $_SERVER['HTTP_HOST'];
58
+ $customer->origin = 'magentoextension';
59
+ $customer->platform = 'Magento';
60
+ $customer->platformVersion = Mage::getVersion();
61
+ $customer->ip = $_SERVER['SERVER_ADDR'];
62
+
63
+ //$customer->activity = AEAdapter::getActivity();
64
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_CustomerRequest($customer);
65
+ $response = $request->loginCustomer();
66
+ if ($response) {
67
+ if ($response['_ok'] == 'true') {
68
+ Mage::helper('affinityitems/aeadapter')->authentication($response['email'], $response['password'], $response['siteId'], $response['securityKey']);
69
+ //addFirstHost();
70
+ } else {
71
+ $ret['_errorMessage'] = $response['_errorMessage'];
72
+ }
73
+ $ret['_ok'] = $response['_ok'];
74
+ } else {
75
+ $ret['_ok'] = "false";
76
+ }
77
+ } else {
78
+ $ret['_ok'] = "false";
79
+ }
80
+ $this->getResponse()->setHeader('Content-type', 'application/json')->setBody(Mage::helper('core')->jsonEncode($ret));
81
+ }
82
+ */
83
+
84
+ }
app/code/local/AffinityEngine/AffinityItems/etc/adminhtml.xml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <admin>
6
+ <children>
7
+ <system>
8
+ <children>
9
+ <config>
10
+ <children>
11
+ <affinityitems translate="title" module="affinityitems">
12
+ <title>Affinity Items</title>
13
+ <sort_order>0</sort_order>
14
+ </affinityitems>
15
+ </children>
16
+ </config>
17
+ </children>
18
+ </system>
19
+ </children>
20
+ </admin>
21
+ </resources>
22
+ </acl>
23
+ </config>
app/code/local/AffinityEngine/AffinityItems/etc/config.xml ADDED
@@ -0,0 +1,399 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <AffinityEngine_AffinityItems>
5
+ <version>1.0.0</version>
6
+ </AffinityEngine_AffinityItems>
7
+ </modules>
8
+
9
+ <global>
10
+ <helpers>
11
+ <affinityitems>
12
+ <class>AffinityEngine_AffinityItems_Helper</class>
13
+ </affinityitems>
14
+ </helpers>
15
+ <events>
16
+ <admin_system_config_changed_section_affinityitems>
17
+ <observers>
18
+ <affinityEngine_updatehosts>
19
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
20
+ <method>updateHosts</method>
21
+ </affinityEngine_updatehosts>
22
+ </observers>
23
+ </admin_system_config_changed_section_affinityitems>
24
+
25
+ <checkout_cart_add_product_complete>
26
+ <observers>
27
+ <affinityEngine_addtocart>
28
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
29
+ <method>addToCart</method>
30
+ </affinityEngine_addtocart>
31
+ </observers>
32
+ </checkout_cart_add_product_complete>
33
+ <checkout_cart_update_items_after>
34
+ <observers>
35
+ <affinityEngine_updatecart>
36
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
37
+ <method>updateCart</method>
38
+ </affinityEngine_updatecart>
39
+ </observers>
40
+ </checkout_cart_update_items_after>
41
+ <checkout_cart_product_update_after>
42
+ <observers>
43
+ <affinityEngine_updateproductcart>
44
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
45
+ <method>updateProductCart</method>
46
+ </affinityEngine_updateproductcart>
47
+ </observers>
48
+ </checkout_cart_product_update_after>
49
+ <sales_quote_remove_item>
50
+ <observers>
51
+ <affinityEngine_removecart>
52
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
53
+ <method>removeFromCart</method>
54
+ </affinityEngine_removecart>
55
+ </observers>
56
+ </sales_quote_remove_item>
57
+ <catalog_product_save_after>
58
+ <observers>
59
+ <affinityEngine_saveproduct>
60
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
61
+ <method>saveProduct</method>
62
+ </affinityEngine_saveproduct>
63
+ </observers>
64
+ </catalog_product_save_after>
65
+ <catalog_category_save_before>
66
+ <observers>
67
+ <affinityEngine_savecategory>
68
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
69
+ <method>saveCategory</method>
70
+ </affinityEngine_savecategory>
71
+ </observers>
72
+ </catalog_category_save_before>
73
+ <sales_order_save_before>
74
+ <observers>
75
+ <affinityEngine_saveorder>
76
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
77
+ <method>saveOrder</method>
78
+ </affinityEngine_saveorder>
79
+ </observers>
80
+ </sales_order_save_before>
81
+ <catalog_controller_category_delete>
82
+ <observers>
83
+ <affinityEngine_deletecategory>
84
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
85
+ <method>deleteCategory</method>
86
+ </affinityEngine_deletecategory>
87
+ </observers>
88
+ </catalog_controller_category_delete>
89
+ <catalog_product_delete_before>
90
+ <observers>
91
+ <affinityEngine_deleteproduct>
92
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
93
+ <method>deleteProduct</method>
94
+ </affinityEngine_deleteproduct>
95
+ </observers>
96
+ </catalog_product_delete_before>
97
+ <controller_action_layout_load_before>
98
+ <observers>
99
+ <affinityEngine_checkcookie>
100
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
101
+ <method>checkCookie</method>
102
+ </affinityEngine_checkcookie>
103
+ </observers>
104
+ </controller_action_layout_load_before>
105
+ <customer_login>
106
+ <observers>
107
+ <affinityEngine_login>
108
+ <class>AffinityEngine_AffinityItems_Model_Observer</class>
109
+ <method>login</method>
110
+ </affinityEngine_login>
111
+ </observers>
112
+ </customer_login>
113
+ </events>
114
+ <blocks>
115
+ <affinityitems>
116
+ <class>AffinityEngine_AffinityItems_Block</class>
117
+ </affinityitems>
118
+ </blocks>
119
+ <models>
120
+ <affinityitems>
121
+ <class>AffinityEngine_AffinityItems_Model</class>
122
+ <resourceModel>affinityitems_resource</resourceModel>
123
+ </affinityitems>
124
+
125
+ <affinityitems_resource>
126
+ <class>AffinityEngine_AffinityItems_Model_Resource</class>
127
+ <entities>
128
+ <ae_log>
129
+ <table>ae_log</table>
130
+ </ae_log>
131
+ <ae_cart_repository>
132
+ <table>ae_cart_repository</table>
133
+ </ae_cart_repository>
134
+ <ae_guest_action_repository>
135
+ <table>ae_guest_action_repository</table>
136
+ </ae_guest_action_repository>
137
+ <ae_sync_rotate>
138
+ <table>ae_sync_rotate</table>
139
+ </ae_sync_rotate>
140
+ <ae_cat_prod_repository>
141
+ <table>ae_cat_prod_repository</table>
142
+ </ae_cat_prod_repository>
143
+ </entities>
144
+ </affinityitems_resource>
145
+ </models>
146
+ <resources>
147
+ <affinityitems_setup>
148
+ <setup>
149
+ <module>AffinityEngine_AffinityItems</module>
150
+ <class>Mage_Eav_Model_Entity_Setup</class>
151
+ </setup>
152
+ <connection>
153
+ <use>core_setup</use>
154
+ </connection>
155
+ </affinityitems_setup>
156
+ <affinityitems_write>
157
+ <connection>
158
+ <use>core_write</use>
159
+ </connection>
160
+ </affinityitems_write>
161
+ <affinityitems_read>
162
+ <connection>
163
+ <use>core_read</use>
164
+ </connection>
165
+ </affinityitems_read>
166
+ </resources>
167
+ </global>
168
+ <admin>
169
+ <routers>
170
+ <affinityitems>
171
+ <use>admin</use>
172
+ <args>
173
+ <module>AffinityEngine_AffinityItems</module>
174
+ <frontName>affinityitems</frontName>
175
+ </args>
176
+ </affinityitems>
177
+ </routers>
178
+ </admin>
179
+ <adminhtml>
180
+ <menu>
181
+ <affinityengine module="affinityitems">
182
+ <title>Affinity Engine</title>
183
+ <sort_order>100</sort_order>
184
+ <children>
185
+ <affinityitems module="affinityitems">
186
+ <title>Dashboard</title>
187
+ <sort_order>0</sort_order>
188
+ <action>affinityitems/adminhtml_affinityitemsbackend</action>
189
+ </affinityitems>
190
+ <affinityitems_log module="affinityitems">
191
+ <title>Logs</title>
192
+ <sort_order>5</sort_order>
193
+ <action>affinityitems/adminhtml_affinityitemslog</action>
194
+ </affinityitems_log>
195
+ <affinityitemsconfig module="affinityitems">
196
+ <title>Configuration</title>
197
+ <sort_order>10</sort_order>
198
+ <action>adminhtml/system_config/edit/section/affinityitems</action>
199
+ </affinityitemsconfig>
200
+ </children>
201
+ </affinityengine>
202
+ </menu>
203
+ <acl>
204
+ <resources>
205
+ <all>
206
+ <title>Allow Everything</title>
207
+ </all>
208
+ <admin>
209
+ <children>
210
+ <affinity_engine translate="title" module="affinityitems">
211
+ <title>Affinity Engine</title>
212
+ <sort_order>1000</sort_order>
213
+ <children>
214
+ <affinityitems translate="title">
215
+ <title>Dashboard</title>
216
+ </affinityitems>
217
+ <affinityitems_log translate="title">
218
+ <title>Logs</title>
219
+ </affinityitems_log>
220
+ <affinityitems_config translate="title">
221
+ <title>Configuration</title>
222
+ </affinityitems_config>
223
+ </children>
224
+ </affinity_engine>
225
+ </children>
226
+ </admin>
227
+ </resources>
228
+ </acl>
229
+ <layout>
230
+ <updates>
231
+ <affinityitems>
232
+ <file>affinityitems.xml</file>
233
+ </affinityitems>
234
+ </updates>
235
+ </layout>
236
+ <translate>
237
+ <modules>
238
+ <AffinityEngine_AffinityItems>
239
+ <files>
240
+ <default>AffinityEngine_AffinityItems.csv</default>
241
+ </files>
242
+ </AffinityEngine_AffinityItems>
243
+ </modules>
244
+ </translate>
245
+ </adminhtml>
246
+ <frontend>
247
+ <routers>
248
+ <affinityitems>
249
+ <use>standard</use>
250
+ <args>
251
+ <module>AffinityEngine_AffinityItems</module>
252
+ <frontName>affinityitems</frontName>
253
+ </args>
254
+ </affinityitems>
255
+ </routers>
256
+ <layout>
257
+ <updates>
258
+ <storelocator>
259
+ <file>affinityengine/affinityitems.xml</file>
260
+ </storelocator>
261
+ </updates>
262
+ </layout>
263
+ </frontend>
264
+
265
+ <default>
266
+ <affinityitems>
267
+ <items_home>
268
+ <number_products>4</number_products>
269
+ <number_products_per_line>4</number_products_per_line>
270
+ <recommendation_config>personalization</recommendation_config>
271
+ <image_size>0</image_size>
272
+ <parent_div>,ae_products_block_center clearfix</parent_div>
273
+ <title_class>ae_block_title_center</title_class>
274
+ <content_div>,ae_content_block_center</content_div>
275
+ <ul>,ae_list_products_block_center</ul>
276
+ <li>,ae_product_block_center</li>
277
+ <product_image_class>ae_img_center</product_image_class>
278
+ <product_name_class>ae_products_name_center</product_name_class>
279
+ <product_dsecription_class>ae_product_dsecription</product_dsecription_class>
280
+ <price_container_class>ae_price_container_center</price_container_class>
281
+ <price_class>ae_price_center</price_class>
282
+ </items_home>
283
+ <items_left>
284
+ <number_products>4</number_products>
285
+ <number_products_per_line>4</number_products_per_line>
286
+ <image_size>0</image_size>
287
+ <parent_div>,ae_products_block_center clearfix</parent_div>
288
+ <title_class>ae_block_title_center</title_class>
289
+ <content_div>,ae_content_block_center</content_div>
290
+ <ul>,ae_list_products_block_center</ul>
291
+ <li>,ae_product_block_center</li>
292
+ <product_image_class>ae_img_center</product_image_class>
293
+ <product_name_class>ae_products_name_center</product_name_class>
294
+ <product_dsecription_class>ae_product_dsecription</product_dsecription_class>
295
+ <price_container_class>ae_price_container_center</price_container_class>
296
+ <price_class>ae_price_center</price_class>
297
+ </items_left>
298
+ <items_right>
299
+ <number_products>4</number_products>
300
+ <number_products_per_line>4</number_products_per_line>
301
+ <recommendation_config>personalization</recommendation_config>
302
+ <image_size>0</image_size>
303
+ <parent_div>,ae_products_block_center clearfix</parent_div>
304
+ <title_class>ae_block_title_center</title_class>
305
+ <content_div>,ae_content_block_center</content_div>
306
+ <ul>,ae_list_products_block_center</ul>
307
+ <li>,ae_product_block_center</li>
308
+ <product_image_class>ae_img_center</product_image_class>
309
+ <product_name_class>ae_products_name_center</product_name_class>
310
+ <product_dsecription_class>ae_product_dsecription</product_dsecription_class>
311
+ <price_container_class>ae_price_container_center</price_container_class>
312
+ <price_class>ae_price_center</price_class>
313
+ </items_right>
314
+ <items_cart>
315
+ <number_products>4</number_products>
316
+ <number_products_per_line>4</number_products_per_line>
317
+ <recommendation_config>personalization</recommendation_config>
318
+ <image_size>0</image_size>
319
+ <parent_div>,ae_products_block_center clearfix</parent_div>
320
+ <title_class>ae_block_title_center</title_class>
321
+ <content_div>,ae_content_block_center</content_div>
322
+ <ul>,ae_list_products_block_center</ul>
323
+ <li>,ae_product_block_center</li>
324
+ <product_image_class>ae_img_center</product_image_class>
325
+ <product_name_class>ae_products_name_center</product_name_class>
326
+ <product_dsecription_class>ae_product_dsecription</product_dsecription_class>
327
+ <price_container_class>ae_price_container_center</price_container_class>
328
+ <price_class>ae_price_center</price_class>
329
+ </items_cart>
330
+ <items_product>
331
+ <number_products>4</number_products>
332
+ <number_products_per_line>4</number_products_per_line>
333
+ <recommendation_config>personalization</recommendation_config>
334
+ <image_size>0</image_size>
335
+ <parent_div>,ae_products_block_center clearfix</parent_div>
336
+ <title_class>ae_block_title_center</title_class>
337
+ <content_div>,ae_content_block_center</content_div>
338
+ <ul>,ae_list_products_block_center</ul>
339
+ <li>,ae_product_block_center</li>
340
+ <product_image_class>ae_img_center</product_image_class>
341
+ <product_name_class>ae_products_name_center</product_name_class>
342
+ <product_dsecription_class>ae_product_dsecription</product_dsecription_class>
343
+ <price_container_class>ae_price_container_center</price_container_class>
344
+ <price_class>ae_price_center</price_class>
345
+ </items_product>
346
+ <items_search>
347
+ <number_products>4</number_products>
348
+ <number_products_per_line>4</number_products_per_line>
349
+ <recommendation_config>personalization</recommendation_config>
350
+ <image_size>0</image_size>
351
+ <parent_div>,ae_products_block_center clearfix</parent_div>
352
+ <title_class>ae_block_title_center</title_class>
353
+ <content_div>,ae_content_block_center</content_div>
354
+ <ul>,ae_list_products_block_center</ul>
355
+ <li>,ae_product_block_center</li>
356
+ <product_image_class>ae_img_center</product_image_class>
357
+ <product_name_class>ae_products_name_center</product_name_class>
358
+ <product_dsecription_class>ae_product_dsecription</product_dsecription_class>
359
+ <price_container_class>ae_price_container_center</price_container_class>
360
+ <price_class>ae_price_center</price_class>
361
+ </items_search>
362
+ <items_category>
363
+ <number_products>4</number_products>
364
+ <number_products_per_line>4</number_products_per_line>
365
+ <recommendation_config>personalization</recommendation_config>
366
+ <image_size>0</image_size>
367
+ <parent_div>,ae_products_block_center clearfix</parent_div>
368
+ <title_class>ae_block_title_center</title_class>
369
+ <content_div>,ae_content_block_center</content_div>
370
+ <ul>,ae_list_products_block_center</ul>
371
+ <li>,ae_product_block_center</li>
372
+ <product_image_class>ae_img_center</product_image_class>
373
+ <product_name_class>ae_products_name_center</product_name_class>
374
+ <product_dsecription_class>ae_product_dsecription</product_dsecription_class>
375
+ <price_container_class>ae_price_container_center</price_container_class>
376
+ <price_class>ae_price_center</price_class>
377
+ </items_category>
378
+ <image_size>
379
+ <default>125,125</default>
380
+ <large>458,458</large>
381
+ <medium>250,250</medium>
382
+ <small>98,98</small>
383
+ </image_size>
384
+ </affinityitems>
385
+ </default>
386
+
387
+ <crontab>
388
+ <jobs>
389
+ <affinityitems_sync>
390
+ <schedule>
391
+ <cron_expr>*/5 * * * *</cron_expr>
392
+ </schedule>
393
+ <run>
394
+ <model>affinityitems/cron::Sync</model>
395
+ </run>
396
+ </affinityitems_sync>
397
+ </jobs>
398
+ </crontab>
399
+ </config>
app/code/local/AffinityEngine/AffinityItems/etc/system.xml ADDED
@@ -0,0 +1,1639 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <tabs>
4
+ <affinity_engine translate="label" module="affinityitems">
5
+ <label>Affinity Engine</label>
6
+ <sort_order>0</sort_order>
7
+ <class>affinity-block</class>
8
+ </affinity_engine>
9
+ </tabs>
10
+ <sections>
11
+ <affinityitems translate="label" module="affinityitems">
12
+ <label>Affinity Items</label>
13
+ <tab>affinity_engine</tab>
14
+ <sort_order>0</sort_order>
15
+ <show_in_default>1</show_in_default>
16
+ <show_in_website>1</show_in_website>
17
+ <show_in_store>1</show_in_store>
18
+ <groups>
19
+ <general translate="label" module="affinityitems">
20
+ <label>General configuration</label>
21
+ <frontend_type>text</frontend_type>
22
+ <sort_order>0</sort_order>
23
+ <show_in_default>1</show_in_default>
24
+ <show_in_website>1</show_in_website>
25
+ <show_in_store>1</show_in_store>
26
+ <fields>
27
+ <enable translate="label">
28
+ <label>Activation</label>
29
+ <frontend_type>select</frontend_type>
30
+ <source_model>adminhtml/system_config_source_yesno</source_model>
31
+ <sort_order>0</sort_order>
32
+ <show_in_default>1</show_in_default>
33
+ <show_in_website>1</show_in_website>
34
+ <show_in_store>1</show_in_store>
35
+ </enable>
36
+ <dev_prod translate="label">
37
+ <label>Enviroment</label>
38
+ <frontend_type>select</frontend_type>
39
+ <source_model>affinityitems/source_enviroment</source_model>
40
+ <sort_order>3</sort_order>
41
+ <show_in_default>1</show_in_default>
42
+ <show_in_website>1</show_in_website>
43
+ <show_in_store>1</show_in_store>
44
+ <comment><![CDATA[You will be logged out from affinity server on change]]></comment>
45
+ </dev_prod>
46
+ <guest_percentage translate="label">
47
+ <label>% guests with recommendations</label>
48
+ <frontend_type>text</frontend_type>
49
+ <sort_order>5</sort_order>
50
+ <show_in_default>1</show_in_default>
51
+ <show_in_website>1</show_in_website>
52
+ <show_in_store>1</show_in_store>
53
+ <comment><![CDATA[Please enter number from 1 to 100]]></comment>
54
+ <tooltip><![CDATA[
55
+ The outcome measurement relies on the AB Testing method, an unbiased and reliable impact measure, no matter the conditions.
56
+ <br>In this method, a control group of visitors is not eligible for the recommandation.
57
+ <br>You can control the AB Testing groups :
58
+ <br>• First test our solution with a low rate of recommandation
59
+ <br>• Maximize the rate to benefit from the full recommandation impact]]></tooltip>
60
+ <depends>
61
+ <enable>1</enable>
62
+ </depends>
63
+ </guest_percentage>
64
+ <version translate="label">
65
+ <label>Version</label>
66
+ <frontend_type>text</frontend_type>
67
+ <frontend_model>affinityitems/renderer_config_version</frontend_model>
68
+ <sort_order>20</sort_order>
69
+ <show_in_default>1</show_in_default>
70
+ <show_in_website>0</show_in_website>
71
+ <show_in_store>0</show_in_store>
72
+ <depends>
73
+ <enable>1</enable>
74
+ </depends>
75
+ </version>
76
+ </fields>
77
+ </general>
78
+ <advanced translate="label" module="affinityitems">
79
+ <label>Advanced configuration</label>
80
+ <frontend_type>text</frontend_type>
81
+ <sort_order>3</sort_order>
82
+ <show_in_default>1</show_in_default>
83
+ <show_in_website>1</show_in_website>
84
+ <show_in_store>1</show_in_store>
85
+ <fields>
86
+ <heading>
87
+ <label><![CDATA[<strong>To secure the access to the recommendations, please indicate the servers that are allowed to query these recommendations</strong>]]></label>
88
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
89
+ <sort_order>5</sort_order>
90
+ <show_in_default>1</show_in_default>
91
+ <show_in_website>1</show_in_website>
92
+ <show_in_store>1</show_in_store>
93
+ </heading>
94
+ <server_ip>
95
+ <label>Server access</label>
96
+ <frontend_model>affinityitems/renderer_config_serverlist</frontend_model>
97
+ <backend_model>adminhtml/system_config_backend_serialized</backend_model>
98
+ <sort_order>10</sort_order>
99
+ <show_in_default>1</show_in_default>
100
+ <show_in_website>1</show_in_website>
101
+ <show_in_store>1</show_in_store>
102
+ <can_be_empty>1</can_be_empty>
103
+ <comment><![CDATA[IP list]]></comment>
104
+ </server_ip>
105
+ <!-- <rescind translate="label">
106
+ <label>Rescind contract</label>
107
+ <frontend_type>select</frontend_type>
108
+ <source_model>adminhtml/system_config_source_yesno</source_model>
109
+ <sort_order>30</sort_order>
110
+ <show_in_default>1</show_in_default>
111
+ <show_in_website>1</show_in_website>
112
+ <show_in_store>1</show_in_store>
113
+ <comment><![CDATA[If this box is set to YES, we will delete yours personal data on our platform after the uninstall]]></comment>
114
+ <tooltip><![CDATA[
115
+ This option allows you to avoid the resynchronization step when installing a new version of the module.]]></tooltip>
116
+ </rescind>-->
117
+ <ab_blacklist_ip translate="label">
118
+ <label>A/B Testing IP Blacklist</label>
119
+ <frontend_model>affinityitems/renderer_config_ipblacklist</frontend_model>
120
+ <backend_model>adminhtml/system_config_backend_serialized</backend_model>
121
+ <sort_order>40</sort_order>
122
+ <show_in_default>1</show_in_default>
123
+ <show_in_website>1</show_in_website>
124
+ <show_in_store>1</show_in_store>
125
+ <comment><![CDATA[IP list]]></comment>
126
+ <tooltip><![CDATA[
127
+ This feature lets you blacklist the IP addresses of your own company, so that the statistics are unbiased. For example, if a call center places orders directly on the site, these commands should not be taken into account in the AB Testing. Blacklisted IP addresses do not receive recommendations]]></tooltip>
128
+ </ab_blacklist_ip>
129
+ <sync_count translate="label">
130
+ <label>Number of elements to be synced</label>
131
+ <frontend_type>text</frontend_type>
132
+ <sort_order>50</sort_order>
133
+ <show_in_default>1</show_in_default>
134
+ <show_in_website>1</show_in_website>
135
+ <show_in_store>1</show_in_store>
136
+ <comment><![CDATA[default value is 300]]></comment>
137
+ <validate>validate-number</validate>
138
+ <tooltip><![CDATA[
139
+ Define number of elements to be synced in one run of cron sync]]></tooltip>
140
+ </sync_count>
141
+ <ae_css>
142
+ <label><![CDATA[<strong>Additional CSS</strong>]]></label>
143
+ <frontend_type>textarea</frontend_type>
144
+ <sort_order>60</sort_order>
145
+ <show_in_default>1</show_in_default>
146
+ <show_in_website>1</show_in_website>
147
+ <show_in_store>1</show_in_store>
148
+ </ae_css>
149
+ </fields>
150
+ </advanced>
151
+ <developer translate="label" module="affinityitems">
152
+ <label>Developer options</label>
153
+ <frontend_type>text</frontend_type>
154
+ <sort_order>4</sort_order>
155
+ <show_in_default>1</show_in_default>
156
+ <show_in_website>1</show_in_website>
157
+ <show_in_store>1</show_in_store>
158
+ <fields>
159
+ <log_level translate="label">
160
+ <label>Log Level</label>
161
+ <frontend_type>select</frontend_type>
162
+ <source_model>affinityitems/source_loglevel</source_model>
163
+ <sort_order>0</sort_order>
164
+ <show_in_default>1</show_in_default>
165
+ <show_in_website>1</show_in_website>
166
+ <show_in_store>1</show_in_store>
167
+ </log_level>
168
+ </fields>
169
+ </developer>
170
+ <image_size translate="label" module="affinityitems">
171
+ <label>Image size</label>
172
+ <frontend_type>text</frontend_type>
173
+ <sort_order>5</sort_order>
174
+ <show_in_default>1</show_in_default>
175
+ <show_in_website>1</show_in_website>
176
+ <show_in_store>1</show_in_store>
177
+ <comment><![CDATA[<strong>Width x Height, in pixels</strong>]]></comment>
178
+ <fields>
179
+ <default translate="label">
180
+ <label>Default Image Size</label>
181
+ <frontend_type>text</frontend_type>
182
+ <frontend_model>affinityitems/renderer_config_imagesize</frontend_model>
183
+ <sort_order>100</sort_order>
184
+ <show_in_default>1</show_in_default>
185
+ <show_in_website>1</show_in_website>
186
+ <show_in_store>1</show_in_store>
187
+ <validate>validate-number</validate>
188
+ </default>
189
+ <large translate="label">
190
+ <label>Large Image Size</label>
191
+ <frontend_type>text</frontend_type>
192
+ <frontend_model>affinityitems/renderer_config_imagesize</frontend_model>
193
+ <sort_order>120</sort_order>
194
+ <show_in_default>1</show_in_default>
195
+ <show_in_website>1</show_in_website>
196
+ <show_in_store>1</show_in_store>
197
+ <validate>validate-number</validate>
198
+ </large>
199
+ <medium translate="label">
200
+ <label>Medium Image Size</label>
201
+ <frontend_type>text</frontend_type>
202
+ <frontend_model>affinityitems/renderer_config_imagesize</frontend_model>
203
+ <sort_order>140</sort_order>
204
+ <show_in_default>1</show_in_default>
205
+ <show_in_website>1</show_in_website>
206
+ <show_in_store>1</show_in_store>
207
+ <validate>validate-number</validate>
208
+ </medium>
209
+ <small translate="label">
210
+ <label>Small Image Size</label>
211
+ <frontend_type>text</frontend_type>
212
+ <frontend_model>affinityitems/renderer_config_imagesize</frontend_model>
213
+ <sort_order>160</sort_order>
214
+ <show_in_default>1</show_in_default>
215
+ <show_in_website>1</show_in_website>
216
+ <show_in_store>1</show_in_store>
217
+ <validate>validate-number</validate>
218
+ </small>
219
+ </fields>
220
+ </image_size>
221
+
222
+ <items_home translate="label" module="affinityitems">
223
+ <label>Home page</label>
224
+ <frontend_type>text</frontend_type>
225
+ <sort_order>10</sort_order>
226
+ <show_in_default>1</show_in_default>
227
+ <show_in_website>1</show_in_website>
228
+ <show_in_store>1</show_in_store>
229
+ <fields>
230
+ <enable translate="label">
231
+ <label>Enable</label>
232
+ <frontend_type>select</frontend_type>
233
+ <source_model>adminhtml/system_config_source_yesno</source_model>
234
+ <sort_order>0</sort_order>
235
+ <show_in_default>1</show_in_default>
236
+ <show_in_website>1</show_in_website>
237
+ <show_in_store>1</show_in_store>
238
+ </enable>
239
+ <recommendation_label translate="label">
240
+ <label>Recommendation area label</label>
241
+ <frontend_type>text</frontend_type>
242
+ <sort_order>5</sort_order>
243
+ <show_in_default>1</show_in_default>
244
+ <show_in_website>1</show_in_website>
245
+ <show_in_store>1</show_in_store>
246
+ <depends>
247
+ <enable>1</enable>
248
+ </depends>
249
+ </recommendation_label>
250
+ <recommendation_config translate="label">
251
+ <label>Recommendation configuration</label>
252
+ <frontend_type>select</frontend_type>
253
+ <source_model>affinityitems/source_recoconfig::home</source_model>
254
+ <sort_order>12</sort_order>
255
+ <show_in_default>1</show_in_default>
256
+ <show_in_website>1</show_in_website>
257
+ <show_in_store>1</show_in_store>
258
+ <depends>
259
+ <enable>1</enable>
260
+ </depends>
261
+ </recommendation_config>
262
+ <number_products translate="label">
263
+ <label>Number of displayed products</label>
264
+ <frontend_type>text</frontend_type>
265
+ <sort_order>10</sort_order>
266
+ <show_in_default>1</show_in_default>
267
+ <show_in_website>1</show_in_website>
268
+ <show_in_store>1</show_in_store>
269
+ <depends>
270
+ <enable>1</enable>
271
+ </depends>
272
+ </number_products>
273
+ <number_products_per_line translate="label">
274
+ <label>Number of displayed products per line</label>
275
+ <frontend_type>text</frontend_type>
276
+ <sort_order>12</sort_order>
277
+ <show_in_default>1</show_in_default>
278
+ <show_in_website>1</show_in_website>
279
+ <show_in_store>1</show_in_store>
280
+ <depends>
281
+ <enable>1</enable>
282
+ </depends>
283
+ </number_products_per_line>
284
+ <image_size translate="label">
285
+ <label>Image size</label>
286
+ <frontend_type>select</frontend_type>
287
+ <source_model>affinityitems/source_imagesize</source_model>
288
+ <sort_order>15</sort_order>
289
+ <show_in_default>1</show_in_default>
290
+ <show_in_website>1</show_in_website>
291
+ <show_in_store>1</show_in_store>
292
+ <depends>
293
+ <enable>1</enable>
294
+ </depends>
295
+ </image_size>
296
+ <display_settings>
297
+ <label><![CDATA[<strong>Display settings</strong>]]></label>
298
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
299
+ <sort_order>60</sort_order>
300
+ <show_in_default>1</show_in_default>
301
+ <show_in_website>1</show_in_website>
302
+ <show_in_store>1</show_in_store>
303
+ <depends>
304
+ <enable>1</enable>
305
+ </depends>
306
+ </display_settings>
307
+ <parent_div translate="label">
308
+ <label><![CDATA[Parent <strong>&lt;div&gt;</strong>]]></label>
309
+ <frontend_type>text</frontend_type>
310
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
311
+ <sort_order>65</sort_order>
312
+ <show_in_default>1</show_in_default>
313
+ <show_in_website>1</show_in_website>
314
+ <show_in_store>1</show_in_store>
315
+ <depends>
316
+ <enable>1</enable>
317
+ </depends>
318
+ </parent_div>
319
+ <title_class translate="label">
320
+ <label><![CDATA[&nbsp;&nbsp;Title <strong>class</strong>]]></label>
321
+ <frontend_type>text</frontend_type>
322
+ <sort_order>70</sort_order>
323
+ <show_in_default>1</show_in_default>
324
+ <show_in_website>1</show_in_website>
325
+ <show_in_store>1</show_in_store>
326
+ <depends>
327
+ <enable>1</enable>
328
+ </depends>
329
+ </title_class>
330
+ <content_div translate="label">
331
+ <label><![CDATA[&nbsp;&nbsp;Content <strong>&lt;div&gt;</strong>]]></label>
332
+ <frontend_type>text</frontend_type>
333
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
334
+ <sort_order>75</sort_order>
335
+ <show_in_default>1</show_in_default>
336
+ <show_in_website>1</show_in_website>
337
+ <show_in_store>1</show_in_store>
338
+ <depends>
339
+ <enable>1</enable>
340
+ </depends>
341
+ </content_div>
342
+ <ul translate="label">
343
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;List <strong>&lt;ul&gt;</strong>]]></label>
344
+ <frontend_type>text</frontend_type>
345
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
346
+ <sort_order>80</sort_order>
347
+ <show_in_default>1</show_in_default>
348
+ <show_in_website>1</show_in_website>
349
+ <show_in_store>1</show_in_store>
350
+ <depends>
351
+ <enable>1</enable>
352
+ </depends>
353
+ </ul>
354
+ <li translate="label">
355
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List element <strong>&lt;li&gt;</strong>]]></label>
356
+ <frontend_type>text</frontend_type>
357
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
358
+ <sort_order>85</sort_order>
359
+ <show_in_default>1</show_in_default>
360
+ <show_in_website>1</show_in_website>
361
+ <show_in_store>1</show_in_store>
362
+ <depends>
363
+ <enable>1</enable>
364
+ </depends>
365
+ </li>
366
+ <product_image_class translate="label">
367
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product image class]]></label>
368
+ <frontend_type>text</frontend_type>
369
+ <sort_order>90</sort_order>
370
+ <show_in_default>1</show_in_default>
371
+ <show_in_website>1</show_in_website>
372
+ <show_in_store>1</show_in_store>
373
+ <depends>
374
+ <enable>1</enable>
375
+ </depends>
376
+ </product_image_class>
377
+ <product_name_class translate="label">
378
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product name class]]></label>
379
+ <frontend_type>text</frontend_type>
380
+ <sort_order>95</sort_order>
381
+ <show_in_default>1</show_in_default>
382
+ <show_in_website>1</show_in_website>
383
+ <show_in_store>1</show_in_store>
384
+ <depends>
385
+ <enable>1</enable>
386
+ </depends>
387
+ </product_name_class>
388
+ <product_dsecription_class translate="label">
389
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product description class]]></label>
390
+ <frontend_type>text</frontend_type>
391
+ <sort_order>100</sort_order>
392
+ <show_in_default>1</show_in_default>
393
+ <show_in_website>1</show_in_website>
394
+ <show_in_store>1</show_in_store>
395
+ <depends>
396
+ <enable>1</enable>
397
+ </depends>
398
+ </product_dsecription_class>
399
+ <price_container_class translate="label">
400
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price container class]]></label>
401
+ <frontend_type>text</frontend_type>
402
+ <sort_order>105</sort_order>
403
+ <show_in_default>1</show_in_default>
404
+ <show_in_website>1</show_in_website>
405
+ <show_in_store>1</show_in_store>
406
+ <depends>
407
+ <enable>1</enable>
408
+ </depends>
409
+ </price_container_class>
410
+ <price_class translate="label">
411
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price class]]></label>
412
+ <frontend_type>text</frontend_type>
413
+ <sort_order>110</sort_order>
414
+ <show_in_default>1</show_in_default>
415
+ <show_in_website>1</show_in_website>
416
+ <show_in_store>1</show_in_store>
417
+ <depends>
418
+ <enable>1</enable>
419
+ </depends>
420
+ </price_class>
421
+ </fields>
422
+ </items_home>
423
+
424
+ <items_left translate="label" module="affinityitems">
425
+ <label>Left column</label>
426
+ <frontend_type>text</frontend_type>
427
+ <sort_order>20</sort_order>
428
+ <show_in_default>1</show_in_default>
429
+ <show_in_website>1</show_in_website>
430
+ <show_in_store>1</show_in_store>
431
+ <fields>
432
+ <enable translate="label">
433
+ <label>Enable</label>
434
+ <frontend_type>select</frontend_type>
435
+ <source_model>adminhtml/system_config_source_yesno</source_model>
436
+ <sort_order>0</sort_order>
437
+ <show_in_default>1</show_in_default>
438
+ <show_in_website>1</show_in_website>
439
+ <show_in_store>1</show_in_store>
440
+ </enable>
441
+ <recommendation_label translate="label">
442
+ <label>Recommendation area label</label>
443
+ <frontend_type>text</frontend_type>
444
+ <sort_order>5</sort_order>
445
+ <show_in_default>1</show_in_default>
446
+ <show_in_website>1</show_in_website>
447
+ <show_in_store>1</show_in_store>
448
+ <depends>
449
+ <enable>1</enable>
450
+ </depends>
451
+ </recommendation_label>
452
+ <recommendation_config translate="label">
453
+ <label>Recommendation configuration</label>
454
+ <frontend_type>select</frontend_type>
455
+ <source_model>affinityitems/source_recoconfig::left</source_model>
456
+ <sort_order>12</sort_order>
457
+ <show_in_default>1</show_in_default>
458
+ <show_in_website>1</show_in_website>
459
+ <show_in_store>1</show_in_store>
460
+ <depends>
461
+ <enable>1</enable>
462
+ </depends>
463
+ </recommendation_config>
464
+ <number_products translate="label">
465
+ <label>Number of displayed products</label>
466
+ <frontend_type>text</frontend_type>
467
+ <sort_order>10</sort_order>
468
+ <show_in_default>1</show_in_default>
469
+ <show_in_website>1</show_in_website>
470
+ <show_in_store>1</show_in_store>
471
+ <depends>
472
+ <enable>1</enable>
473
+ </depends>
474
+ </number_products>
475
+ <number_products_per_line translate="label">
476
+ <label>Number of displayed products per line</label>
477
+ <frontend_type>text</frontend_type>
478
+ <sort_order>12</sort_order>
479
+ <show_in_default>1</show_in_default>
480
+ <show_in_website>1</show_in_website>
481
+ <show_in_store>1</show_in_store>
482
+ <depends>
483
+ <enable>1</enable>
484
+ </depends>
485
+ </number_products_per_line>
486
+ <image_size translate="label">
487
+ <label>Image size</label>
488
+ <frontend_type>select</frontend_type>
489
+ <source_model>affinityitems/source_imagesize</source_model>
490
+ <sort_order>15</sort_order>
491
+ <show_in_default>1</show_in_default>
492
+ <show_in_website>1</show_in_website>
493
+ <show_in_store>1</show_in_store>
494
+ <depends>
495
+ <enable>1</enable>
496
+ </depends>
497
+ </image_size>
498
+ <display_settings>
499
+ <label><![CDATA[<strong>Display settings</strong>]]></label>
500
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
501
+ <sort_order>60</sort_order>
502
+ <show_in_default>1</show_in_default>
503
+ <show_in_website>1</show_in_website>
504
+ <show_in_store>1</show_in_store>
505
+ <depends>
506
+ <enable>1</enable>
507
+ </depends>
508
+ </display_settings>
509
+ <parent_div translate="label">
510
+ <label><![CDATA[Parent <strong>&lt;div&gt;</strong>]]></label>
511
+ <frontend_type>text</frontend_type>
512
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
513
+ <sort_order>65</sort_order>
514
+ <show_in_default>1</show_in_default>
515
+ <show_in_website>1</show_in_website>
516
+ <show_in_store>1</show_in_store>
517
+ <depends>
518
+ <enable>1</enable>
519
+ </depends>
520
+ </parent_div>
521
+ <title_class translate="label">
522
+ <label><![CDATA[&nbsp;&nbsp;Title <strong>class</strong>]]></label>
523
+ <frontend_type>text</frontend_type>
524
+ <sort_order>70</sort_order>
525
+ <show_in_default>1</show_in_default>
526
+ <show_in_website>1</show_in_website>
527
+ <show_in_store>1</show_in_store>
528
+ <depends>
529
+ <enable>1</enable>
530
+ </depends>
531
+ </title_class>
532
+ <content_div translate="label">
533
+ <label><![CDATA[&nbsp;&nbsp;Content <strong>&lt;div&gt;</strong>]]></label>
534
+ <frontend_type>text</frontend_type>
535
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
536
+ <sort_order>75</sort_order>
537
+ <show_in_default>1</show_in_default>
538
+ <show_in_website>1</show_in_website>
539
+ <show_in_store>1</show_in_store>
540
+ <depends>
541
+ <enable>1</enable>
542
+ </depends>
543
+ </content_div>
544
+ <ul translate="label">
545
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;List <strong>&lt;ul&gt;</strong>]]></label>
546
+ <frontend_type>text</frontend_type>
547
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
548
+ <sort_order>80</sort_order>
549
+ <show_in_default>1</show_in_default>
550
+ <show_in_website>1</show_in_website>
551
+ <show_in_store>1</show_in_store>
552
+ <depends>
553
+ <enable>1</enable>
554
+ </depends>
555
+ </ul>
556
+ <li translate="label">
557
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List element <strong>&lt;li&gt;</strong>]]></label>
558
+ <frontend_type>text</frontend_type>
559
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
560
+ <sort_order>85</sort_order>
561
+ <show_in_default>1</show_in_default>
562
+ <show_in_website>1</show_in_website>
563
+ <show_in_store>1</show_in_store>
564
+ <depends>
565
+ <enable>1</enable>
566
+ </depends>
567
+ </li>
568
+ <product_image_class translate="label">
569
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product image class]]></label>
570
+ <frontend_type>text</frontend_type>
571
+ <sort_order>90</sort_order>
572
+ <show_in_default>1</show_in_default>
573
+ <show_in_website>1</show_in_website>
574
+ <show_in_store>1</show_in_store>
575
+ <depends>
576
+ <enable>1</enable>
577
+ </depends>
578
+ </product_image_class>
579
+ <product_name_class translate="label">
580
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product name class]]></label>
581
+ <frontend_type>text</frontend_type>
582
+ <sort_order>95</sort_order>
583
+ <show_in_default>1</show_in_default>
584
+ <show_in_website>1</show_in_website>
585
+ <show_in_store>1</show_in_store>
586
+ <depends>
587
+ <enable>1</enable>
588
+ </depends>
589
+ </product_name_class>
590
+ <product_dsecription_class translate="label">
591
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product description class]]></label>
592
+ <frontend_type>text</frontend_type>
593
+ <sort_order>100</sort_order>
594
+ <show_in_default>1</show_in_default>
595
+ <show_in_website>1</show_in_website>
596
+ <show_in_store>1</show_in_store>
597
+ <depends>
598
+ <enable>1</enable>
599
+ </depends>
600
+ </product_dsecription_class>
601
+ <price_container_class translate="label">
602
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price container class]]></label>
603
+ <frontend_type>text</frontend_type>
604
+ <sort_order>105</sort_order>
605
+ <show_in_default>1</show_in_default>
606
+ <show_in_website>1</show_in_website>
607
+ <show_in_store>1</show_in_store>
608
+ <depends>
609
+ <enable>1</enable>
610
+ </depends>
611
+ </price_container_class>
612
+ <price_class translate="label">
613
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price class]]></label>
614
+ <frontend_type>text</frontend_type>
615
+ <sort_order>110</sort_order>
616
+ <show_in_default>1</show_in_default>
617
+ <show_in_website>1</show_in_website>
618
+ <show_in_store>1</show_in_store>
619
+ <depends>
620
+ <enable>1</enable>
621
+ </depends>
622
+ </price_class>
623
+ </fields>
624
+ </items_left>
625
+
626
+ <items_right translate="label" module="affinityitems">
627
+ <label>Right column</label>
628
+ <frontend_type>text</frontend_type>
629
+ <sort_order>30</sort_order>
630
+ <show_in_default>1</show_in_default>
631
+ <show_in_website>1</show_in_website>
632
+ <show_in_store>1</show_in_store>
633
+ <fields>
634
+ <enable translate="label">
635
+ <label>Enable</label>
636
+ <frontend_type>select</frontend_type>
637
+ <source_model>adminhtml/system_config_source_yesno</source_model>
638
+ <sort_order>0</sort_order>
639
+ <show_in_default>1</show_in_default>
640
+ <show_in_website>1</show_in_website>
641
+ <show_in_store>1</show_in_store>
642
+ </enable>
643
+ <recommendation_label translate="label">
644
+ <label>Recommendation area label</label>
645
+ <frontend_type>text</frontend_type>
646
+ <sort_order>5</sort_order>
647
+ <show_in_default>1</show_in_default>
648
+ <show_in_website>1</show_in_website>
649
+ <show_in_store>1</show_in_store>
650
+ <depends>
651
+ <enable>1</enable>
652
+ </depends>
653
+ </recommendation_label>
654
+ <recommendation_config translate="label">
655
+ <label>Recommendation configuration</label>
656
+ <frontend_type>select</frontend_type>
657
+ <source_model>affinityitems/source_recoconfig::right</source_model>
658
+ <sort_order>12</sort_order>
659
+ <show_in_default>1</show_in_default>
660
+ <show_in_website>1</show_in_website>
661
+ <show_in_store>1</show_in_store>
662
+ <depends>
663
+ <enable>1</enable>
664
+ </depends>
665
+ </recommendation_config>
666
+ <number_products translate="label">
667
+ <label>Number of displayed products</label>
668
+ <frontend_type>text</frontend_type>
669
+ <sort_order>10</sort_order>
670
+ <show_in_default>1</show_in_default>
671
+ <show_in_website>1</show_in_website>
672
+ <show_in_store>1</show_in_store>
673
+ <depends>
674
+ <enable>1</enable>
675
+ </depends>
676
+ </number_products>
677
+ <number_products_per_line translate="label">
678
+ <label>Number of displayed products per line</label>
679
+ <frontend_type>text</frontend_type>
680
+ <sort_order>12</sort_order>
681
+ <show_in_default>1</show_in_default>
682
+ <show_in_website>1</show_in_website>
683
+ <show_in_store>1</show_in_store>
684
+ <depends>
685
+ <enable>1</enable>
686
+ </depends>
687
+ </number_products_per_line>
688
+ <image_size translate="label">
689
+ <label>Image size</label>
690
+ <frontend_type>select</frontend_type>
691
+ <source_model>affinityitems/source_imagesize</source_model>
692
+ <sort_order>15</sort_order>
693
+ <show_in_default>1</show_in_default>
694
+ <show_in_website>1</show_in_website>
695
+ <show_in_store>1</show_in_store>
696
+ <depends>
697
+ <enable>1</enable>
698
+ </depends>
699
+ </image_size>
700
+ <display_settings>
701
+ <label><![CDATA[<strong>Display settings</strong>]]></label>
702
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
703
+ <sort_order>60</sort_order>
704
+ <show_in_default>1</show_in_default>
705
+ <show_in_website>1</show_in_website>
706
+ <show_in_store>1</show_in_store>
707
+ <depends>
708
+ <enable>1</enable>
709
+ </depends>
710
+ </display_settings>
711
+ <parent_div translate="label">
712
+ <label><![CDATA[Parent <strong>&lt;div&gt;</strong>]]></label>
713
+ <frontend_type>text</frontend_type>
714
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
715
+ <sort_order>65</sort_order>
716
+ <show_in_default>1</show_in_default>
717
+ <show_in_website>1</show_in_website>
718
+ <show_in_store>1</show_in_store>
719
+ <depends>
720
+ <enable>1</enable>
721
+ </depends>
722
+ </parent_div>
723
+ <title_class translate="label">
724
+ <label><![CDATA[&nbsp;&nbsp;Title <strong>class</strong>]]></label>
725
+ <frontend_type>text</frontend_type>
726
+ <sort_order>70</sort_order>
727
+ <show_in_default>1</show_in_default>
728
+ <show_in_website>1</show_in_website>
729
+ <show_in_store>1</show_in_store>
730
+ <depends>
731
+ <enable>1</enable>
732
+ </depends>
733
+ </title_class>
734
+ <content_div translate="label">
735
+ <label><![CDATA[&nbsp;&nbsp;Content <strong>&lt;div&gt;</strong>]]></label>
736
+ <frontend_type>text</frontend_type>
737
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
738
+ <sort_order>75</sort_order>
739
+ <show_in_default>1</show_in_default>
740
+ <show_in_website>1</show_in_website>
741
+ <show_in_store>1</show_in_store>
742
+ <depends>
743
+ <enable>1</enable>
744
+ </depends>
745
+ </content_div>
746
+ <ul translate="label">
747
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;List <strong>&lt;ul&gt;</strong>]]></label>
748
+ <frontend_type>text</frontend_type>
749
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
750
+ <sort_order>80</sort_order>
751
+ <show_in_default>1</show_in_default>
752
+ <show_in_website>1</show_in_website>
753
+ <show_in_store>1</show_in_store>
754
+ <depends>
755
+ <enable>1</enable>
756
+ </depends>
757
+ </ul>
758
+ <li translate="label">
759
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List element <strong>&lt;li&gt;</strong>]]></label>
760
+ <frontend_type>text</frontend_type>
761
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
762
+ <sort_order>85</sort_order>
763
+ <show_in_default>1</show_in_default>
764
+ <show_in_website>1</show_in_website>
765
+ <show_in_store>1</show_in_store>
766
+ <depends>
767
+ <enable>1</enable>
768
+ </depends>
769
+ </li>
770
+ <product_image_class translate="label">
771
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product image class]]></label>
772
+ <frontend_type>text</frontend_type>
773
+ <sort_order>90</sort_order>
774
+ <show_in_default>1</show_in_default>
775
+ <show_in_website>1</show_in_website>
776
+ <show_in_store>1</show_in_store>
777
+ <depends>
778
+ <enable>1</enable>
779
+ </depends>
780
+ </product_image_class>
781
+ <product_name_class translate="label">
782
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product name class]]></label>
783
+ <frontend_type>text</frontend_type>
784
+ <sort_order>95</sort_order>
785
+ <show_in_default>1</show_in_default>
786
+ <show_in_website>1</show_in_website>
787
+ <show_in_store>1</show_in_store>
788
+ <depends>
789
+ <enable>1</enable>
790
+ </depends>
791
+ </product_name_class>
792
+ <product_dsecription_class translate="label">
793
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product description class]]></label>
794
+ <frontend_type>text</frontend_type>
795
+ <sort_order>100</sort_order>
796
+ <show_in_default>1</show_in_default>
797
+ <show_in_website>1</show_in_website>
798
+ <show_in_store>1</show_in_store>
799
+ <depends>
800
+ <enable>1</enable>
801
+ </depends>
802
+ </product_dsecription_class>
803
+ <price_container_class translate="label">
804
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price container class]]></label>
805
+ <frontend_type>text</frontend_type>
806
+ <sort_order>105</sort_order>
807
+ <show_in_default>1</show_in_default>
808
+ <show_in_website>1</show_in_website>
809
+ <show_in_store>1</show_in_store>
810
+ <depends>
811
+ <enable>1</enable>
812
+ </depends>
813
+ </price_container_class>
814
+ <price_class translate="label">
815
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price class]]></label>
816
+ <frontend_type>text</frontend_type>
817
+ <sort_order>110</sort_order>
818
+ <show_in_default>1</show_in_default>
819
+ <show_in_website>1</show_in_website>
820
+ <show_in_store>1</show_in_store>
821
+ <depends>
822
+ <enable>1</enable>
823
+ </depends>
824
+ </price_class>
825
+ </fields>
826
+ </items_right>
827
+
828
+ <items_cart translate="label" module="affinityitems">
829
+ <label>Cart page</label>
830
+ <frontend_type>text</frontend_type>
831
+ <sort_order>40</sort_order>
832
+ <show_in_default>1</show_in_default>
833
+ <show_in_website>1</show_in_website>
834
+ <show_in_store>1</show_in_store>
835
+ <fields>
836
+ <enable translate="label">
837
+ <label>Enable</label>
838
+ <frontend_type>select</frontend_type>
839
+ <source_model>adminhtml/system_config_source_yesno</source_model>
840
+ <sort_order>0</sort_order>
841
+ <show_in_default>1</show_in_default>
842
+ <show_in_website>1</show_in_website>
843
+ <show_in_store>1</show_in_store>
844
+ </enable>
845
+ <recommendation_label translate="label">
846
+ <label>Recommendation area label</label>
847
+ <frontend_type>text</frontend_type>
848
+ <sort_order>5</sort_order>
849
+ <show_in_default>1</show_in_default>
850
+ <show_in_website>1</show_in_website>
851
+ <show_in_store>1</show_in_store>
852
+ <depends>
853
+ <enable>1</enable>
854
+ </depends>
855
+ </recommendation_label>
856
+ <recommendation_config translate="label">
857
+ <label>Recommendation configuration</label>
858
+ <frontend_type>select</frontend_type>
859
+ <source_model>affinityitems/source_recoconfig::cart</source_model>
860
+ <sort_order>12</sort_order>
861
+ <show_in_default>1</show_in_default>
862
+ <show_in_website>1</show_in_website>
863
+ <show_in_store>1</show_in_store>
864
+ <depends>
865
+ <enable>1</enable>
866
+ </depends>
867
+ </recommendation_config>
868
+ <number_products translate="label">
869
+ <label>Number of displayed products</label>
870
+ <frontend_type>text</frontend_type>
871
+ <sort_order>10</sort_order>
872
+ <show_in_default>1</show_in_default>
873
+ <show_in_website>1</show_in_website>
874
+ <show_in_store>1</show_in_store>
875
+ <depends>
876
+ <enable>1</enable>
877
+ </depends>
878
+ </number_products>
879
+ <number_products_per_line translate="label">
880
+ <label>Number of displayed products per line</label>
881
+ <frontend_type>text</frontend_type>
882
+ <sort_order>12</sort_order>
883
+ <show_in_default>1</show_in_default>
884
+ <show_in_website>1</show_in_website>
885
+ <show_in_store>1</show_in_store>
886
+ <depends>
887
+ <enable>1</enable>
888
+ </depends>
889
+ </number_products_per_line>
890
+ <image_size translate="label">
891
+ <label>Image size</label>
892
+ <frontend_type>select</frontend_type>
893
+ <source_model>affinityitems/source_imagesize</source_model>
894
+ <sort_order>15</sort_order>
895
+ <show_in_default>1</show_in_default>
896
+ <show_in_website>1</show_in_website>
897
+ <show_in_store>1</show_in_store>
898
+ <depends>
899
+ <enable>1</enable>
900
+ </depends>
901
+ </image_size>
902
+ <display_settings>
903
+ <label><![CDATA[<strong>Display settings</strong>]]></label>
904
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
905
+ <sort_order>60</sort_order>
906
+ <show_in_default>1</show_in_default>
907
+ <show_in_website>1</show_in_website>
908
+ <show_in_store>1</show_in_store>
909
+ <depends>
910
+ <enable>1</enable>
911
+ </depends>
912
+ </display_settings>
913
+ <parent_div translate="label">
914
+ <label><![CDATA[Parent <strong>&lt;div&gt;</strong>]]></label>
915
+ <frontend_type>text</frontend_type>
916
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
917
+ <sort_order>65</sort_order>
918
+ <show_in_default>1</show_in_default>
919
+ <show_in_website>1</show_in_website>
920
+ <show_in_store>1</show_in_store>
921
+ <depends>
922
+ <enable>1</enable>
923
+ </depends>
924
+ </parent_div>
925
+ <title_class translate="label">
926
+ <label><![CDATA[&nbsp;&nbsp;Title <strong>class</strong>]]></label>
927
+ <frontend_type>text</frontend_type>
928
+ <sort_order>70</sort_order>
929
+ <show_in_default>1</show_in_default>
930
+ <show_in_website>1</show_in_website>
931
+ <show_in_store>1</show_in_store>
932
+ <depends>
933
+ <enable>1</enable>
934
+ </depends>
935
+ </title_class>
936
+ <content_div translate="label">
937
+ <label><![CDATA[&nbsp;&nbsp;Content <strong>&lt;div&gt;</strong>]]></label>
938
+ <frontend_type>text</frontend_type>
939
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
940
+ <sort_order>75</sort_order>
941
+ <show_in_default>1</show_in_default>
942
+ <show_in_website>1</show_in_website>
943
+ <show_in_store>1</show_in_store>
944
+ <depends>
945
+ <enable>1</enable>
946
+ </depends>
947
+ </content_div>
948
+ <ul translate="label">
949
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;List <strong>&lt;ul&gt;</strong>]]></label>
950
+ <frontend_type>text</frontend_type>
951
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
952
+ <sort_order>80</sort_order>
953
+ <show_in_default>1</show_in_default>
954
+ <show_in_website>1</show_in_website>
955
+ <show_in_store>1</show_in_store>
956
+ <depends>
957
+ <enable>1</enable>
958
+ </depends>
959
+ </ul>
960
+ <li translate="label">
961
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List element <strong>&lt;li&gt;</strong>]]></label>
962
+ <frontend_type>text</frontend_type>
963
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
964
+ <sort_order>85</sort_order>
965
+ <show_in_default>1</show_in_default>
966
+ <show_in_website>1</show_in_website>
967
+ <show_in_store>1</show_in_store>
968
+ <depends>
969
+ <enable>1</enable>
970
+ </depends>
971
+ </li>
972
+ <product_image_class translate="label">
973
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product image class]]></label>
974
+ <frontend_type>text</frontend_type>
975
+ <sort_order>90</sort_order>
976
+ <show_in_default>1</show_in_default>
977
+ <show_in_website>1</show_in_website>
978
+ <show_in_store>1</show_in_store>
979
+ <depends>
980
+ <enable>1</enable>
981
+ </depends>
982
+ </product_image_class>
983
+ <product_name_class translate="label">
984
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product name class]]></label>
985
+ <frontend_type>text</frontend_type>
986
+ <sort_order>95</sort_order>
987
+ <show_in_default>1</show_in_default>
988
+ <show_in_website>1</show_in_website>
989
+ <show_in_store>1</show_in_store>
990
+ <depends>
991
+ <enable>1</enable>
992
+ </depends>
993
+ </product_name_class>
994
+ <product_dsecription_class translate="label">
995
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product description class]]></label>
996
+ <frontend_type>text</frontend_type>
997
+ <sort_order>100</sort_order>
998
+ <show_in_default>1</show_in_default>
999
+ <show_in_website>1</show_in_website>
1000
+ <show_in_store>1</show_in_store>
1001
+ <depends>
1002
+ <enable>1</enable>
1003
+ </depends>
1004
+ </product_dsecription_class>
1005
+ <price_container_class translate="label">
1006
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price container class]]></label>
1007
+ <frontend_type>text</frontend_type>
1008
+ <sort_order>105</sort_order>
1009
+ <show_in_default>1</show_in_default>
1010
+ <show_in_website>1</show_in_website>
1011
+ <show_in_store>1</show_in_store>
1012
+ <depends>
1013
+ <enable>1</enable>
1014
+ </depends>
1015
+ </price_container_class>
1016
+ <price_class translate="label">
1017
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price class]]></label>
1018
+ <frontend_type>text</frontend_type>
1019
+ <sort_order>110</sort_order>
1020
+ <show_in_default>1</show_in_default>
1021
+ <show_in_website>1</show_in_website>
1022
+ <show_in_store>1</show_in_store>
1023
+ <depends>
1024
+ <enable>1</enable>
1025
+ </depends>
1026
+ </price_class>
1027
+ </fields>
1028
+ </items_cart>
1029
+
1030
+ <items_product translate="label" module="affinityitems">
1031
+ <label>Product page</label>
1032
+ <frontend_type>text</frontend_type>
1033
+ <sort_order>50</sort_order>
1034
+ <show_in_default>1</show_in_default>
1035
+ <show_in_website>1</show_in_website>
1036
+ <show_in_store>1</show_in_store>
1037
+ <fields>
1038
+ <enable translate="label">
1039
+ <label>Enable</label>
1040
+ <frontend_type>select</frontend_type>
1041
+ <source_model>adminhtml/system_config_source_yesno</source_model>
1042
+ <sort_order>0</sort_order>
1043
+ <show_in_default>1</show_in_default>
1044
+ <show_in_website>1</show_in_website>
1045
+ <show_in_store>1</show_in_store>
1046
+ </enable>
1047
+ <recommendation_label translate="label">
1048
+ <label>Recommendation area label</label>
1049
+ <frontend_type>text</frontend_type>
1050
+ <sort_order>5</sort_order>
1051
+ <show_in_default>1</show_in_default>
1052
+ <show_in_website>1</show_in_website>
1053
+ <show_in_store>1</show_in_store>
1054
+ <depends>
1055
+ <enable>1</enable>
1056
+ </depends>
1057
+ </recommendation_label>
1058
+ <recommendation_config translate="label">
1059
+ <label>Recommendation configuration</label>
1060
+ <frontend_type>select</frontend_type>
1061
+ <source_model>affinityitems/source_recoconfig::product</source_model>
1062
+ <sort_order>12</sort_order>
1063
+ <show_in_default>1</show_in_default>
1064
+ <show_in_website>1</show_in_website>
1065
+ <show_in_store>1</show_in_store>
1066
+ <depends>
1067
+ <enable>1</enable>
1068
+ </depends>
1069
+ </recommendation_config>
1070
+ <number_products translate="label">
1071
+ <label>Number of displayed products</label>
1072
+ <frontend_type>text</frontend_type>
1073
+ <sort_order>10</sort_order>
1074
+ <show_in_default>1</show_in_default>
1075
+ <show_in_website>1</show_in_website>
1076
+ <show_in_store>1</show_in_store>
1077
+ <depends>
1078
+ <enable>1</enable>
1079
+ </depends>
1080
+ </number_products>
1081
+ <number_products_per_line translate="label">
1082
+ <label>Number of displayed products per line</label>
1083
+ <frontend_type>text</frontend_type>
1084
+ <sort_order>12</sort_order>
1085
+ <show_in_default>1</show_in_default>
1086
+ <show_in_website>1</show_in_website>
1087
+ <show_in_store>1</show_in_store>
1088
+ <depends>
1089
+ <enable>1</enable>
1090
+ </depends>
1091
+ </number_products_per_line>
1092
+ <image_size translate="label">
1093
+ <label>Image size</label>
1094
+ <frontend_type>select</frontend_type>
1095
+ <source_model>affinityitems/source_imagesize</source_model>
1096
+ <sort_order>15</sort_order>
1097
+ <show_in_default>1</show_in_default>
1098
+ <show_in_website>1</show_in_website>
1099
+ <show_in_store>1</show_in_store>
1100
+ <depends>
1101
+ <enable>1</enable>
1102
+ </depends>
1103
+ </image_size>
1104
+ <display_settings>
1105
+ <label><![CDATA[<strong>Display settings</strong>]]></label>
1106
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
1107
+ <sort_order>60</sort_order>
1108
+ <show_in_default>1</show_in_default>
1109
+ <show_in_website>1</show_in_website>
1110
+ <show_in_store>1</show_in_store>
1111
+ <depends>
1112
+ <enable>1</enable>
1113
+ </depends>
1114
+ </display_settings>
1115
+ <parent_div translate="label">
1116
+ <label><![CDATA[Parent <strong>&lt;div&gt;</strong>]]></label>
1117
+ <frontend_type>text</frontend_type>
1118
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1119
+ <sort_order>65</sort_order>
1120
+ <show_in_default>1</show_in_default>
1121
+ <show_in_website>1</show_in_website>
1122
+ <show_in_store>1</show_in_store>
1123
+ <depends>
1124
+ <enable>1</enable>
1125
+ </depends>
1126
+ </parent_div>
1127
+ <title_class translate="label">
1128
+ <label><![CDATA[&nbsp;&nbsp;Title <strong>class</strong>]]></label>
1129
+ <frontend_type>text</frontend_type>
1130
+ <sort_order>70</sort_order>
1131
+ <show_in_default>1</show_in_default>
1132
+ <show_in_website>1</show_in_website>
1133
+ <show_in_store>1</show_in_store>
1134
+ <depends>
1135
+ <enable>1</enable>
1136
+ </depends>
1137
+ </title_class>
1138
+ <content_div translate="label">
1139
+ <label><![CDATA[&nbsp;&nbsp;Content <strong>&lt;div&gt;</strong>]]></label>
1140
+ <frontend_type>text</frontend_type>
1141
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1142
+ <sort_order>75</sort_order>
1143
+ <show_in_default>1</show_in_default>
1144
+ <show_in_website>1</show_in_website>
1145
+ <show_in_store>1</show_in_store>
1146
+ <depends>
1147
+ <enable>1</enable>
1148
+ </depends>
1149
+ </content_div>
1150
+ <ul translate="label">
1151
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;List <strong>&lt;ul&gt;</strong>]]></label>
1152
+ <frontend_type>text</frontend_type>
1153
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1154
+ <sort_order>80</sort_order>
1155
+ <show_in_default>1</show_in_default>
1156
+ <show_in_website>1</show_in_website>
1157
+ <show_in_store>1</show_in_store>
1158
+ <depends>
1159
+ <enable>1</enable>
1160
+ </depends>
1161
+ </ul>
1162
+ <li translate="label">
1163
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List element <strong>&lt;li&gt;</strong>]]></label>
1164
+ <frontend_type>text</frontend_type>
1165
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1166
+ <sort_order>85</sort_order>
1167
+ <show_in_default>1</show_in_default>
1168
+ <show_in_website>1</show_in_website>
1169
+ <show_in_store>1</show_in_store>
1170
+ <depends>
1171
+ <enable>1</enable>
1172
+ </depends>
1173
+ </li>
1174
+ <product_image_class translate="label">
1175
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product image class]]></label>
1176
+ <frontend_type>text</frontend_type>
1177
+ <sort_order>90</sort_order>
1178
+ <show_in_default>1</show_in_default>
1179
+ <show_in_website>1</show_in_website>
1180
+ <show_in_store>1</show_in_store>
1181
+ <depends>
1182
+ <enable>1</enable>
1183
+ </depends>
1184
+ </product_image_class>
1185
+ <product_name_class translate="label">
1186
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product name class]]></label>
1187
+ <frontend_type>text</frontend_type>
1188
+ <sort_order>95</sort_order>
1189
+ <show_in_default>1</show_in_default>
1190
+ <show_in_website>1</show_in_website>
1191
+ <show_in_store>1</show_in_store>
1192
+ <depends>
1193
+ <enable>1</enable>
1194
+ </depends>
1195
+ </product_name_class>
1196
+ <product_dsecription_class translate="label">
1197
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product description class]]></label>
1198
+ <frontend_type>text</frontend_type>
1199
+ <sort_order>100</sort_order>
1200
+ <show_in_default>1</show_in_default>
1201
+ <show_in_website>1</show_in_website>
1202
+ <show_in_store>1</show_in_store>
1203
+ <depends>
1204
+ <enable>1</enable>
1205
+ </depends>
1206
+ </product_dsecription_class>
1207
+ <price_container_class translate="label">
1208
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price container class]]></label>
1209
+ <frontend_type>text</frontend_type>
1210
+ <sort_order>105</sort_order>
1211
+ <show_in_default>1</show_in_default>
1212
+ <show_in_website>1</show_in_website>
1213
+ <show_in_store>1</show_in_store>
1214
+ <depends>
1215
+ <enable>1</enable>
1216
+ </depends>
1217
+ </price_container_class>
1218
+ <price_class translate="label">
1219
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price class]]></label>
1220
+ <frontend_type>text</frontend_type>
1221
+ <sort_order>110</sort_order>
1222
+ <show_in_default>1</show_in_default>
1223
+ <show_in_website>1</show_in_website>
1224
+ <show_in_store>1</show_in_store>
1225
+ <depends>
1226
+ <enable>1</enable>
1227
+ </depends>
1228
+ </price_class>
1229
+ </fields>
1230
+ </items_product>
1231
+
1232
+ <items_search translate="label" module="affinityitems">
1233
+ <label>Search page</label>
1234
+ <frontend_type>text</frontend_type>
1235
+ <sort_order>60</sort_order>
1236
+ <show_in_default>1</show_in_default>
1237
+ <show_in_website>1</show_in_website>
1238
+ <show_in_store>1</show_in_store>
1239
+ <fields>
1240
+ <enable translate="label">
1241
+ <label>Enable</label>
1242
+ <frontend_type>select</frontend_type>
1243
+ <source_model>adminhtml/system_config_source_yesno</source_model>
1244
+ <sort_order>0</sort_order>
1245
+ <show_in_default>1</show_in_default>
1246
+ <show_in_website>1</show_in_website>
1247
+ <show_in_store>1</show_in_store>
1248
+ </enable>
1249
+ <recommendation_label translate="label">
1250
+ <label>Recommendation area label</label>
1251
+ <frontend_type>text</frontend_type>
1252
+ <sort_order>5</sort_order>
1253
+ <show_in_default>1</show_in_default>
1254
+ <show_in_website>1</show_in_website>
1255
+ <show_in_store>1</show_in_store>
1256
+ <depends>
1257
+ <enable>1</enable>
1258
+ </depends>
1259
+ </recommendation_label>
1260
+ <recommendation_config translate="label">
1261
+ <label>Recommendation configuration</label>
1262
+ <frontend_type>select</frontend_type>
1263
+ <source_model>affinityitems/source_recoconfig::search</source_model>
1264
+ <sort_order>12</sort_order>
1265
+ <show_in_default>1</show_in_default>
1266
+ <show_in_website>1</show_in_website>
1267
+ <show_in_store>1</show_in_store>
1268
+ <depends>
1269
+ <enable>1</enable>
1270
+ </depends>
1271
+ </recommendation_config>
1272
+ <number_products translate="label">
1273
+ <label>Number of displayed products</label>
1274
+ <frontend_type>text</frontend_type>
1275
+ <sort_order>10</sort_order>
1276
+ <show_in_default>1</show_in_default>
1277
+ <show_in_website>1</show_in_website>
1278
+ <show_in_store>1</show_in_store>
1279
+ <depends>
1280
+ <enable>1</enable>
1281
+ </depends>
1282
+ </number_products>
1283
+ <number_products_per_line translate="label">
1284
+ <label>Number of displayed products per line</label>
1285
+ <frontend_type>text</frontend_type>
1286
+ <sort_order>12</sort_order>
1287
+ <show_in_default>1</show_in_default>
1288
+ <show_in_website>1</show_in_website>
1289
+ <show_in_store>1</show_in_store>
1290
+ <depends>
1291
+ <enable>1</enable>
1292
+ </depends>
1293
+ </number_products_per_line>
1294
+ <image_size translate="label">
1295
+ <label>Image size</label>
1296
+ <frontend_type>select</frontend_type>
1297
+ <source_model>affinityitems/source_imagesize</source_model>
1298
+ <sort_order>15</sort_order>
1299
+ <show_in_default>1</show_in_default>
1300
+ <show_in_website>1</show_in_website>
1301
+ <show_in_store>1</show_in_store>
1302
+ <depends>
1303
+ <enable>1</enable>
1304
+ </depends>
1305
+ </image_size>
1306
+ <display_settings>
1307
+ <label><![CDATA[<strong>Display settings</strong>]]></label>
1308
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
1309
+ <sort_order>60</sort_order>
1310
+ <show_in_default>1</show_in_default>
1311
+ <show_in_website>1</show_in_website>
1312
+ <show_in_store>1</show_in_store>
1313
+ <depends>
1314
+ <enable>1</enable>
1315
+ </depends>
1316
+ </display_settings>
1317
+ <parent_div translate="label">
1318
+ <label><![CDATA[Parent <strong>&lt;div&gt;</strong>]]></label>
1319
+ <frontend_type>text</frontend_type>
1320
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1321
+ <sort_order>65</sort_order>
1322
+ <show_in_default>1</show_in_default>
1323
+ <show_in_website>1</show_in_website>
1324
+ <show_in_store>1</show_in_store>
1325
+ <depends>
1326
+ <enable>1</enable>
1327
+ </depends>
1328
+ </parent_div>
1329
+ <title_class translate="label">
1330
+ <label><![CDATA[&nbsp;&nbsp;Title <strong>class</strong>]]></label>
1331
+ <frontend_type>text</frontend_type>
1332
+ <sort_order>70</sort_order>
1333
+ <show_in_default>1</show_in_default>
1334
+ <show_in_website>1</show_in_website>
1335
+ <show_in_store>1</show_in_store>
1336
+ <depends>
1337
+ <enable>1</enable>
1338
+ </depends>
1339
+ </title_class>
1340
+ <content_div translate="label">
1341
+ <label><![CDATA[&nbsp;&nbsp;Content <strong>&lt;div&gt;</strong>]]></label>
1342
+ <frontend_type>text</frontend_type>
1343
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1344
+ <sort_order>75</sort_order>
1345
+ <show_in_default>1</show_in_default>
1346
+ <show_in_website>1</show_in_website>
1347
+ <show_in_store>1</show_in_store>
1348
+ <depends>
1349
+ <enable>1</enable>
1350
+ </depends>
1351
+ </content_div>
1352
+ <ul translate="label">
1353
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;List <strong>&lt;ul&gt;</strong>]]></label>
1354
+ <frontend_type>text</frontend_type>
1355
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1356
+ <sort_order>80</sort_order>
1357
+ <show_in_default>1</show_in_default>
1358
+ <show_in_website>1</show_in_website>
1359
+ <show_in_store>1</show_in_store>
1360
+ <depends>
1361
+ <enable>1</enable>
1362
+ </depends>
1363
+ </ul>
1364
+ <li translate="label">
1365
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List element <strong>&lt;li&gt;</strong>]]></label>
1366
+ <frontend_type>text</frontend_type>
1367
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1368
+ <sort_order>85</sort_order>
1369
+ <show_in_default>1</show_in_default>
1370
+ <show_in_website>1</show_in_website>
1371
+ <show_in_store>1</show_in_store>
1372
+ <depends>
1373
+ <enable>1</enable>
1374
+ </depends>
1375
+ </li>
1376
+ <product_image_class translate="label">
1377
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product image class]]></label>
1378
+ <frontend_type>text</frontend_type>
1379
+ <sort_order>90</sort_order>
1380
+ <show_in_default>1</show_in_default>
1381
+ <show_in_website>1</show_in_website>
1382
+ <show_in_store>1</show_in_store>
1383
+ <depends>
1384
+ <enable>1</enable>
1385
+ </depends>
1386
+ </product_image_class>
1387
+ <product_name_class translate="label">
1388
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product name class]]></label>
1389
+ <frontend_type>text</frontend_type>
1390
+ <sort_order>95</sort_order>
1391
+ <show_in_default>1</show_in_default>
1392
+ <show_in_website>1</show_in_website>
1393
+ <show_in_store>1</show_in_store>
1394
+ <depends>
1395
+ <enable>1</enable>
1396
+ </depends>
1397
+ </product_name_class>
1398
+ <product_dsecription_class translate="label">
1399
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product description class]]></label>
1400
+ <frontend_type>text</frontend_type>
1401
+ <sort_order>100</sort_order>
1402
+ <show_in_default>1</show_in_default>
1403
+ <show_in_website>1</show_in_website>
1404
+ <show_in_store>1</show_in_store>
1405
+ <depends>
1406
+ <enable>1</enable>
1407
+ </depends>
1408
+ </product_dsecription_class>
1409
+ <price_container_class translate="label">
1410
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price container class]]></label>
1411
+ <frontend_type>text</frontend_type>
1412
+ <sort_order>105</sort_order>
1413
+ <show_in_default>1</show_in_default>
1414
+ <show_in_website>1</show_in_website>
1415
+ <show_in_store>1</show_in_store>
1416
+ <depends>
1417
+ <enable>1</enable>
1418
+ </depends>
1419
+ </price_container_class>
1420
+ <price_class translate="label">
1421
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price class]]></label>
1422
+ <frontend_type>text</frontend_type>
1423
+ <sort_order>110</sort_order>
1424
+ <show_in_default>1</show_in_default>
1425
+ <show_in_website>1</show_in_website>
1426
+ <show_in_store>1</show_in_store>
1427
+ <depends>
1428
+ <enable>1</enable>
1429
+ </depends>
1430
+ </price_class>
1431
+ </fields>
1432
+ </items_search>
1433
+
1434
+ <items_category translate="label" module="affinityitems">
1435
+ <label>Category page</label>
1436
+ <frontend_type>text</frontend_type>
1437
+ <sort_order>70</sort_order>
1438
+ <show_in_default>1</show_in_default>
1439
+ <show_in_website>1</show_in_website>
1440
+ <show_in_store>1</show_in_store>
1441
+ <fields>
1442
+ <enable translate="label">
1443
+ <label>Enable</label>
1444
+ <frontend_type>select</frontend_type>
1445
+ <source_model>adminhtml/system_config_source_yesno</source_model>
1446
+ <sort_order>0</sort_order>
1447
+ <show_in_default>1</show_in_default>
1448
+ <show_in_website>1</show_in_website>
1449
+ <show_in_store>1</show_in_store>
1450
+ </enable>
1451
+ <recommendation_label translate="label">
1452
+ <label>Recommendation area label</label>
1453
+ <frontend_type>text</frontend_type>
1454
+ <sort_order>5</sort_order>
1455
+ <show_in_default>1</show_in_default>
1456
+ <show_in_website>1</show_in_website>
1457
+ <show_in_store>1</show_in_store>
1458
+ <depends>
1459
+ <enable>1</enable>
1460
+ </depends>
1461
+ </recommendation_label>
1462
+ <recommendation_config translate="label">
1463
+ <label>Recommendation configuration</label>
1464
+ <frontend_type>select</frontend_type>
1465
+ <source_model>affinityitems/source_recoconfig::category</source_model>
1466
+ <sort_order>12</sort_order>
1467
+ <show_in_default>1</show_in_default>
1468
+ <show_in_website>1</show_in_website>
1469
+ <show_in_store>1</show_in_store>
1470
+ <depends>
1471
+ <enable>1</enable>
1472
+ </depends>
1473
+ </recommendation_config>
1474
+ <number_products translate="label">
1475
+ <label>Number of displayed products</label>
1476
+ <frontend_type>text</frontend_type>
1477
+ <sort_order>10</sort_order>
1478
+ <show_in_default>1</show_in_default>
1479
+ <show_in_website>1</show_in_website>
1480
+ <show_in_store>1</show_in_store>
1481
+ <depends>
1482
+ <enable>1</enable>
1483
+ </depends>
1484
+ </number_products>
1485
+ <number_products_per_line translate="label">
1486
+ <label>Number of displayed products per line</label>
1487
+ <frontend_type>text</frontend_type>
1488
+ <sort_order>12</sort_order>
1489
+ <show_in_default>1</show_in_default>
1490
+ <show_in_website>1</show_in_website>
1491
+ <show_in_store>1</show_in_store>
1492
+ <depends>
1493
+ <enable>1</enable>
1494
+ </depends>
1495
+ </number_products_per_line>
1496
+ <image_size translate="label">
1497
+ <label>Image size</label>
1498
+ <frontend_type>select</frontend_type>
1499
+ <source_model>affinityitems/source_imagesize</source_model>
1500
+ <sort_order>15</sort_order>
1501
+ <show_in_default>1</show_in_default>
1502
+ <show_in_website>1</show_in_website>
1503
+ <show_in_store>1</show_in_store>
1504
+ <depends>
1505
+ <enable>1</enable>
1506
+ </depends>
1507
+ </image_size>
1508
+ <display_settings>
1509
+ <label><![CDATA[<strong>Display settings</strong>]]></label>
1510
+ <frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
1511
+ <sort_order>60</sort_order>
1512
+ <show_in_default>1</show_in_default>
1513
+ <show_in_website>1</show_in_website>
1514
+ <show_in_store>1</show_in_store>
1515
+ <depends>
1516
+ <enable>1</enable>
1517
+ </depends>
1518
+ </display_settings>
1519
+ <parent_div translate="label">
1520
+ <label><![CDATA[Parent <strong>&lt;div&gt;</strong>]]></label>
1521
+ <frontend_type>text</frontend_type>
1522
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1523
+ <sort_order>65</sort_order>
1524
+ <show_in_default>1</show_in_default>
1525
+ <show_in_website>1</show_in_website>
1526
+ <show_in_store>1</show_in_store>
1527
+ <depends>
1528
+ <enable>1</enable>
1529
+ </depends>
1530
+ </parent_div>
1531
+ <title_class translate="label">
1532
+ <label><![CDATA[&nbsp;&nbsp;Title <strong>class</strong>]]></label>
1533
+ <frontend_type>text</frontend_type>
1534
+ <sort_order>70</sort_order>
1535
+ <show_in_default>1</show_in_default>
1536
+ <show_in_website>1</show_in_website>
1537
+ <show_in_store>1</show_in_store>
1538
+ <depends>
1539
+ <enable>1</enable>
1540
+ </depends>
1541
+ </title_class>
1542
+ <content_div translate="label">
1543
+ <label><![CDATA[&nbsp;&nbsp;Content <strong>&lt;div&gt;</strong>]]></label>
1544
+ <frontend_type>text</frontend_type>
1545
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1546
+ <sort_order>75</sort_order>
1547
+ <show_in_default>1</show_in_default>
1548
+ <show_in_website>1</show_in_website>
1549
+ <show_in_store>1</show_in_store>
1550
+ <depends>
1551
+ <enable>1</enable>
1552
+ </depends>
1553
+ </content_div>
1554
+ <ul translate="label">
1555
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;List <strong>&lt;ul&gt;</strong>]]></label>
1556
+ <frontend_type>text</frontend_type>
1557
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1558
+ <sort_order>80</sort_order>
1559
+ <show_in_default>1</show_in_default>
1560
+ <show_in_website>1</show_in_website>
1561
+ <show_in_store>1</show_in_store>
1562
+ <depends>
1563
+ <enable>1</enable>
1564
+ </depends>
1565
+ </ul>
1566
+ <li translate="label">
1567
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List element <strong>&lt;li&gt;</strong>]]></label>
1568
+ <frontend_type>text</frontend_type>
1569
+ <frontend_model>affinityitems/renderer_config_classes</frontend_model>
1570
+ <sort_order>85</sort_order>
1571
+ <show_in_default>1</show_in_default>
1572
+ <show_in_website>1</show_in_website>
1573
+ <show_in_store>1</show_in_store>
1574
+ <depends>
1575
+ <enable>1</enable>
1576
+ </depends>
1577
+ </li>
1578
+ <product_image_class translate="label">
1579
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product image class]]></label>
1580
+ <frontend_type>text</frontend_type>
1581
+ <sort_order>90</sort_order>
1582
+ <show_in_default>1</show_in_default>
1583
+ <show_in_website>1</show_in_website>
1584
+ <show_in_store>1</show_in_store>
1585
+ <depends>
1586
+ <enable>1</enable>
1587
+ </depends>
1588
+ </product_image_class>
1589
+ <product_name_class translate="label">
1590
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product name class]]></label>
1591
+ <frontend_type>text</frontend_type>
1592
+ <sort_order>95</sort_order>
1593
+ <show_in_default>1</show_in_default>
1594
+ <show_in_website>1</show_in_website>
1595
+ <show_in_store>1</show_in_store>
1596
+ <depends>
1597
+ <enable>1</enable>
1598
+ </depends>
1599
+ </product_name_class>
1600
+ <product_dsecription_class translate="label">
1601
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Product description class]]></label>
1602
+ <frontend_type>text</frontend_type>
1603
+ <sort_order>100</sort_order>
1604
+ <show_in_default>1</show_in_default>
1605
+ <show_in_website>1</show_in_website>
1606
+ <show_in_store>1</show_in_store>
1607
+ <depends>
1608
+ <enable>1</enable>
1609
+ </depends>
1610
+ </product_dsecription_class>
1611
+ <price_container_class translate="label">
1612
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price container class]]></label>
1613
+ <frontend_type>text</frontend_type>
1614
+ <sort_order>105</sort_order>
1615
+ <show_in_default>1</show_in_default>
1616
+ <show_in_website>1</show_in_website>
1617
+ <show_in_store>1</show_in_store>
1618
+ <depends>
1619
+ <enable>1</enable>
1620
+ </depends>
1621
+ </price_container_class>
1622
+ <price_class translate="label">
1623
+ <label><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price class]]></label>
1624
+ <frontend_type>text</frontend_type>
1625
+ <sort_order>110</sort_order>
1626
+ <show_in_default>1</show_in_default>
1627
+ <show_in_website>1</show_in_website>
1628
+ <show_in_store>1</show_in_store>
1629
+ <depends>
1630
+ <enable>1</enable>
1631
+ </depends>
1632
+ </price_class>
1633
+ </fields>
1634
+ </items_category>
1635
+
1636
+ </groups>
1637
+ </affinityitems>
1638
+ </sections>
1639
+ </config>
app/code/local/AffinityEngine/AffinityItems/sql/affinityitems_setup/mysql4-install-1.0.0.php ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+ $installer->startSetup();
5
+
6
+ $sql = 'CREATE TABLE IF NOT EXISTS `' . $this->getTable('ae_log') . '` (
7
+ `id_log` int(16) NOT NULL AUTO_INCREMENT,
8
+ `date_add` DATETIME NOT NULL,
9
+ `severity` VARCHAR(50) NOT NULL,
10
+ `message` LONGTEXT NOT NULL,
11
+ PRIMARY KEY (`id_log`)
12
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;';
13
+
14
+ $installer->run($sql);
15
+
16
+ $sql = 'CREATE TABLE IF NOT EXISTS `' . $this->getTable('ae_cart_repository') . '` (
17
+ `id` int(11) NOT NULL AUTO_INCREMENT,
18
+ `id_cart` int(16) DEFAULT NULL,
19
+ `id_product` int(16) DEFAULT NULL,
20
+ `id_product_attribute` varchar(50) DEFAULT NULL,
21
+ `quantity` int(16) DEFAULT NULL,
22
+ `date_add` datetime DEFAULT NULL,
23
+ `action` varchar(50) DEFAULT NULL,
24
+ `aeguestid` varchar(100) DEFAULT NULL,
25
+ `aememberid` varchar(200) DEFAULT "",
26
+ `language` varchar(10) DEFAULT "",
27
+ `aegroup` varchar(10) DEFAULT NULL,
28
+ `ip` varchar(100) DEFAULT "",
29
+ PRIMARY KEY (`id`)
30
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;';
31
+
32
+ $installer->run($sql);
33
+
34
+ $sql = 'CREATE TABLE IF NOT EXISTS `' . $this->getTable('ae_guest_action_repository') . '` (
35
+ `id` int(11) NOT NULL AUTO_INCREMENT,
36
+ `product_id` int(11) NOT NULL DEFAULT 0,
37
+ `category_id` int(11) NOT NULL DEFAULT 0,
38
+ `ae_guest` varchar(200) NOT NULL,
39
+ `ae_member` varchar(200) DEFAULT "",
40
+ `ae_action` varchar(100) NOT NULL,
41
+ `ae_group` varchar(10) NOT NULL,
42
+ `rec_type` varchar(100) NOT NULL,
43
+ `language` varchar(10) DEFAULT "",
44
+ `ip` varchar(100) DEFAULT "",
45
+ PRIMARY KEY (`id`)
46
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;';
47
+
48
+ $installer->run($sql);
49
+
50
+ $sql = 'CREATE TABLE IF NOT EXISTS `' . $this->getTable('ae_sync_rotate') . '` (
51
+ `id` int(16) NOT NULL,
52
+ `last_sync` VARCHAR(10) NOT NULL,
53
+ `date_add` DATE NULL,
54
+ `initial_sync` INT NULL DEFAULT "1",
55
+ PRIMARY KEY(id)
56
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;';
57
+
58
+ $installer->run($sql);
59
+
60
+ $sql = 'CREATE TABLE IF NOT EXISTS `ae_cat_prod_repository` (
61
+ `id` int(11) NOT NULL AUTO_INCREMENT,
62
+ `obj_id` text NOT NULL,
63
+ `obj_type` text NOT NULL,
64
+ PRIMARY KEY (`id`)
65
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;';
66
+
67
+ $installer->run($sql);
68
+
69
+ $sql = "INSERT INTO `" . $this->getTable('ae_sync_rotate') . "` (`id`, `last_sync`, `date_add`) VALUES (0, 'actions', '2014-01-01');";
70
+ $installer->run($sql);
71
+
72
+ // define defaults in system config
73
+
74
+ $xml_path = array('items_home', 'items_left', 'items_right', 'items_cart', 'items_product', 'items_search', 'items_category');
75
+ foreach ($xml_path as $path) {
76
+ $sql = "INSERT INTO `" . $this->getTable('core_config_data') . "` (`config_id`, `scope`, `scope_id`, `path`, `value`)
77
+ VALUES
78
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/number_products', '4'),
79
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/number_products_per_line', '4'),
80
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/recommendation_config', 'personalization'),
81
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/image_size', '0'),
82
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/parent_div', ',ae_products_block_center clearfix'),
83
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/title_class', 'ae_block_title_center'),
84
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/content_div', ',ae_content_block_center'),
85
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/ul', ',ae_list_products_block_center'),
86
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/li', ',ae_product_block_center'),
87
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/product_image_class', 'ae_img_center'),
88
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/product_name_class', 'ae_products_name_center'),
89
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/product_dsecription_class', 'ae_product_dsecription'),
90
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/price_container_class', 'ae_price_container_center'),
91
+ (NULL, 'default', '0', 'affinityitems/" . $path . "/price_class', 'ae_price_center');";
92
+ $installer->run($sql);
93
+ }
94
+
95
+ $sql = "INSERT INTO `" . $this->getTable('core_config_data') . "` (`config_id`, `scope`, `scope_id`, `path`, `value`)
96
+ VALUES
97
+ (NULL, 'default', '0', 'affinityitems/security/login', ''),
98
+ (NULL, 'default', '0', 'affinityitems/security/password', ''),
99
+ (NULL, 'default', '0', 'affinityitems/security/site_id', ''),
100
+ (NULL, 'default', '0', 'affinityitems/security/key', ''),
101
+ (NULL, 'default', '0', 'affinityitems/security/conf_test_host', 'json.approval.v1.0.affinityitems.com'),
102
+ (NULL, 'default', '0', 'affinityitems/security/conf_prod_host', 'json.production.affinityitems.com'),
103
+ (NULL, 'default', '0', 'affinityitems/security/conf_port', '80'),
104
+ (NULL, 'default', '0', 'affinityitems/general/dev_prod','0'),
105
+ (NULL, 'default', '0', 'affinityitems/general/dev_prod_rel','0'),
106
+ (NULL, 'default', '0', 'affinityitems/image_size/default', '125,125'),
107
+ (NULL, 'default', '0', 'affinityitems/image_size/large', '458,458'),
108
+ (NULL, 'default', '0', 'affinityitems/image_size/medium', '250,250'),
109
+ (NULL, 'default', '0', 'affinityitems/image_size/small', '98,98'),
110
+ (NULL, 'default', '0', 'affinityitems/advanced/sync_count', '300'),
111
+ (NULL, 'default', '0', 'affinityitems/advanced/ae_css', ''),
112
+ (NULL, 'default', '0', 'affinityitems/advanced/ae_tracking_js', 0),
113
+ (NULL, 'default', '0', 'affinityitems/developer/log_level','3'),
114
+ (NULL, 'default', '0', 'affinityitems/general/guest_percentage', '70');";
115
+
116
+ $installer->run($sql);
117
+
118
+ // add attribute to product
119
+ $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'ae_sync', array(
120
+ 'group' => 'General',
121
+ 'label' => 'AE synced',
122
+ 'type' => 'int',
123
+ 'input' => 'boolean',
124
+ 'source' => 'eav/entity_attribute_source_boolean',
125
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
126
+ 'visible' => 0,
127
+ 'required' => 0,
128
+ 'user_defined' => 0,
129
+ 'searchable' => 0,
130
+ 'filterable' => 0,
131
+ 'comparable' => 0,
132
+ 'visible_on_front' => 0,
133
+ 'visible_in_advanced_search' => 0,
134
+ 'unique' => 0,
135
+ 'default' => 0
136
+ ));
137
+
138
+ $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'ae_sync_date', array(
139
+ 'group' => 'General',
140
+ 'label' => 'AE sync date',
141
+ 'input' => 'text',
142
+ 'type' => 'text',
143
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
144
+ 'visible' => false,
145
+ 'is_visible' => false,
146
+ 'required' => 0,
147
+ 'user_defined' => 0,
148
+ 'searchable' => 0,
149
+ 'filterable' => 0,
150
+ 'comparable' => 0,
151
+ 'visible_on_front' => 0,
152
+ 'visible_in_advanced_search' => 0,
153
+ 'unique' => 0
154
+ ));
155
+
156
+ $installer->updateAttribute(Mage_Catalog_Model_Product::ENTITY,'ae_sync_date','is_visible',false);
157
+
158
+ $installer->endSetup();
159
+
160
+
161
+ // add attribute to category
162
+ $installer = new Mage_Eav_Model_Entity_Setup('core_setup');
163
+ $entityTypeId = $installer->getEntityTypeId('catalog_category');
164
+ $attributeSetId = $installer->getDefaultAttributeSetId($entityTypeId);
165
+ $attributeGroupId = $installer->getDefaultAttributeGroupId($entityTypeId, $attributeSetId);
166
+
167
+ $installer->addAttribute(Mage_Catalog_Model_Category::ENTITY, 'ae_sync', array(
168
+ 'group' => 'General Information',
169
+ 'type' => 'int',
170
+ 'label' => 'AE synced',
171
+ 'input' => 'select',
172
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
173
+ 'visible' => true,
174
+ 'required' => false,
175
+ 'user_defined' => false,
176
+ 'default' => 0,
177
+ 'source' => 'eav/entity_attribute_source_boolean'
178
+ ));
179
+
180
+ $installer->addAttribute(Mage_Catalog_Model_Category::ENTITY, 'ae_sync_date', array(
181
+ 'group' => 'General Information',
182
+ 'type' => 'text',
183
+ 'label' => 'AE sync date',
184
+ 'input' => 'text',
185
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
186
+ 'visible' => false,
187
+ 'is_visible' => false,
188
+ 'required' => false,
189
+ 'user_defined' => false
190
+ ));
191
+
192
+ $installer->updateAttribute(Mage_Catalog_Model_Category::ENTITY,'ae_sync_date','is_visible',false);
193
+
194
+ $installer->endSetup();
195
+
196
+ // add attribute to order table
197
+ $installer = new Mage_Sales_Model_Mysql4_Setup('core_setup');
198
+ $installer->addAttribute('order', 'ae_sync', array(
199
+ 'type' => 'int',
200
+ 'backend_type' => 'int',
201
+ 'is_user_defined' => true,
202
+ 'label' => 'AE synced',
203
+ 'visible' => true,
204
+ 'required' => false,
205
+ 'user_defined' => false,
206
+ 'searchable' => false,
207
+ 'filterable' => false,
208
+ 'comparable' => false,
209
+ 'default' => 0
210
+ ));
211
+ $installer->addAttribute('order', 'ae_group', array(
212
+ 'type' => 'varchar',
213
+ 'backend_type' => '',
214
+ 'is_user_defined' => true,
215
+ 'label' => 'AE group',
216
+ 'visible' => false,
217
+ 'required' => false,
218
+ 'user_defined' => false,
219
+ 'searchable' => false,
220
+ 'filterable' => false,
221
+ 'comparable' => false
222
+ ));
223
+
224
+ // add attribute to customer table
225
+ $installer = new Mage_Eav_Model_Entity_Setup('core_setup');
226
+ $entityTypeId = $installer->getEntityTypeId('customer');
227
+ $attributeSetId = $installer->getDefaultAttributeSetId($entityTypeId);
228
+ $attributeGroupId = $installer->getDefaultAttributeGroupId($entityTypeId, $attributeSetId);
229
+
230
+ $installer->addAttribute('customer', 'ae_sync', array(
231
+ 'type' => 'int',
232
+ 'backend_type' => 'int',
233
+ 'input' => 'boolean',
234
+ 'source' => 'eav/entity_attribute_source_boolean',
235
+ 'is_user_defined' => true,
236
+ 'label' => 'AE synced',
237
+ 'visible' => true,
238
+ 'required' => false,
239
+ 'user_defined' => false,
240
+ 'searchable' => false,
241
+ 'filterable' => false,
242
+ 'comparable' => false,
243
+ 'default' => 0
244
+ ));
245
+
246
+
247
+ $installer->endSetup();
app/code/local/AffinityEngine/AffinityItems/uninstall.sql ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ SET foreign_key_checks = 0;
2
+ DROP TABLE IF EXISTS `ae_cart_ab_testing`, `ae_cat_prod_repository`, `ae_cart_repository`, `ae_guest_action_repository`, `ae_log`, `ae_sync_rotate`;
3
+ DELETE FROM `eav_attribute` WHERE `eav_attribute`.`attribute_code` = "ae_sync";
4
+ DELETE FROM `eav_attribute` WHERE `eav_attribute`.`attribute_code` = "ae_sync_date";
5
+ ALTER TABLE `sales_flat_order` DROP `ae_sync`;
6
+ ALTER TABLE `sales_flat_order` DROP `ae_group`;
7
+ DELETE FROM `core_resource` WHERE `core_resource`.`code` = 'affinityitems_setup';
8
+ DELETE FROM `core_config_data` WHERE `core_config_data`.`path` LIKE "affinityitems%";
9
+ SET foreign_key_checks = 1;
app/design/adminhtml/default/default/layout/affinityitems.xml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0">
3
+ <affinityitems_adminhtml_affinityitemsbackend_index>
4
+ <reference name="content">
5
+ <block type="affinityitems/adminhtml_affinityitemsbackend" name="affinityitemsbackend">
6
+ <action method="setCacheLifetime"><s>null</s></action>
7
+ </block>
8
+ </reference>
9
+ <reference name="head">
10
+ <action method="addItem">
11
+ <type>skin_css</type>
12
+ <name>affinityengine/main.css</name>
13
+ </action>
14
+ <action method="addItem">
15
+ <type>skin_js</type>
16
+ <name>affinityengine/jquery-noconflict.js</name>
17
+ </action>
18
+ </reference>
19
+ </affinityitems_adminhtml_affinityitemsbackend_index>
20
+ <affinityitems_adminhtml_affinityitemslog_index>
21
+ <reference name="content">
22
+ <block type="affinityitems/adminhtml_affinityitems" name="affinityitems">
23
+ <action method="setCacheLifetime"><s>null</s></action>
24
+ </block>
25
+ </reference>
26
+ </affinityitems_adminhtml_affinityitemslog_index>
27
+ </layout>
app/design/adminhtml/default/default/template/affinityitems/affinityitems_login.phtml ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script>
2
+ var v = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
3
+ var n = /^[A-Za-z0-9!@#$%^&*()_]{6,20}$/;
4
+ var r;
5
+
6
+ function error(e) {
7
+ jQuery(".items-alert").hide();
8
+ jQuery(".items-alert").empty();
9
+ var t = "Please enter valid data : <br>";
10
+ for (var n = 0; n < e.length; n++) {
11
+ var r = n + 1;
12
+ t += "\n" + r + ". " + e[n] + "<br>";
13
+ }
14
+ jQuery(".items-alert").append(t);
15
+ jQuery(".items-alert").slideDown();
16
+ }
17
+
18
+ jQuery(document).ready(function () {
19
+
20
+ jQuery('.items-register-container').on('submit', function() {
21
+ r = [];
22
+ if (!v.test(jQuery("#remail").val())) {
23
+ r[r.length] = "Please enter a valid email address";
24
+ }
25
+ if (!n.test(jQuery("#rpassword").val())) {
26
+ r[r.length] = "Your password must be between 6 and 20 characters long";
27
+ }
28
+ if(!jQuery('#rcgv').is(':checked')) {
29
+ r[r.length] = "Please accept the terms and conditions of use";
30
+ }
31
+ if (r.length > 0) {
32
+ error(r);
33
+ return false;
34
+ } else {
35
+ jQuery.ajax({
36
+ url: "<?php echo Mage::helper("affinityitems/aeadapter")->getRegisterUrl();?>",
37
+ type: "POST",
38
+ async: true,
39
+ data: {
40
+ action: "register",
41
+ email: jQuery("#remail").val(),
42
+ password: jQuery("#rpassword").val(),
43
+ discountCode: jQuery("#rdiscount").val(),
44
+ form_key: jQuery("#rform_key").val()
45
+ },
46
+ success: function (e, t, n) {
47
+ var response = e;
48
+ if(response._ok == "true") {
49
+ location.reload();
50
+ } else {
51
+ r = [];
52
+ if(typeof response._errorMessage != "undefined") {
53
+ r[r.length] = response._errorMessage;
54
+ } else {
55
+ r[r.length] = "An error has occured, it seems there is no connection between your shop and our servers, please contact <a href=\'mailto:mathieu@affinity-engine.fr\'>mathieu@affinity-engine.fr</a>";
56
+ }
57
+ error(r);
58
+ }
59
+ },
60
+ error: function (e, t, n) {
61
+ r = [];
62
+ r[r.length] = "An error has occured, please contact <a href=\'mailto:mathieu@affinity-engine.fr\'>mathieu@affinity-engine.fr</a>";
63
+ error(r);
64
+ }
65
+ });
66
+ }
67
+ return false;
68
+ });
69
+
70
+ });
71
+
72
+ </script>
73
+
74
+ <div class="items-wrapper">
75
+ <div class="items-header">
76
+ <div class="aelogo"></div>
77
+ </div>
78
+ <div class="items-alert" style="display:none;"></div>
79
+ <div class="items-content">
80
+ <div class="items-auth-zone">
81
+ <div class="items-auth-container items-left">
82
+ <div class="items-auth-register">
83
+ <h3><?php echo Mage::helper('affinityitems')->__('Sign up for 30-days free trial');?></h3>
84
+ <p><?php echo Mage::helper('affinityitems')->__('To get a clear view of the impact on your sales');?></p>
85
+ <p><?php echo Mage::helper('affinityitems')->__('at the end of the trial');?></p>
86
+ <form class="items-register-container">
87
+ <input type="text" class="aeinput" id="remail" value="" placeholder="<?php echo Mage::helper('affinityitems')->__('Email'); ?>">
88
+ <br>
89
+ <input type="password" class="aeinput" id="rpassword" placeholder="<?php echo Mage::helper('affinityitems')->__('Password'); ?>">
90
+ <br>
91
+ <input type="text" class="aeinput" id="rdiscount" placeholder="<?php echo Mage::helper('affinityitems')->__('Discount code'); ?>" style="display: inline-block;">
92
+ <br>
93
+ <p class="ae-cgv"><input type="checkbox" id="rcgv">
94
+ <?php echo Mage::helper('affinityitems')->__('I accept the');?> <a target='_blank' href="{$module_dir|escape:'htmlall':'UTF-8'}resources/pdf/contract.pdf" ><?php echo Mage::helper('affinityitems')->__('terms and conditions of use.');?></a>
95
+ </p>
96
+ <input id="aeregister" style="margin-top: 67px;" class="items-button items-green" type="submit" value="<?php echo Mage::helper('affinityitems')->__('Install AffinityItems');?>">
97
+ <input name="form_key" id="rform_key" type="hidden" value="<?php echo Mage::getSingleton('core/session')->getFormKey() ?>" />
98
+ </form>
99
+ </div>
100
+ </div>
101
+ <div class="items-auth-presentation items-right">
102
+ <div class="items-auth-presentation-content">
103
+ <h3><?php echo Mage::helper('affinityitems')->__('Boost your transformation rate');?></h3>
104
+ <p><?php echo Mage::helper('affinityitems')->__('Suggest automatically, on each page,');?></p>
105
+ <p><?php echo Mage::helper('affinityitems')->__('a selection of products that match each visitor needs.');?></p>
106
+ <div class="items-video">
107
+ <span class="items-video-promotion"><object type="text/html" data="http://www.youtube.com/embed/rxn3fHYNL3s" width="340" height="210"></object></span>
108
+ </div>
109
+ <p><?php echo Mage::helper('affinityitems')->__('Up to 60% products sold');?></p>
110
+ <p><?php echo Mage::helper('affinityitems')->__('have been recommended by affinity items.');?></p>
111
+ <a class="items-button items-purple" href="http://addons.prestashop.com/fr/ventes-croisees-cross-selling/17491-affinityitems.html"><?php echo Mage::helper('affinityitems')->__('More about');?></a>
112
+ </div>
113
+ </div>
114
+ <div class="clear"></div>
115
+ </div>
116
+ </div>
117
+ </div>
app/design/adminhtml/default/default/template/affinityitems/affinityitems_sync.phtml ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $helper = Mage::helper('affinityitems/aeadapter');
3
+ $request = new AffinityEngine_AffinityItems_Model_Sdk_Request_SiteRequest(array());
4
+ $data = $request->get();
5
+ $statistics = Mage::helper('core')->jsonDecode($data['statistics']);
6
+ $siteId = $helper->getSiteId();
7
+ $categories = $helper->checkSync('categories');
8
+ $products = $helper->checkSync('products');
9
+ $cart = $helper->checkSync('cart');
10
+ $orders = $helper->checkSync('orders');
11
+ $actions = $helper->checkSync('actions');
12
+ $isSynced = (bool) ($categories && $products && $cart && $orders && $actions);
13
+ $initialsync = (count(Mage::getModel('affinityitems/syncrotate')->getCollection())) ? (bool) Mage::getModel('affinityitems/syncrotate')->getCollection()->getFirstItem()->getData('initial_sync') : true;
14
+ ?>
15
+
16
+ <div class="aewrapper">
17
+ <?php if ($data['_ok']): ?>
18
+ <div class="items-account">
19
+ <a class="items-manager-button" target="_blank" href="http://manager.affinityitems.com/login/<?php echo $siteId . '/' . $data['authToken']; ?>">
20
+ <div class="items-button">
21
+ <?php echo $this->__('Access my account') ?>
22
+ </div>
23
+ </a>
24
+ </div>
25
+ <?php endif; ?>
26
+ </div>
27
+
28
+ <div class="items-wrapper">
29
+ <div class="items-header">
30
+ <div class="aelogo"></div>
31
+ </div>
32
+ <div id="items-dashboard" style="display: block;">
33
+
34
+ <?php if($data['authToken']) { ?>
35
+
36
+ <div class="items-synchronize-container" style="background-color: rgb(130, 200, 54);">
37
+
38
+ <div class="items-synchronize-container-text items-left">
39
+ <?php echo $this->__('Affinity items is activated and operational') ?>
40
+ </div>
41
+
42
+ <a class="items-manager-button" target="_blank" href="http://manager.affinityitems.com/login/<?php echo $siteId . '/' . $data['authToken']; ?>">
43
+ <div style="color: white;" class="items-synchronize-container-button items-green items-right">
44
+ <?php echo $this->__('Access my account') ?>
45
+ </div>
46
+ </a>
47
+ <div class="clear"></div>
48
+ </div>
49
+
50
+ <?php } else { ?>
51
+
52
+ <br />
53
+
54
+ <?php } ?>
55
+
56
+ <div class="items-boxes">
57
+
58
+ <div class="items-box items-box-black">
59
+ <p><span class="items-box-large-font"><?php echo is_numeric($statistics['onlineUsers']) ? $statistics['onlineUsers'] : 0; ?></span> <br> <span> <?php echo $this->__('current connected visitors'); ?> </span></p>
60
+ </div>
61
+
62
+ <div class="items-box items-box-black">
63
+ <p><span class="items-box-large-font"><?php echo is_numeric($statistics['cartsInProgress']) ? $statistics['cartsInProgress'] : 0; ?></span> <br> <span><?php echo $this->__('current carts'); ?></span></p>
64
+ </div>
65
+
66
+ <div class="items-box items-box-purple">
67
+ <p><span class="items-box-large-font"><?php echo is_numeric($statistics['lastMonthVisitsWithRecommendation']) ? $statistics['lastMonthVisitsWithRecommendation'] : 0; ?></span> <br> <span><?php echo $this->__('visits with recommendations'); ?></span></p>
68
+ </div>
69
+
70
+ <div class="items-box items-box-purple">
71
+ <p><span class="items-box-large-font"><?php echo round(($statistics['bestClickRate']['rate']*100), 2); ?> %</span> <br> <span> <?php echo $this->__('recommendations click rate on'); ?> <?php echo $statistics['bestClickRate']['hook'] ?> page*</span></p>
72
+ </div>
73
+
74
+ <div class="items-box items-box-purple">
75
+ <p><span class="items-box-large-font"><?php echo round($statistics['lastMonthClickersConversationRate'], 2); ?> %</span> <br> <span><?php echo $this->__('transformation rate among clickers'); ?> *</span></p>
76
+ </div>
77
+
78
+ <div class="items-box items-box-black">
79
+ <p><span class="items-box-large-font"><?php echo is_numeric($statistics['lastMonthOrders']) ? $statistics['lastMonthOrders'] : 0; ?></span> <br> <span> <?php echo $this->__('orders last 30 days'); ?></span></p>
80
+ </div>
81
+
82
+ <div class="items-box items-box-black">
83
+ <p><span class="items-box-large-font"><?php echo round($statistics['lastMonthSales'], 0) ?></span> <br> <span><?php echo $this->__('sales last 30 days'); ?></span></p>
84
+ </div>
85
+
86
+ <div class="items-box items-box-purple">
87
+ <p><span class="items-box-large-font"><?php echo is_numeric($data['recommendation']) ? $data['recommendation'] : 0; ?></span> <br> <span><?php echo $this->__('recommandations since 30 days'); ?></span></p>
88
+ </div>
89
+
90
+ <div class="items-box items-box-purple">
91
+ <p><span class="items-box-large-font"><?php echo round($statistics['salesAfterClick'], 0) ?> €</span> <br> <span><?php echo $this->__('of sales following click on recommendations'); ?> *</span></p>
92
+ </div>
93
+
94
+ <div class="items-box items-box-purple">
95
+ <p><span class="items-box-large-font"><?php echo round($statistics['salesAfterReco'], 0) ?> €</span> <br> <span><?php echo $this->__('of sales following a recommendation'); ?> *</span></p>
96
+ </div>
97
+
98
+ </div>
99
+
100
+ <div class="clear"></div>
101
+ </div>
102
+
103
+
104
+ <div class="items-synchronization">
105
+ <div>
106
+ <?php if ($initialsync):?>
107
+ <h2><?php echo $this->__('Initial sync in progress'); ?></h2>
108
+ <?php else:?>
109
+ <h2><?php echo ($isSynced) ? $this->__('Your system is synchronized') : $this->__('Your system is not synchronized'); ?></h2>
110
+ <?php endif;?>
111
+ </div>
112
+ <div>
113
+ <ul>
114
+ <li class="<?php echo ($categories) ? 'aechecked' : 'aeunchecked'; ?>"><?php echo $this->__('Categories synchronization'); ?></li>
115
+ <li class="<?php echo ($products) ? 'aechecked' : 'aeunchecked'; ?>"><?php echo $this->__('Products synchronization'); ?></li>
116
+ <li class="<?php echo ($cart) ? 'aechecked' : 'aeunchecked'; ?>"><?php echo $this->__('Carts synchronization'); ?></li>
117
+ <li class="<?php echo ($orders) ? 'aechecked' : 'aeunchecked'; ?>"><?php echo $this->__('Orders synchronization'); ?></li>
118
+ <li class="<?php echo ($actions) ? 'aechecked' : 'aeunchecked'; ?>"><?php echo $this->__('Actions synchronization'); ?></li>
119
+ </ul>
120
+ </div>
121
+ </div>
122
+
123
+ </div>
app/design/frontend/base/default/layout/affinityengine/affinityitems.xml ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+
3
+ <layout version="0.1.0">
4
+ <default>
5
+ <!-- for all pages -->
6
+ <reference name="left">
7
+ <block type="affinityitems/index" name="ae_vertical_left" after="_" template="affinityengine/vertical.phtml"/>
8
+ </reference>
9
+ <reference name="right">
10
+ <block type="affinityitems/index" name="ae_vertical_right" after="_" template="affinityengine/vertical.phtml"/>
11
+ </reference>
12
+ <reference name="head">
13
+ <action method="addCss"><stylesheet>css/affinityitems/affinityitems.css</stylesheet></action>
14
+ <action method="addItem"><type>skin_js</type><name>js/affinityitems/jquery-noconflict.js</name></action>
15
+ <action method="addItem"><type>skin_js</type><name>js/affinityitems/affinityitems.js</name></action>
16
+ <block type="affinityitems/index" name="ae_css" after="_" template="affinityengine/ae_css.phtml" />
17
+ </reference>
18
+ <reference name="content">
19
+ <block type="affinityitems/index" name="ae_js" after="_" template="affinityengine/ae_js.phtml"/>
20
+ </reference>
21
+ </default>
22
+
23
+ <!-- for home page -->
24
+ <cms_index_index>
25
+ <reference name="content">
26
+ <block type="affinityitems/index" name="ae_horizontal" after="_" template="affinityengine/horizontal.phtml"/>
27
+ </reference>
28
+ </cms_index_index>
29
+
30
+ <!-- for product view page -->
31
+ <catalog_product_view>
32
+ <reference name="content">
33
+ <block type="affinityitems/index" name="ae_horizontal" after="_" template="affinityengine/horizontal.phtml"/>
34
+ </reference>
35
+ </catalog_product_view>
36
+
37
+ <!-- for category layered page -->
38
+ <catalog_category_layered>
39
+ <reference name="content">
40
+ <block type="affinityitems/index" name="ae_horizontal" after="_" template="affinityengine/horizontal.phtml"/>
41
+ </reference>
42
+ </catalog_category_layered>
43
+
44
+ <!-- for category page -->
45
+ <catalog_category_default>
46
+ <reference name="content">
47
+ <block type="affinityitems/index" name="ae_horizontal" after="_" template="affinityengine/horizontal.phtml"/>
48
+ </reference>
49
+ </catalog_category_default>
50
+
51
+ <!-- for search page -->
52
+ <catalogsearch_result_index>
53
+ <reference name="content">
54
+ <block type="affinityitems/index" name="ae_horizontal" after="_" template="affinityengine/horizontal.phtml"/>
55
+ </reference>
56
+ </catalogsearch_result_index>
57
+
58
+ <!-- for advanced search page -->
59
+ <catalogsearch_advanced_result>
60
+ <reference name="content">
61
+ <block type="affinityitems/index" name="ae_horizontal" after="_" template="affinityengine/horizontal.phtml"/>
62
+ </reference>
63
+ </catalogsearch_advanced_result>
64
+
65
+ <!-- for cart page -->
66
+ <checkout_cart_index>
67
+ <reference name="content">
68
+ <block type="affinityitems/index" name="ae_horizontal" after="_" template="affinityengine/horizontal.phtml"/>
69
+ </reference>
70
+ </checkout_cart_index>
71
+ </layout>
app/design/frontend/base/default/template/affinityengine/ae_css.phtml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <style type="text/css">
2
+ <?php echo Mage::getStoreConfig('affinityitems/advanced/ae_css'); ?>
3
+ </style>
app/design/frontend/base/default/template/affinityengine/ae_js.phtml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script>
2
+ var abtesting = '<?php echo Mage::getModel('core/cookie')->get('aegroup');?>';
3
+ var base_url = '<?php echo Mage::getBaseUrl();?>';
4
+
5
+ <?php if((bool)Mage::getModel('affinityitems/config')->getValue('affinityitems/advanced/ae_tracking_js')) { ?>
6
+
7
+ var pageName = '<?php echo Mage::helper('affinityitems')->getCurrentPage();?>';
8
+
9
+ var affinityItemsTrackPageView=function(t,e){"use strict";var n=function(t,e){"undefined"==typeof ga&&!function(t,e,n,o,a,c,i){t.GoogleAnalyticsObject=a,t[a]=t[a]||function(){(t[a].q=t[a].q||[]).push(arguments)},t[a].l=1*new Date,c=e.createElement(n),i=e.getElementsByTagName(n)[0],c.async=1,c.src=o,i.parentNode.insertBefore(c,i)}(window,document,"script","//www.google-analytics.com/analytics.js","ga"),ga("create","UA-57445738-1",{name:"affintyItemsTracker",cookieName:"_affintyItemsGa",cookieDomain:"auto"}),ga("affintyItemsTracker.set","location",window.location.protocol+"//"+window.location.host+"/"+window.location.host+window.location.pathname+window.location.search+window.location.hash),void 0===t&&(t="not-set"),void 0===e&&(e="not-set"),ga("affintyItemsTracker.send","pageview",{dimension1:t,dimension2:e})};document.addEventListener?document.addEventListener("DOMContentLoaded",function(){n(t,e)}):document.attachEvent?document.attachEvent("onreadystatechange",function(){"complete"==document.readyState&&n(t,e)}):console.log("[affintyItemsTrack] cannot attach to a document ready event")};
10
+
11
+ affinityItemsTrackPageView(abtesting, pageName);
12
+
13
+ <?php } ?>
14
+
15
+ <?php
16
+ $_helper = $this->helper('catalog/output');
17
+ $_category_detail = Mage::registry('current_category');
18
+ if(isset($_category_detail)) { ?>
19
+ var categoryId = '<?php echo $_category_detail->getId();?>';
20
+ <?php } ?>
21
+ aejQuery(document).ready(function () {
22
+ aejQuery('.ae-area a').on('click', function() {
23
+ aenow = new Date().getTime();
24
+ createCookie('aelastreco', (aenow+"."+aejQuery(this).parents(".ae-area").attr("class").split(" ")[1].split("-")[1]+"."+aejQuery(this).attr("rel")), 1);
25
+ });
26
+ });
27
+ </script>
app/design/frontend/base/default/template/affinityengine/horizontal.phtml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $helper = $this->helper('affinityitems'); ?>
2
+ <?php if ($current_product = Mage::registry('current_product')) : ?>
3
+ <input type='hidden' id='product_page_product_id' name='product_page_product_id' value='<?php echo $current_product->getId() ?>' />
4
+ <?php endif; ?>
5
+ <?php if ($helper->isEnabled()): ?>
6
+ <?php $productCollection = $this->getProductCollection(); ?>
7
+
8
+ <?php if ($productCollection && count($productCollection)): ?>
9
+ <?php $imagesize = $helper->getImageSize(); ?>
10
+ <div class="ae-area ae-<?php echo $helper->getCurrentPage()?>">
11
+ <div id="<?php echo $helper->getId('parent_div'); ?>" class="<?php echo $helper->getClass('parent_div'); ?>">
12
+ <h4 class="<?php echo $helper->getClass('title_class'); ?>"><?php echo $helper->getConfig('recommendation_label'); ?></h4>
13
+ <div id="<?php echo $helper->getId('content_div'); ?>" class="<?php echo $helper->getClass('content_div'); ?>">
14
+ <ul id="<?php echo $helper->getId('ul'); ?>" class="<?php echo $helper->getClass('ul'); ?>">
15
+ <?php $i=0 ?>
16
+ <?php foreach ($productCollection as $product): ?>
17
+ <?php if (Mage::registry('current_product') && Mage::registry('current_product')->getId() == $product->getId()) continue; ?>
18
+ <?php $product = Mage::getModel('catalog/product')->load($product->getId()); ?>
19
+ <?php if ($helper->canDisplayProduct($product)) continue;?>
20
+ <?php $pname = $this->escapeHtml($product->getName()); ?>
21
+ <li id="<?php echo $helper->getId('li'); ?>" class="<?php echo $helper->getClass('ul'); ?> <?php if(($i % $helper->getConfig('number_products_per_line')) == ($helper->getConfig('number_products_per_line') - 1)) echo 'ae_last_item_of_line'; ?>">
22
+ <a rel="<?php echo $product->getId()?>" href="<?php echo $helper->getFullProductUrl($product); ?>" title="<?php echo $pname ?>" rel="<?php echo $product->getId() ?>"><img class="<?php echo $helper->getClass('product_image_class'); ?>" src="<?php echo Mage::helper('catalog/image')->init($product, 'image')->resize($imagesize[0], $imagesize[1]) ?>"" height="<?php echo $imagesize[0]; ?>" width="<?php echo $imagesize[1]; ?>" alt="<?php echo $pname ?>" /></a>
23
+ <h5 itemprop="name">
24
+ <a rel="<?php echo $product->getId()?>" class="<?php echo $helper->getClass('product_name_class'); ?>" href="<?php echo $helper->getFullProductUrl($product); ?>" rel="<?php echo $pname ?>" title="<?php echo $pname ?>"><?php echo $pname ?></a>
25
+ </h5>
26
+ <div>
27
+ <p class="<?php echo $helper->getClass('product_description_class'); ?>"><?php echo Mage::helper('core/string')->truncate($product->getShortDescription(), 40); ?></p>
28
+ <p class="<?php echo $helper->getClass('price_container_class'); ?>"><span class="<?php echo $helper->getClass('price_class'); ?>"><?php echo $helper->getFormatedPrice($product); ?></span></p>
29
+ </div>
30
+ </li>
31
+ <?php $i++; ?>
32
+ <?php endforeach; ?>
33
+ </ul>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ <?php endif; ?>
38
+ <?php endif; ?>
app/design/frontend/base/default/template/affinityengine/pricehtml.phtml ADDED
@@ -0,0 +1 @@
 
1
+ <?php echo $this->getPricehtml($this->getProd());?>
app/design/frontend/base/default/template/affinityengine/vertical.phtml ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $helper = $this->helper('affinityitems'); ?>
2
+ <?php $blockName = $this->getNameInLayout(); ?>
3
+ <?php if ($blockName == 'ae_vertical_right'): ?>
4
+ <?php $enable_column = $helper->isRightEnabled(); ?>
5
+ <?php $imagesize = $helper->getRImageSize(); ?>
6
+ <?php $css = "right";?>
7
+ <?php elseif ($blockName == 'ae_vertical_left'): ?>
8
+ <?php $enable_column = $helper->isLeftEnabled(); ?>
9
+ <?php $imagesize = $helper->getLImageSize(); ?>
10
+ <?php $css = "left";?>
11
+ <?php else: ?>
12
+ <?php $enable_column = false; ?>
13
+ <?php endif; ?>
14
+
15
+ <?php if ($enable_column): ?>
16
+ <?php $productCollection = $this->getProductCollection($blockName); ?>
17
+ <?php if ($productCollection && count($productCollection)): ?>
18
+ <div class="ae-area ae-<?php echo $css;?>">
19
+ <div id="<?php echo $helper->getId('parent_div'); ?>" class="<?php echo $helper->getClass('parent_div'); ?>">
20
+ <h4 class="<?php echo $helper->getClass('title_class'); ?>"><?php echo $helper->getSideTitle($this->getNameInLayout()); ?></h4>
21
+ <div id="<?php echo $helper->getId('content_div'); ?>" class="<?php echo $helper->getClass('content_div'); ?>">
22
+ <ul id="<?php echo $helper->getId('ul'); ?>" class="<?php echo $helper->getClass('ul'); ?>">
23
+ <?php $i=0 ?>
24
+ <?php foreach ($productCollection as $product): ?>
25
+ <?php if (Mage::registry('current_product') && Mage::registry('current_product')->getId() == $product->getId()) continue; ?>
26
+ <?php $product = Mage::getModel('catalog/product')->load($product->getId()); ?>
27
+ <?php if ($helper->canDisplayProduct($product)) continue;?>
28
+ <?php $pname = $this->escapeHtml($product->getName()); ?>
29
+ <li id="<?php echo $helper->getId('li'); ?>" class="<?php echo $helper->getClass('ul'); ?> <?php if(($i % $helper->getConfig('number_products_per_line')) == ($helper->getConfig('number_products_per_line') - 1)) echo 'ae_last_item_of_line'; ?>">
30
+ <a rel="<?php echo $product->getId()?>" href="<?php echo $helper->getFullProductUrl($product); ?>" title="<?php echo $pname ?>" rel="<?php echo $product->getId() ?>"><img class="<?php echo $helper->getClass('product_image_class'); ?>" src="<?php echo Mage::helper('catalog/image')->init($product, 'image')->resize($imagesize[0], $imagesize[1]) ?>"" height="<?php echo $imagesize[0]; ?>" width="<?php echo $imagesize[1]; ?>" alt="<?php echo $pname ?>" /></a>
31
+ <h5 itemprop="name">
32
+ <a rel="<?php echo $product->getId()?>" class="<?php echo $helper->getClass('product_name_class'); ?>" href="<?php echo $helper->getFullProductUrl($product); ?>" rel="<?php echo $pname ?>" title="<?php echo $pname ?>"><?php echo $pname ?></a>
33
+ </h5>
34
+ <div>
35
+ <p class="<?php echo $helper->getClass('product_description_class'); ?>"><?php echo Mage::helper('core/string')->truncate($product->getShortDescription(), 40); ?></p>
36
+ <p class="<?php echo $helper->getClass('price_container_class'); ?>"><span class="<?php echo $helper->getClass('price_class'); ?>"><?php echo $helper->getFormatedPrice($product); ?></span></p>
37
+ </div>
38
+ </li>
39
+ <?php $i++; ?>
40
+ <?php endforeach; ?>
41
+ </ul>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ <?php endif; ?>
46
+ <?php endif; ?>
app/etc/modules/AffinityEngine_AffinityItems.xml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <AffinityEngine_AffinityItems>
5
+ <active>true</active>
6
+ <codePool>local</codePool>
7
+ <version>1.0.0</version>
8
+ </AffinityEngine_AffinityItems>
9
+ </modules>
10
+ </config>
app/locale/fr_FR/AffinityEngine_AffinityItems.csv ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "General configuration", "Configuration générale"
2
+ "Activation", "Activation"
3
+ "Enviroment", "Environnement"
4
+ "Number of elements to be synced", "Nombre d'éléments par paquet durant la synchronisation"
5
+ "Advanced configuration", "Configuration avancée"
6
+ "<strong>To secure the access to the recommendations, please indicate the servers that are allowed to query these recommendations</strong>", "<strong>Merci d'indiquer les serveurs authorisés à faire des demandes de recommandation</strong>"
7
+ "Server access", "Accès serveur"
8
+ "<strong>Additional CSS</strong>", "<strong>CSS additionnel</strong>"
9
+ "Log Level", "Niveau de log"
10
+ "% guests with recommendations", "% de visiteurs avec recommandations"
11
+ "Developer options", "Options de développement"
12
+ "Image size", "Dimensions des images"
13
+ "Default Image Size", "Dimensions des images par défault"
14
+ "Large Image Size", "Dimensions des images de large taille"
15
+ "Medium Image Size", "Dimensions des images de moyenne taille"
16
+ "Small Image Size", "Dimensions des images de petite taille"
17
+ "Enable", "Activation"
18
+ "Recommendation area label", "Label de la zone de recommandation"
19
+ "Number of displayed products", "Nombre de produits affichés"
20
+ "Number of displayed products per line", "Nombre de produits par ligne"
21
+ "Recommendation configuration", "Configuration de la recommandation"
22
+ "<strong>Display settings</strong>", "<strong>Paramètres d'affichage</strong>"
23
+ "Sign up for 30-days free trial", "Essai gratuit de 30 jours"
24
+ "To get a clear view of the impact on your sales", "Bénéficiez d’un bilan gratuit de l’impact sur vos ventes"
25
+ "at the end of the trial", "à la fin de la période d’essai"
26
+ "Email", "Email"
27
+ "Password", "Mot de passe"
28
+ "Discount code", "J'ai un code promotion"
29
+ "I accept the", "J'accepte les"
30
+ "terms and conditions of use.", "termes et conditions d'utilisation"
31
+ "Install AffinityItems", "Installer AffinityItems"
32
+ "Boost your transformation rate", "Améliorez votre taux de transformation"
33
+ "Suggest automatically, on each page,", "Suggérez automatiquement, sur chaque page,"
34
+ "a selection of products that match each visitor needs.", "une sélection de produits adaptés à chaque visiteur."
35
+ "Up to 60% products sold", "Jusqu'a 60% des produits achetés"
36
+ "have been recommended by affinity items.", "ont été recommandés par affinity items."
37
+ "More about", "Plus d'info"
38
+ "Access my account", "Accèder à mon compte"
39
+ "Affinity items is activated and operational", "Affinity items est activé et opérationnel"
40
+ "current connected visitors", "visiteurs connectés"
41
+ "current carts", "paniers en cours"
42
+ "visits with recommendations", "visites avec recommandations"
43
+ "recommendations click rate on", "taux de clic sur les recos page"
44
+ "transformation rate among clickers", "de taux de transformation auprès des clickers"
45
+ "orders last 30 days", "commandes les 30 derniers jours"
46
+ "sales last 30 days", "vente les 30 derniers jours"
47
+ "recommandations since 30 days", "recommandations les 30 derniers jours"
48
+ "of sales following click on recommendations", "de CA suite à un clic sur une recommandation"
49
+ "of sales following a recommendation", "du chiffre d'affaires suite à une recommandation"
50
+ "Affinity Items Synchronization", "Synchronisation d'Affinity Items"
51
+ "Initial sync in progress", "Synchronisation générale en progression"
52
+ "Your system is synchronized", "Votre système est synchronisé"
53
+ "Your system is not synchronized", "Votre système n'est pas synchronisé"
54
+ "Categories synchronization", "Synchronisation des catégories"
55
+ "Products synchronization", "Synchronisation des produits"
56
+ "Carts synchronization", "Synchronisation des paniers"
57
+ "Orders synchronization", "Synchronisation des commandes"
58
+ "Actions synchronization", "Synchronisation des actions"
package.xml ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Affinity_Items</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Increase your sales with new generation personalized recommendations: affinity items automatically displays to each visitor, on each page, the selection of products that best fits his/her tastes &amp; needs. Give your customer an unrivaled experience with our real time multilingual algorithms. Use the most advanced personalization service on a success-based pricing.</summary>
10
+ <description>Affinity items - Personalization for Magento&#xD;
11
+ &#xD;
12
+ Increase your sales with new generation personalized recommendations: affinity items automatically displays to each visitor, on each page, the selection of products that best fits his/her tastes &amp; needs. Give your customer an unrivaled experience with our real time multilingual algorithms. Use the most advanced personalization service on a success-based pricing.&#xD;
13
+ &#xD;
14
+ As a salesperson in a traditional store, affinity items listens to visitors to understand what they want and guide them to the right products.&#xD;
15
+ &#xD;
16
+ Affinity items increases the conversion rate and the cart value, improve the customer experience and it&#x2019;s loyalty.&#xD;
17
+ &#xD;
18
+ Why is it important for merchants?&#xD;
19
+ &#xD;
20
+ Most of merchants use traffic generation as the unique lever to increase their sales. But traffic acquisition is expensive, and even more when the website conversion rate is low. &#xD;
21
+ &#xD;
22
+ Personalized recommendations revive the &#x201C;merchant spirit&#x201D;: they generate visitor&#x2019;s satisfaction by easing their purchases, and thus increase the conversion and ultimately improve profitability of all webmarketing actions.&#xD;
23
+ &#xD;
24
+ Test affinity items for free for 30 days.&#xD;
25
+ &#xD;
26
+ What is cool about this extension?&#xD;
27
+ &#xD;
28
+ Saying &#x201C;personalization&#x201D; is not enough to do some.&#xD;
29
+ &#xD;
30
+ Affinity items uses an exclusive real-time semantic analysis to ensure a very fine and rich understanding of visitor&#x2019;s and do not put people in clusters, in order to provide each user with specific recommendations.&#xD;
31
+ &#xD;
32
+ Besides, it is the only service of this type on a pay-per-use base, with no minimum billing, thus affordable to each and every website.&#xD;
33
+ &#xD;
34
+ How does a merchant take the next step?&#xD;
35
+ &#xD;
36
+ Install the module directly from Magento Connect or contact us on support@affinityitems.com or on +33 2 97 43 49 00 for a free set-up. Affinity items one-month free trial enables to freely measure the impact on the website sales.&#xD;
37
+ &#xD;
38
+ Pricing&#xD;
39
+ &#xD;
40
+ Affinity items pricing model is a pure success based pricing model. There are no setup costs, no fixed fees and no minimum spends.&#xD;
41
+ &#xD;
42
+ Developers&#xD;
43
+ &#xD;
44
+ Affinity items Magento extension is also downloadable from our developer platform: http://developer.affinity-engine.fr/affinityitems/magento/wikis/master/en-home</description>
45
+ <notes>No notes</notes>
46
+ <authors><author><name>Mathieu</name><user>BARAN</user><email>mathieu@affinity-engine.fr</email></author></authors>
47
+ <date>2015-04-28</date>
48
+ <time>16:26:20</time>
49
+ <contents><target name="magelocal"><dir name="AffinityEngine"><dir name="AffinityItems"><dir name="Block"><dir name="Adminhtml"><dir name="Affinityitems"><file name="Grid.php" hash="de34b472132fc34610da4b2257f17176"/></dir><file name="Affinityitems.php" hash="ae8d3d49bc84ade4ab253ce9bff305d2"/><file name="Affinityitemsbackend.php" hash="40aa694ef6ee2f256f202cf1a144ce0b"/></dir><file name="Index.php" hash="c88110dedce1f701dc202095ce8cdc08"/><dir name="Renderer"><dir name="Config"><file name="Classes.php" hash="8c3d39529ef95c439b8e679a3912d9be"/><file name="Imagesize.php" hash="1a1bdd54722e5cf9ecb0318655b5f6db"/><file name="Ipblacklist.php" hash="645526f7fc6ad0ca8835f027d3a8c5f9"/><file name="Serverlist.php" hash="5c0f647a50a9444cde02909bcc164c6f"/><file name="Siteinfo.php" hash="baed3f0f265f0e93537d75ed988c871b"/><file name="Version.php" hash="48fe7d204de5dbc4194b54b6c3df41e9"/></dir></dir></dir><dir name="Helper"><file name="Aeadapter.php" hash="3a5d399727da2e0e1cdd6158535d9374"/><file name="Data.php" hash="17c33a6fcc14bf27ff4dda7326eedb86"/></dir><dir name="Model"><file name="Action.php" hash="2eb81ffd225b596d389c63f158818809"/><file name="Cart.php" hash="31c04d90e49fce5cc7e89f8892fc772c"/><file name="CatProdRepo.php" hash="a96f30305035b6bb82483199e3b731cc"/><file name="Config.php" hash="484d6fd84ca1a2322e6300aad22e82aa"/><file name="Cron.php" hash="0ca61c06a2ec49ac4f603ad5945bb890"/><file name="Log.php" hash="b86d41197ebcfa96acd1ef9da14b1595"/><file name="Observer.php" hash="c7865f97a2bc07aa579c065f66cb1866"/><dir name="Resource"><dir name="Action"><file name="Collection.php" hash="326d82fe39153680f99defdb1e846476"/></dir><file name="Action.php" hash="6cd9f6a6d4b87e220c3bbf271a24810d"/><dir name="Cart"><file name="Collection.php" hash="9a8c23023645f9170102980ce56bc193"/></dir><file name="Cart.php" hash="8bb395c3ebfc043326c6001d623270a4"/><dir name="CatProdRepo"><file name="Collection.php" hash="bf98be72eae2c0859046142ed2d7fb4c"/></dir><file name="CatProdRepo.php" hash="4781a985d1b889633ed28d98b28378bf"/><dir name="Log"><file name="Collection.php" hash="935eae91b74f30c4a960b1c18f373050"/></dir><file name="Log.php" hash="bc36af5602145cc1fc094fa17289eb1a"/><dir name="Syncrotate"><file name="Collection.php" hash="66bd261226b6865c5a52ef28e9b064ea"/></dir><file name="Syncrotate.php" hash="0d3b60d41d19f49c8dc673fd61007de5"/></dir><dir name="Sdk"><dir name="Abtesting"><file name="Abtesting.php" hash="59ae987fa1fd1d75a0263ccf7c86d10d"/></dir><dir name="Core"><file name="AbstractRequest.php" hash="d92ec4494b9cee5fa1343594024336fd"/><file name="Curl.php" hash="e620ba54fc00bf974adbb8ae0e0ffe95"/></dir><dir name="Recommendation"><file name="Recommendation.php" hash="64929784b877e32281705eee0c056533"/></dir><dir name="Request"><file name="ActionRequest.php" hash="a4128a5365d69a19e72ed9d7fe357514"/><file name="CategoryRequest.php" hash="31db44e9f404ee80a29939424a1a3596"/><file name="CustomerRequest.php" hash="3f1a0758034a2865e5bdf0e439694212"/><file name="DisableRequest.php" hash="9eeb721518be067c57eb8ce58df3d270"/><file name="GuestRequest.php" hash="78dd970ae4d0612853ddcdafd4de8ec4"/><file name="HostRequest.php" hash="8df4275aaf02019d9228ee14b395abe5"/><file name="LinkGuestToMemberRequest.php" hash="499c3986c89b09942c424542375d4d58"/><file name="MemberRequest.php" hash="74747f67cca8cccad5e6e346cfc157b0"/><file name="NotificationRequest.php" hash="3758c90470a9a32bafc8395a30127490"/><file name="OrderRequest.php" hash="590c8d40c2202f0becd50ec9a97c6885"/><file name="ProductRequest.php" hash="ad20d6f489728b5863867bd6bfaca753"/><file name="RecommendationRequest.php" hash="dc4e986ed4b224cbc1f36464e8610a43"/><file name="ResynchronizeRequest.php" hash="5d534d27011644ba14aa58bd935394bd"/><file name="SiteRequest.php" hash="42029a530971606fd2a2fd4cdb23b8b3"/></dir></dir><dir name="Source"><file name="Enviroment.php" hash="099b2a345377ceb795674a5d4d30a6a7"/><file name="Imagesize.php" hash="fa63ae1460a85dae21b0c6a3aabd6e35"/><file name="Loglevel.php" hash="2f9f20c2aff9f645cab10d1c1ff35af1"/><file name="Recoconfig.php" hash="cc99f674dd147f270969d05f02c615a6"/></dir><dir name="Sync"><file name="ActionSync.php" hash="9a159b5a9737e8219ca797780d9e281b"/><file name="CartActionSync.php" hash="00ffa3870ffab842261b771e80b89c3a"/><file name="CategorySync.php" hash="1119c45f88925a5453fdad4fd4f87650"/><file name="MemberSync.php" hash="aae843752f2f6e93efa8a63699970318"/><file name="OrderSync.php" hash="01aefd33bfd7802038e9e5658c628901"/><file name="ProductSync.php" hash="a5c98bb6a0025e65c43640b800a29200"/><file name="Sync.php" hash="566e8315189d593d44fc60f94c5c8df2"/></dir><file name="Syncrotate.php" hash="5685bf909244da8a8d9e2bf65bb1e2e3"/></dir><dir name="bin"><file name="manual-run.php" hash="96d1b37af2d93e0cfd8647250b6469e2"/></dir><dir name="controllers"><file name="ActionController.php" hash="bc93bfa952b2451ec71e9dc60d32ce00"/><dir name="Adminhtml"><file name="AffinityitemsbackendController.php" hash="a1f7026fd8ac2def3b25826a11b41f0a"/><file name="AffinityitemslogController.php" hash="398ca37dfc8a48f88ac8cadf7a471ec8"/><file name="AjaxController.php" hash="7cdee5c9f004056b9334735b740a42a9"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="3db0abc036764375bece30c5bb5dc976"/><file name="config.xml" hash="8fe736ac078b381c4c10879eaabe21f3"/><file name="system.xml" hash="697868b642cb633f08e15ee9a2bd6b04"/></dir><dir name="sql"><dir name="affinityitems_setup"><file name="mysql4-install-1.0.0.php" hash="78d3b4f08df64cbfe5dff290ad392f4e"/></dir></dir><file name="uninstall.sql" hash="73cb0928320f6f5325c6d21a87bf49eb"/></dir></dir></target><target name="mageetc"><dir name="modules"><file name="AffinityEngine_AffinityItems.xml" hash="204ebb541724e767ec5eb67916c39c6b"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="affinityitems.xml" hash="32d45a407463b4e76b5e30dab765b965"/></dir><dir name="template"><dir name="affinityitems"><file name="affinityitems_login.phtml" hash="7bc103a9720d13c20f55373c29f4f59e"/><file name="affinityitems_sync.phtml" hash="5a4ebc7989eadad7269547decf3fdbff"/></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><dir name="affinityengine"><file name="affinityitems.xml" hash="9a2c254e32f5d69deef0e3d74f007905"/></dir></dir><dir name="template"><dir name="affinityengine"><file name="ae_css.phtml" hash="828164eb0fcf039ac670c432d2d56c0d"/><file name="ae_js.phtml" hash="dbf7ae914bbcbde55cd0855a9c58119e"/><file name="horizontal.phtml" hash="4060998dba74e152c7d42aba19fda002"/><file name="pricehtml.phtml" hash="a4c2c740d9119fb016c8e005ed5ad7ca"/><file name="vertical.phtml" hash="3dd66bb879bc2f2044b945831145e920"/></dir></dir></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="css"><dir name="affinityitems"><file name="affinityitems.css" hash="ecb8e40e67270c872e53b18f46a42671"/></dir></dir><dir name="js"><dir name="affinityitems"><file name="affinityitems.js" hash="b240ad85e3a8d41745acbfefc3b5f2fc"/><file name="jquery-noconflict.js" hash="1f3b8801b59144eeaee27caa7c5c15db"/></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="affinityengine"><dir name="img"><file name="aeboard.jpg" hash="9481a712582bcac6bdc2727a9cf52b3b"/><file name="aemoney.jpg" hash="6dc4d7612be1efe77784c622fa73985d"/><file name="aestart.jpg" hash="277c540ae19974133f473a731145f33d"/><file name="ailogo.png" hash="df2799c4ee9e68bd793cb85149fea2e7"/><file name="checked.png" hash="d4122f013483f59be79719385405a0de"/><file name="disabled.png" hash="fd56b078b4c3423735c667358285dc06"/><file name="enabled.png" hash="2499c302772cacbaf5d3c85427f2e7c5"/><file name="error.png" hash="bc87cd99143fc930408e379d5c3aa0f0"/><file name="index.php" hash="931175008efa4be6a17827fefd16937d"/><file name="loading.gif" hash="30d8e72bfdae694b1938658e1b087df0"/><file name="logo.png" hash="af48761d7b17a4e5115b8f16aaf634b6"/><file name="pdf.png" hash="95b561422892384337eb2eabb968a558"/><file name="unchecked.png" hash="0f5ec71a07abf89590209349c85b58ff"/></dir><file name="jquery-noconflict.js" hash="3d8c3103282467d2cd94031dbf4a75b6"/><file name="main.css" hash="24b27193af0a6a75cf5090acb01639a4"/></dir></dir></dir></dir></target><target name="magelocale"><dir name="fr_FR"><file name="AffinityEngine_AffinityItems.csv" hash="8354ba61ed4a3cedb8e80a463ec5d7fb"/></dir></target></contents>
50
+ <compatible/>
51
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
52
+ </package>
skin/adminhtml/default/default/affinityengine/img/aeboard.jpg ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/aemoney.jpg ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/aestart.jpg ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/ailogo.png ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/checked.png ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/disabled.png ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/enabled.png ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/error.png ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/index.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 2007-2014 PrestaShop
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@prestashop.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
18
+ * versions in the future.If you wish to customize PrestaShop for your
19
+ * needs please refer to http://www.prestashop.com for more information.
20
+ *
21
+ * @author PrestaShop SA <contact@prestashop.com>
22
+ * @copyright 2007-2014 PrestaShop SA
23
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
24
+ * International Registered Trademark & Property of PrestaShop SA
25
+ */
26
+
27
+ header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
28
+ header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
29
+
30
+ header('Cache-Control: no-store, no-cache, must-revalidate');
31
+ header('Cache-Control: post-check=0, pre-check=0', false);
32
+ header('Pragma: no-cache');
33
+
34
+ header('Location:../');
35
+ exit;
skin/adminhtml/default/default/affinityengine/img/loading.gif ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/logo.png ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/pdf.png ADDED
Binary file
skin/adminhtml/default/default/affinityengine/img/unchecked.png ADDED
Binary file
skin/adminhtml/default/default/affinityengine/jquery-noconflict.js ADDED
@@ -0,0 +1,9791 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery JavaScript Library v1.10.2
3
+ * http://jquery.com/
4
+ *
5
+ * Includes Sizzle.js
6
+ * http://sizzlejs.com/
7
+ *
8
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
9
+ * Released under the MIT license
10
+ * http://jquery.org/license
11
+ *
12
+ * Date: 2013-07-03T13:48Z
13
+ */
14
+ (function( window, undefined ) {
15
+
16
+ // Can't do this because several apps including ASP.NET trace
17
+ // the stack via arguments.caller.callee and Firefox dies if
18
+ // you try to trace through "use strict" call chains. (#13335)
19
+ // Support: Firefox 18+
20
+ //"use strict";
21
+ var
22
+ // The deferred used on DOM ready
23
+ readyList,
24
+
25
+ // A central reference to the root jQuery(document)
26
+ rootjQuery,
27
+
28
+ // Support: IE<10
29
+ // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
30
+ core_strundefined = typeof undefined,
31
+
32
+ // Use the correct document accordingly with window argument (sandbox)
33
+ location = window.location,
34
+ document = window.document,
35
+ docElem = document.documentElement,
36
+
37
+ // Map over jQuery in case of overwrite
38
+ _jQuery = window.jQuery,
39
+
40
+ // Map over the $ in case of overwrite
41
+ _$ = window.$,
42
+
43
+ // [[Class]] -> type pairs
44
+ class2type = {},
45
+
46
+ // List of deleted data cache ids, so we can reuse them
47
+ core_deletedIds = [],
48
+
49
+ core_version = "1.10.2",
50
+
51
+ // Save a reference to some core methods
52
+ core_concat = core_deletedIds.concat,
53
+ core_push = core_deletedIds.push,
54
+ core_slice = core_deletedIds.slice,
55
+ core_indexOf = core_deletedIds.indexOf,
56
+ core_toString = class2type.toString,
57
+ core_hasOwn = class2type.hasOwnProperty,
58
+ core_trim = core_version.trim,
59
+
60
+ // Define a local copy of jQuery
61
+ jQuery = function( selector, context ) {
62
+ // The jQuery object is actually just the init constructor 'enhanced'
63
+ return new jQuery.fn.init( selector, context, rootjQuery );
64
+ },
65
+
66
+ // Used for matching numbers
67
+ core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
68
+
69
+ // Used for splitting on whitespace
70
+ core_rnotwhite = /\S+/g,
71
+
72
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
73
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
74
+
75
+ // A simple way to check for HTML strings
76
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
77
+ // Strict HTML recognition (#11290: must start with <)
78
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
79
+
80
+ // Match a standalone tag
81
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
82
+
83
+ // JSON RegExp
84
+ rvalidchars = /^[\],:{}\s]*$/,
85
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
86
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
87
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
88
+
89
+ // Matches dashed string for camelizing
90
+ rmsPrefix = /^-ms-/,
91
+ rdashAlpha = /-([\da-z])/gi,
92
+
93
+ // Used by jQuery.camelCase as callback to replace()
94
+ fcamelCase = function( all, letter ) {
95
+ return letter.toUpperCase();
96
+ },
97
+
98
+ // The ready event handler
99
+ completed = function( event ) {
100
+
101
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
102
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
103
+ detach();
104
+ jQuery.ready();
105
+ }
106
+ },
107
+ // Clean-up method for dom ready events
108
+ detach = function() {
109
+ if ( document.addEventListener ) {
110
+ document.removeEventListener( "DOMContentLoaded", completed, false );
111
+ window.removeEventListener( "load", completed, false );
112
+
113
+ } else {
114
+ document.detachEvent( "onreadystatechange", completed );
115
+ window.detachEvent( "onload", completed );
116
+ }
117
+ };
118
+
119
+ jQuery.fn = jQuery.prototype = {
120
+ // The current version of jQuery being used
121
+ jquery: core_version,
122
+
123
+ constructor: jQuery,
124
+ init: function( selector, context, rootjQuery ) {
125
+ var match, elem;
126
+
127
+ // HANDLE: $(""), $(null), $(undefined), $(false)
128
+ if ( !selector ) {
129
+ return this;
130
+ }
131
+
132
+ // Handle HTML strings
133
+ if ( typeof selector === "string" ) {
134
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
135
+ // Assume that strings that start and end with <> are HTML and skip the regex check
136
+ match = [ null, selector, null ];
137
+
138
+ } else {
139
+ match = rquickExpr.exec( selector );
140
+ }
141
+
142
+ // Match html or make sure no context is specified for #id
143
+ if ( match && (match[1] || !context) ) {
144
+
145
+ // HANDLE: $(html) -> $(array)
146
+ if ( match[1] ) {
147
+ context = context instanceof jQuery ? context[0] : context;
148
+
149
+ // scripts is true for back-compat
150
+ jQuery.merge( this, jQuery.parseHTML(
151
+ match[1],
152
+ context && context.nodeType ? context.ownerDocument || context : document,
153
+ true
154
+ ) );
155
+
156
+ // HANDLE: $(html, props)
157
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
158
+ for ( match in context ) {
159
+ // Properties of context are called as methods if possible
160
+ if ( jQuery.isFunction( this[ match ] ) ) {
161
+ this[ match ]( context[ match ] );
162
+
163
+ // ...and otherwise set as attributes
164
+ } else {
165
+ this.attr( match, context[ match ] );
166
+ }
167
+ }
168
+ }
169
+
170
+ return this;
171
+
172
+ // HANDLE: $(#id)
173
+ } else {
174
+ elem = document.getElementById( match[2] );
175
+
176
+ // Check parentNode to catch when Blackberry 4.6 returns
177
+ // nodes that are no longer in the document #6963
178
+ if ( elem && elem.parentNode ) {
179
+ // Handle the case where IE and Opera return items
180
+ // by name instead of ID
181
+ if ( elem.id !== match[2] ) {
182
+ return rootjQuery.find( selector );
183
+ }
184
+
185
+ // Otherwise, we inject the element directly into the jQuery object
186
+ this.length = 1;
187
+ this[0] = elem;
188
+ }
189
+
190
+ this.context = document;
191
+ this.selector = selector;
192
+ return this;
193
+ }
194
+
195
+ // HANDLE: $(expr, $(...))
196
+ } else if ( !context || context.jquery ) {
197
+ return ( context || rootjQuery ).find( selector );
198
+
199
+ // HANDLE: $(expr, context)
200
+ // (which is just equivalent to: $(context).find(expr)
201
+ } else {
202
+ return this.constructor( context ).find( selector );
203
+ }
204
+
205
+ // HANDLE: $(DOMElement)
206
+ } else if ( selector.nodeType ) {
207
+ this.context = this[0] = selector;
208
+ this.length = 1;
209
+ return this;
210
+
211
+ // HANDLE: $(function)
212
+ // Shortcut for document ready
213
+ } else if ( jQuery.isFunction( selector ) ) {
214
+ return rootjQuery.ready( selector );
215
+ }
216
+
217
+ if ( selector.selector !== undefined ) {
218
+ this.selector = selector.selector;
219
+ this.context = selector.context;
220
+ }
221
+
222
+ return jQuery.makeArray( selector, this );
223
+ },
224
+
225
+ // Start with an empty selector
226
+ selector: "",
227
+
228
+ // The default length of a jQuery object is 0
229
+ length: 0,
230
+
231
+ toArray: function() {
232
+ return core_slice.call( this );
233
+ },
234
+
235
+ // Get the Nth element in the matched element set OR
236
+ // Get the whole matched element set as a clean array
237
+ get: function( num ) {
238
+ return num == null ?
239
+
240
+ // Return a 'clean' array
241
+ this.toArray() :
242
+
243
+ // Return just the object
244
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
245
+ },
246
+
247
+ // Take an array of elements and push it onto the stack
248
+ // (returning the new matched element set)
249
+ pushStack: function( elems ) {
250
+
251
+ // Build a new jQuery matched element set
252
+ var ret = jQuery.merge( this.constructor(), elems );
253
+
254
+ // Add the old object onto the stack (as a reference)
255
+ ret.prevObject = this;
256
+ ret.context = this.context;
257
+
258
+ // Return the newly-formed element set
259
+ return ret;
260
+ },
261
+
262
+ // Execute a callback for every element in the matched set.
263
+ // (You can seed the arguments with an array of args, but this is
264
+ // only used internally.)
265
+ each: function( callback, args ) {
266
+ return jQuery.each( this, callback, args );
267
+ },
268
+
269
+ ready: function( fn ) {
270
+ // Add the callback
271
+ jQuery.ready.promise().done( fn );
272
+
273
+ return this;
274
+ },
275
+
276
+ slice: function() {
277
+ return this.pushStack( core_slice.apply( this, arguments ) );
278
+ },
279
+
280
+ first: function() {
281
+ return this.eq( 0 );
282
+ },
283
+
284
+ last: function() {
285
+ return this.eq( -1 );
286
+ },
287
+
288
+ eq: function( i ) {
289
+ var len = this.length,
290
+ j = +i + ( i < 0 ? len : 0 );
291
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
292
+ },
293
+
294
+ map: function( callback ) {
295
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
296
+ return callback.call( elem, i, elem );
297
+ }));
298
+ },
299
+
300
+ end: function() {
301
+ return this.prevObject || this.constructor(null);
302
+ },
303
+
304
+ // For internal use only.
305
+ // Behaves like an Array's method, not like a jQuery method.
306
+ push: core_push,
307
+ sort: [].sort,
308
+ splice: [].splice
309
+ };
310
+
311
+ // Give the init function the jQuery prototype for later instantiation
312
+ jQuery.fn.init.prototype = jQuery.fn;
313
+
314
+ jQuery.extend = jQuery.fn.extend = function() {
315
+ var src, copyIsArray, copy, name, options, clone,
316
+ target = arguments[0] || {},
317
+ i = 1,
318
+ length = arguments.length,
319
+ deep = false;
320
+
321
+ // Handle a deep copy situation
322
+ if ( typeof target === "boolean" ) {
323
+ deep = target;
324
+ target = arguments[1] || {};
325
+ // skip the boolean and the target
326
+ i = 2;
327
+ }
328
+
329
+ // Handle case when target is a string or something (possible in deep copy)
330
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
331
+ target = {};
332
+ }
333
+
334
+ // extend jQuery itself if only one argument is passed
335
+ if ( length === i ) {
336
+ target = this;
337
+ --i;
338
+ }
339
+
340
+ for ( ; i < length; i++ ) {
341
+ // Only deal with non-null/undefined values
342
+ if ( (options = arguments[ i ]) != null ) {
343
+ // Extend the base object
344
+ for ( name in options ) {
345
+ src = target[ name ];
346
+ copy = options[ name ];
347
+
348
+ // Prevent never-ending loop
349
+ if ( target === copy ) {
350
+ continue;
351
+ }
352
+
353
+ // Recurse if we're merging plain objects or arrays
354
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
355
+ if ( copyIsArray ) {
356
+ copyIsArray = false;
357
+ clone = src && jQuery.isArray(src) ? src : [];
358
+
359
+ } else {
360
+ clone = src && jQuery.isPlainObject(src) ? src : {};
361
+ }
362
+
363
+ // Never move original objects, clone them
364
+ target[ name ] = jQuery.extend( deep, clone, copy );
365
+
366
+ // Don't bring in undefined values
367
+ } else if ( copy !== undefined ) {
368
+ target[ name ] = copy;
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ // Return the modified object
375
+ return target;
376
+ };
377
+
378
+ jQuery.extend({
379
+ // Unique for each copy of jQuery on the page
380
+ // Non-digits removed to match rinlinejQuery
381
+ expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
382
+
383
+ noConflict: function( deep ) {
384
+ if ( window.$ === jQuery ) {
385
+ window.$ = _$;
386
+ }
387
+
388
+ if ( deep && window.jQuery === jQuery ) {
389
+ window.jQuery = _jQuery;
390
+ }
391
+
392
+ return jQuery;
393
+ },
394
+
395
+ // Is the DOM ready to be used? Set to true once it occurs.
396
+ isReady: false,
397
+
398
+ // A counter to track how many items to wait for before
399
+ // the ready event fires. See #6781
400
+ readyWait: 1,
401
+
402
+ // Hold (or release) the ready event
403
+ holdReady: function( hold ) {
404
+ if ( hold ) {
405
+ jQuery.readyWait++;
406
+ } else {
407
+ jQuery.ready( true );
408
+ }
409
+ },
410
+
411
+ // Handle when the DOM is ready
412
+ ready: function( wait ) {
413
+
414
+ // Abort if there are pending holds or we're already ready
415
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
416
+ return;
417
+ }
418
+
419
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
420
+ if ( !document.body ) {
421
+ return setTimeout( jQuery.ready );
422
+ }
423
+
424
+ // Remember that the DOM is ready
425
+ jQuery.isReady = true;
426
+
427
+ // If a normal DOM Ready event fired, decrement, and wait if need be
428
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
429
+ return;
430
+ }
431
+
432
+ // If there are functions bound, to execute
433
+ readyList.resolveWith( document, [ jQuery ] );
434
+
435
+ // Trigger any bound ready events
436
+ if ( jQuery.fn.trigger ) {
437
+ jQuery( document ).trigger("ready").off("ready");
438
+ }
439
+ },
440
+
441
+ // See test/unit/core.js for details concerning isFunction.
442
+ // Since version 1.3, DOM methods and functions like alert
443
+ // aren't supported. They return false on IE (#2968).
444
+ isFunction: function( obj ) {
445
+ return jQuery.type(obj) === "function";
446
+ },
447
+
448
+ isArray: Array.isArray || function( obj ) {
449
+ return jQuery.type(obj) === "array";
450
+ },
451
+
452
+ isWindow: function( obj ) {
453
+ /* jshint eqeqeq: false */
454
+ return obj != null && obj == obj.window;
455
+ },
456
+
457
+ isNumeric: function( obj ) {
458
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
459
+ },
460
+
461
+ type: function( obj ) {
462
+ if ( obj == null ) {
463
+ return String( obj );
464
+ }
465
+ return typeof obj === "object" || typeof obj === "function" ?
466
+ class2type[ core_toString.call(obj) ] || "object" :
467
+ typeof obj;
468
+ },
469
+
470
+ isPlainObject: function( obj ) {
471
+ var key;
472
+
473
+ // Must be an Object.
474
+ // Because of IE, we also have to check the presence of the constructor property.
475
+ // Make sure that DOM nodes and window objects don't pass through, as well
476
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
477
+ return false;
478
+ }
479
+
480
+ try {
481
+ // Not own constructor property must be Object
482
+ if ( obj.constructor &&
483
+ !core_hasOwn.call(obj, "constructor") &&
484
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
485
+ return false;
486
+ }
487
+ } catch ( e ) {
488
+ // IE8,9 Will throw exceptions on certain host objects #9897
489
+ return false;
490
+ }
491
+
492
+ // Support: IE<9
493
+ // Handle iteration over inherited properties before own properties.
494
+ if ( jQuery.support.ownLast ) {
495
+ for ( key in obj ) {
496
+ return core_hasOwn.call( obj, key );
497
+ }
498
+ }
499
+
500
+ // Own properties are enumerated firstly, so to speed up,
501
+ // if last one is own, then all properties are own.
502
+ for ( key in obj ) {}
503
+
504
+ return key === undefined || core_hasOwn.call( obj, key );
505
+ },
506
+
507
+ isEmptyObject: function( obj ) {
508
+ var name;
509
+ for ( name in obj ) {
510
+ return false;
511
+ }
512
+ return true;
513
+ },
514
+
515
+ error: function( msg ) {
516
+ throw new Error( msg );
517
+ },
518
+
519
+ // data: string of html
520
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
521
+ // keepScripts (optional): If true, will include scripts passed in the html string
522
+ parseHTML: function( data, context, keepScripts ) {
523
+ if ( !data || typeof data !== "string" ) {
524
+ return null;
525
+ }
526
+ if ( typeof context === "boolean" ) {
527
+ keepScripts = context;
528
+ context = false;
529
+ }
530
+ context = context || document;
531
+
532
+ var parsed = rsingleTag.exec( data ),
533
+ scripts = !keepScripts && [];
534
+
535
+ // Single tag
536
+ if ( parsed ) {
537
+ return [ context.createElement( parsed[1] ) ];
538
+ }
539
+
540
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
541
+ if ( scripts ) {
542
+ jQuery( scripts ).remove();
543
+ }
544
+ return jQuery.merge( [], parsed.childNodes );
545
+ },
546
+
547
+ parseJSON: function( data ) {
548
+ // Attempt to parse using the native JSON parser first
549
+ if ( window.JSON && window.JSON.parse ) {
550
+ return window.JSON.parse( data );
551
+ }
552
+
553
+ if ( data === null ) {
554
+ return data;
555
+ }
556
+
557
+ if ( typeof data === "string" ) {
558
+
559
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
560
+ data = jQuery.trim( data );
561
+
562
+ if ( data ) {
563
+ // Make sure the incoming data is actual JSON
564
+ // Logic borrowed from http://json.org/json2.js
565
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
566
+ .replace( rvalidtokens, "]" )
567
+ .replace( rvalidbraces, "")) ) {
568
+
569
+ return ( new Function( "return " + data ) )();
570
+ }
571
+ }
572
+ }
573
+
574
+ jQuery.error( "Invalid JSON: " + data );
575
+ },
576
+
577
+ // Cross-browser xml parsing
578
+ parseXML: function( data ) {
579
+ var xml, tmp;
580
+ if ( !data || typeof data !== "string" ) {
581
+ return null;
582
+ }
583
+ try {
584
+ if ( window.DOMParser ) { // Standard
585
+ tmp = new DOMParser();
586
+ xml = tmp.parseFromString( data , "text/xml" );
587
+ } else { // IE
588
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
589
+ xml.async = "false";
590
+ xml.loadXML( data );
591
+ }
592
+ } catch( e ) {
593
+ xml = undefined;
594
+ }
595
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
596
+ jQuery.error( "Invalid XML: " + data );
597
+ }
598
+ return xml;
599
+ },
600
+
601
+ noop: function() {},
602
+
603
+ // Evaluates a script in a global context
604
+ // Workarounds based on findings by Jim Driscoll
605
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
606
+ globalEval: function( data ) {
607
+ if ( data && jQuery.trim( data ) ) {
608
+ // We use execScript on Internet Explorer
609
+ // We use an anonymous function so that context is window
610
+ // rather than jQuery in Firefox
611
+ ( window.execScript || function( data ) {
612
+ window[ "eval" ].call( window, data );
613
+ } )( data );
614
+ }
615
+ },
616
+
617
+ // Convert dashed to camelCase; used by the css and data modules
618
+ // Microsoft forgot to hump their vendor prefix (#9572)
619
+ camelCase: function( string ) {
620
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
621
+ },
622
+
623
+ nodeName: function( elem, name ) {
624
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
625
+ },
626
+
627
+ // args is for internal usage only
628
+ each: function( obj, callback, args ) {
629
+ var value,
630
+ i = 0,
631
+ length = obj.length,
632
+ isArray = isArraylike( obj );
633
+
634
+ if ( args ) {
635
+ if ( isArray ) {
636
+ for ( ; i < length; i++ ) {
637
+ value = callback.apply( obj[ i ], args );
638
+
639
+ if ( value === false ) {
640
+ break;
641
+ }
642
+ }
643
+ } else {
644
+ for ( i in obj ) {
645
+ value = callback.apply( obj[ i ], args );
646
+
647
+ if ( value === false ) {
648
+ break;
649
+ }
650
+ }
651
+ }
652
+
653
+ // A special, fast, case for the most common use of each
654
+ } else {
655
+ if ( isArray ) {
656
+ for ( ; i < length; i++ ) {
657
+ value = callback.call( obj[ i ], i, obj[ i ] );
658
+
659
+ if ( value === false ) {
660
+ break;
661
+ }
662
+ }
663
+ } else {
664
+ for ( i in obj ) {
665
+ value = callback.call( obj[ i ], i, obj[ i ] );
666
+
667
+ if ( value === false ) {
668
+ break;
669
+ }
670
+ }
671
+ }
672
+ }
673
+
674
+ return obj;
675
+ },
676
+
677
+ // Use native String.trim function wherever possible
678
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
679
+ function( text ) {
680
+ return text == null ?
681
+ "" :
682
+ core_trim.call( text );
683
+ } :
684
+
685
+ // Otherwise use our own trimming functionality
686
+ function( text ) {
687
+ return text == null ?
688
+ "" :
689
+ ( text + "" ).replace( rtrim, "" );
690
+ },
691
+
692
+ // results is for internal usage only
693
+ makeArray: function( arr, results ) {
694
+ var ret = results || [];
695
+
696
+ if ( arr != null ) {
697
+ if ( isArraylike( Object(arr) ) ) {
698
+ jQuery.merge( ret,
699
+ typeof arr === "string" ?
700
+ [ arr ] : arr
701
+ );
702
+ } else {
703
+ core_push.call( ret, arr );
704
+ }
705
+ }
706
+
707
+ return ret;
708
+ },
709
+
710
+ inArray: function( elem, arr, i ) {
711
+ var len;
712
+
713
+ if ( arr ) {
714
+ if ( core_indexOf ) {
715
+ return core_indexOf.call( arr, elem, i );
716
+ }
717
+
718
+ len = arr.length;
719
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
720
+
721
+ for ( ; i < len; i++ ) {
722
+ // Skip accessing in sparse arrays
723
+ if ( i in arr && arr[ i ] === elem ) {
724
+ return i;
725
+ }
726
+ }
727
+ }
728
+
729
+ return -1;
730
+ },
731
+
732
+ merge: function( first, second ) {
733
+ var l = second.length,
734
+ i = first.length,
735
+ j = 0;
736
+
737
+ if ( typeof l === "number" ) {
738
+ for ( ; j < l; j++ ) {
739
+ first[ i++ ] = second[ j ];
740
+ }
741
+ } else {
742
+ while ( second[j] !== undefined ) {
743
+ first[ i++ ] = second[ j++ ];
744
+ }
745
+ }
746
+
747
+ first.length = i;
748
+
749
+ return first;
750
+ },
751
+
752
+ grep: function( elems, callback, inv ) {
753
+ var retVal,
754
+ ret = [],
755
+ i = 0,
756
+ length = elems.length;
757
+ inv = !!inv;
758
+
759
+ // Go through the array, only saving the items
760
+ // that pass the validator function
761
+ for ( ; i < length; i++ ) {
762
+ retVal = !!callback( elems[ i ], i );
763
+ if ( inv !== retVal ) {
764
+ ret.push( elems[ i ] );
765
+ }
766
+ }
767
+
768
+ return ret;
769
+ },
770
+
771
+ // arg is for internal usage only
772
+ map: function( elems, callback, arg ) {
773
+ var value,
774
+ i = 0,
775
+ length = elems.length,
776
+ isArray = isArraylike( elems ),
777
+ ret = [];
778
+
779
+ // Go through the array, translating each of the items to their
780
+ if ( isArray ) {
781
+ for ( ; i < length; i++ ) {
782
+ value = callback( elems[ i ], i, arg );
783
+
784
+ if ( value != null ) {
785
+ ret[ ret.length ] = value;
786
+ }
787
+ }
788
+
789
+ // Go through every key on the object,
790
+ } else {
791
+ for ( i in elems ) {
792
+ value = callback( elems[ i ], i, arg );
793
+
794
+ if ( value != null ) {
795
+ ret[ ret.length ] = value;
796
+ }
797
+ }
798
+ }
799
+
800
+ // Flatten any nested arrays
801
+ return core_concat.apply( [], ret );
802
+ },
803
+
804
+ // A global GUID counter for objects
805
+ guid: 1,
806
+
807
+ // Bind a function to a context, optionally partially applying any
808
+ // arguments.
809
+ proxy: function( fn, context ) {
810
+ var args, proxy, tmp;
811
+
812
+ if ( typeof context === "string" ) {
813
+ tmp = fn[ context ];
814
+ context = fn;
815
+ fn = tmp;
816
+ }
817
+
818
+ // Quick check to determine if target is callable, in the spec
819
+ // this throws a TypeError, but we will just return undefined.
820
+ if ( !jQuery.isFunction( fn ) ) {
821
+ return undefined;
822
+ }
823
+
824
+ // Simulated bind
825
+ args = core_slice.call( arguments, 2 );
826
+ proxy = function() {
827
+ return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
828
+ };
829
+
830
+ // Set the guid of unique handler to the same of original handler, so it can be removed
831
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
832
+
833
+ return proxy;
834
+ },
835
+
836
+ // Multifunctional method to get and set values of a collection
837
+ // The value/s can optionally be executed if it's a function
838
+ access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
839
+ var i = 0,
840
+ length = elems.length,
841
+ bulk = key == null;
842
+
843
+ // Sets many values
844
+ if ( jQuery.type( key ) === "object" ) {
845
+ chainable = true;
846
+ for ( i in key ) {
847
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
848
+ }
849
+
850
+ // Sets one value
851
+ } else if ( value !== undefined ) {
852
+ chainable = true;
853
+
854
+ if ( !jQuery.isFunction( value ) ) {
855
+ raw = true;
856
+ }
857
+
858
+ if ( bulk ) {
859
+ // Bulk operations run against the entire set
860
+ if ( raw ) {
861
+ fn.call( elems, value );
862
+ fn = null;
863
+
864
+ // ...except when executing function values
865
+ } else {
866
+ bulk = fn;
867
+ fn = function( elem, key, value ) {
868
+ return bulk.call( jQuery( elem ), value );
869
+ };
870
+ }
871
+ }
872
+
873
+ if ( fn ) {
874
+ for ( ; i < length; i++ ) {
875
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
876
+ }
877
+ }
878
+ }
879
+
880
+ return chainable ?
881
+ elems :
882
+
883
+ // Gets
884
+ bulk ?
885
+ fn.call( elems ) :
886
+ length ? fn( elems[0], key ) : emptyGet;
887
+ },
888
+
889
+ now: function() {
890
+ return ( new Date() ).getTime();
891
+ },
892
+
893
+ // A method for quickly swapping in/out CSS properties to get correct calculations.
894
+ // Note: this method belongs to the css module but it's needed here for the support module.
895
+ // If support gets modularized, this method should be moved back to the css module.
896
+ swap: function( elem, options, callback, args ) {
897
+ var ret, name,
898
+ old = {};
899
+
900
+ // Remember the old values, and insert the new ones
901
+ for ( name in options ) {
902
+ old[ name ] = elem.style[ name ];
903
+ elem.style[ name ] = options[ name ];
904
+ }
905
+
906
+ ret = callback.apply( elem, args || [] );
907
+
908
+ // Revert the old values
909
+ for ( name in options ) {
910
+ elem.style[ name ] = old[ name ];
911
+ }
912
+
913
+ return ret;
914
+ }
915
+ });
916
+
917
+ jQuery.ready.promise = function( obj ) {
918
+ if ( !readyList ) {
919
+
920
+ readyList = jQuery.Deferred();
921
+
922
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
923
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
924
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
925
+ if ( document.readyState === "complete" ) {
926
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
927
+ setTimeout( jQuery.ready );
928
+
929
+ // Standards-based browsers support DOMContentLoaded
930
+ } else if ( document.addEventListener ) {
931
+ // Use the handy event callback
932
+ document.addEventListener( "DOMContentLoaded", completed, false );
933
+
934
+ // A fallback to window.onload, that will always work
935
+ window.addEventListener( "load", completed, false );
936
+
937
+ // If IE event model is used
938
+ } else {
939
+ // Ensure firing before onload, maybe late but safe also for iframes
940
+ document.attachEvent( "onreadystatechange", completed );
941
+
942
+ // A fallback to window.onload, that will always work
943
+ window.attachEvent( "onload", completed );
944
+
945
+ // If IE and not a frame
946
+ // continually check to see if the document is ready
947
+ var top = false;
948
+
949
+ try {
950
+ top = window.frameElement == null && document.documentElement;
951
+ } catch(e) {}
952
+
953
+ if ( top && top.doScroll ) {
954
+ (function doScrollCheck() {
955
+ if ( !jQuery.isReady ) {
956
+
957
+ try {
958
+ // Use the trick by Diego Perini
959
+ // http://javascript.nwbox.com/IEContentLoaded/
960
+ top.doScroll("left");
961
+ } catch(e) {
962
+ return setTimeout( doScrollCheck, 50 );
963
+ }
964
+
965
+ // detach all dom ready events
966
+ detach();
967
+
968
+ // and execute any waiting functions
969
+ jQuery.ready();
970
+ }
971
+ })();
972
+ }
973
+ }
974
+ }
975
+ return readyList.promise( obj );
976
+ };
977
+
978
+ // Populate the class2type map
979
+ jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
980
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
981
+ });
982
+
983
+ function isArraylike( obj ) {
984
+ var length = obj.length,
985
+ type = jQuery.type( obj );
986
+
987
+ if ( jQuery.isWindow( obj ) ) {
988
+ return false;
989
+ }
990
+
991
+ if ( obj.nodeType === 1 && length ) {
992
+ return true;
993
+ }
994
+
995
+ return type === "array" || type !== "function" &&
996
+ ( length === 0 ||
997
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj );
998
+ }
999
+
1000
+ // All jQuery objects should point back to these
1001
+ rootjQuery = jQuery(document);
1002
+ /*!
1003
+ * Sizzle CSS Selector Engine v1.10.2
1004
+ * http://sizzlejs.com/
1005
+ *
1006
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
1007
+ * Released under the MIT license
1008
+ * http://jquery.org/license
1009
+ *
1010
+ * Date: 2013-07-03
1011
+ */
1012
+ (function( window, undefined ) {
1013
+
1014
+ var i,
1015
+ support,
1016
+ cachedruns,
1017
+ Expr,
1018
+ getText,
1019
+ isXML,
1020
+ compile,
1021
+ outermostContext,
1022
+ sortInput,
1023
+
1024
+ // Local document vars
1025
+ setDocument,
1026
+ document,
1027
+ docElem,
1028
+ documentIsHTML,
1029
+ rbuggyQSA,
1030
+ rbuggyMatches,
1031
+ matches,
1032
+ contains,
1033
+
1034
+ // Instance-specific data
1035
+ expando = "sizzle" + -(new Date()),
1036
+ preferredDoc = window.document,
1037
+ dirruns = 0,
1038
+ done = 0,
1039
+ classCache = createCache(),
1040
+ tokenCache = createCache(),
1041
+ compilerCache = createCache(),
1042
+ hasDuplicate = false,
1043
+ sortOrder = function( a, b ) {
1044
+ if ( a === b ) {
1045
+ hasDuplicate = true;
1046
+ return 0;
1047
+ }
1048
+ return 0;
1049
+ },
1050
+
1051
+ // General-purpose constants
1052
+ strundefined = typeof undefined,
1053
+ MAX_NEGATIVE = 1 << 31,
1054
+
1055
+ // Instance methods
1056
+ hasOwn = ({}).hasOwnProperty,
1057
+ arr = [],
1058
+ pop = arr.pop,
1059
+ push_native = arr.push,
1060
+ push = arr.push,
1061
+ slice = arr.slice,
1062
+ // Use a stripped-down indexOf if we can't use a native one
1063
+ indexOf = arr.indexOf || function( elem ) {
1064
+ var i = 0,
1065
+ len = this.length;
1066
+ for ( ; i < len; i++ ) {
1067
+ if ( this[i] === elem ) {
1068
+ return i;
1069
+ }
1070
+ }
1071
+ return -1;
1072
+ },
1073
+
1074
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
1075
+
1076
+ // Regular expressions
1077
+
1078
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
1079
+ whitespace = "[\\x20\\t\\r\\n\\f]",
1080
+ // http://www.w3.org/TR/css3-syntax/#characters
1081
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
1082
+
1083
+ // Loosely modeled on CSS identifier characters
1084
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
1085
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
1086
+ identifier = characterEncoding.replace( "w", "w#" ),
1087
+
1088
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
1089
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
1090
+ "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
1091
+
1092
+ // Prefer arguments quoted,
1093
+ // then not containing pseudos/brackets,
1094
+ // then attribute selectors/non-parenthetical expressions,
1095
+ // then anything else
1096
+ // These preferences are here to reduce the number of selectors
1097
+ // needing tokenize in the PSEUDO preFilter
1098
+ pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
1099
+
1100
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
1101
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
1102
+
1103
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
1104
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
1105
+
1106
+ rsibling = new RegExp( whitespace + "*[+~]" ),
1107
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
1108
+
1109
+ rpseudo = new RegExp( pseudos ),
1110
+ ridentifier = new RegExp( "^" + identifier + "$" ),
1111
+
1112
+ matchExpr = {
1113
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
1114
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
1115
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
1116
+ "ATTR": new RegExp( "^" + attributes ),
1117
+ "PSEUDO": new RegExp( "^" + pseudos ),
1118
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
1119
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
1120
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
1121
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
1122
+ // For use in libraries implementing .is()
1123
+ // We use this for POS matching in `select`
1124
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
1125
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
1126
+ },
1127
+
1128
+ rnative = /^[^{]+\{\s*\[native \w/,
1129
+
1130
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
1131
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
1132
+
1133
+ rinputs = /^(?:input|select|textarea|button)$/i,
1134
+ rheader = /^h\d$/i,
1135
+
1136
+ rescape = /'|\\/g,
1137
+
1138
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
1139
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
1140
+ funescape = function( _, escaped, escapedWhitespace ) {
1141
+ var high = "0x" + escaped - 0x10000;
1142
+ // NaN means non-codepoint
1143
+ // Support: Firefox
1144
+ // Workaround erroneous numeric interpretation of +"0x"
1145
+ return high !== high || escapedWhitespace ?
1146
+ escaped :
1147
+ // BMP codepoint
1148
+ high < 0 ?
1149
+ String.fromCharCode( high + 0x10000 ) :
1150
+ // Supplemental Plane codepoint (surrogate pair)
1151
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
1152
+ };
1153
+
1154
+ // Optimize for push.apply( _, NodeList )
1155
+ try {
1156
+ push.apply(
1157
+ (arr = slice.call( preferredDoc.childNodes )),
1158
+ preferredDoc.childNodes
1159
+ );
1160
+ // Support: Android<4.0
1161
+ // Detect silently failing push.apply
1162
+ arr[ preferredDoc.childNodes.length ].nodeType;
1163
+ } catch ( e ) {
1164
+ push = { apply: arr.length ?
1165
+
1166
+ // Leverage slice if possible
1167
+ function( target, els ) {
1168
+ push_native.apply( target, slice.call(els) );
1169
+ } :
1170
+
1171
+ // Support: IE<9
1172
+ // Otherwise append directly
1173
+ function( target, els ) {
1174
+ var j = target.length,
1175
+ i = 0;
1176
+ // Can't trust NodeList.length
1177
+ while ( (target[j++] = els[i++]) ) {}
1178
+ target.length = j - 1;
1179
+ }
1180
+ };
1181
+ }
1182
+
1183
+ function Sizzle( selector, context, results, seed ) {
1184
+ var match, elem, m, nodeType,
1185
+ // QSA vars
1186
+ i, groups, old, nid, newContext, newSelector;
1187
+
1188
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
1189
+ setDocument( context );
1190
+ }
1191
+
1192
+ context = context || document;
1193
+ results = results || [];
1194
+
1195
+ if ( !selector || typeof selector !== "string" ) {
1196
+ return results;
1197
+ }
1198
+
1199
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
1200
+ return [];
1201
+ }
1202
+
1203
+ if ( documentIsHTML && !seed ) {
1204
+
1205
+ // Shortcuts
1206
+ if ( (match = rquickExpr.exec( selector )) ) {
1207
+ // Speed-up: Sizzle("#ID")
1208
+ if ( (m = match[1]) ) {
1209
+ if ( nodeType === 9 ) {
1210
+ elem = context.getElementById( m );
1211
+ // Check parentNode to catch when Blackberry 4.6 returns
1212
+ // nodes that are no longer in the document #6963
1213
+ if ( elem && elem.parentNode ) {
1214
+ // Handle the case where IE, Opera, and Webkit return items
1215
+ // by name instead of ID
1216
+ if ( elem.id === m ) {
1217
+ results.push( elem );
1218
+ return results;
1219
+ }
1220
+ } else {
1221
+ return results;
1222
+ }
1223
+ } else {
1224
+ // Context is not a document
1225
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
1226
+ contains( context, elem ) && elem.id === m ) {
1227
+ results.push( elem );
1228
+ return results;
1229
+ }
1230
+ }
1231
+
1232
+ // Speed-up: Sizzle("TAG")
1233
+ } else if ( match[2] ) {
1234
+ push.apply( results, context.getElementsByTagName( selector ) );
1235
+ return results;
1236
+
1237
+ // Speed-up: Sizzle(".CLASS")
1238
+ } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
1239
+ push.apply( results, context.getElementsByClassName( m ) );
1240
+ return results;
1241
+ }
1242
+ }
1243
+
1244
+ // QSA path
1245
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
1246
+ nid = old = expando;
1247
+ newContext = context;
1248
+ newSelector = nodeType === 9 && selector;
1249
+
1250
+ // qSA works strangely on Element-rooted queries
1251
+ // We can work around this by specifying an extra ID on the root
1252
+ // and working up from there (Thanks to Andrew Dupont for the technique)
1253
+ // IE 8 doesn't work on object elements
1254
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
1255
+ groups = tokenize( selector );
1256
+
1257
+ if ( (old = context.getAttribute("id")) ) {
1258
+ nid = old.replace( rescape, "\\$&" );
1259
+ } else {
1260
+ context.setAttribute( "id", nid );
1261
+ }
1262
+ nid = "[id='" + nid + "'] ";
1263
+
1264
+ i = groups.length;
1265
+ while ( i-- ) {
1266
+ groups[i] = nid + toSelector( groups[i] );
1267
+ }
1268
+ newContext = rsibling.test( selector ) && context.parentNode || context;
1269
+ newSelector = groups.join(",");
1270
+ }
1271
+
1272
+ if ( newSelector ) {
1273
+ try {
1274
+ push.apply( results,
1275
+ newContext.querySelectorAll( newSelector )
1276
+ );
1277
+ return results;
1278
+ } catch(qsaError) {
1279
+ } finally {
1280
+ if ( !old ) {
1281
+ context.removeAttribute("id");
1282
+ }
1283
+ }
1284
+ }
1285
+ }
1286
+ }
1287
+
1288
+ // All others
1289
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
1290
+ }
1291
+
1292
+ /**
1293
+ * Create key-value caches of limited size
1294
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
1295
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
1296
+ * deleting the oldest entry
1297
+ */
1298
+ function createCache() {
1299
+ var keys = [];
1300
+
1301
+ function cache( key, value ) {
1302
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
1303
+ if ( keys.push( key += " " ) > Expr.cacheLength ) {
1304
+ // Only keep the most recent entries
1305
+ delete cache[ keys.shift() ];
1306
+ }
1307
+ return (cache[ key ] = value);
1308
+ }
1309
+ return cache;
1310
+ }
1311
+
1312
+ /**
1313
+ * Mark a function for special use by Sizzle
1314
+ * @param {Function} fn The function to mark
1315
+ */
1316
+ function markFunction( fn ) {
1317
+ fn[ expando ] = true;
1318
+ return fn;
1319
+ }
1320
+
1321
+ /**
1322
+ * Support testing using an element
1323
+ * @param {Function} fn Passed the created div and expects a boolean result
1324
+ */
1325
+ function assert( fn ) {
1326
+ var div = document.createElement("div");
1327
+
1328
+ try {
1329
+ return !!fn( div );
1330
+ } catch (e) {
1331
+ return false;
1332
+ } finally {
1333
+ // Remove from its parent by default
1334
+ if ( div.parentNode ) {
1335
+ div.parentNode.removeChild( div );
1336
+ }
1337
+ // release memory in IE
1338
+ div = null;
1339
+ }
1340
+ }
1341
+
1342
+ /**
1343
+ * Adds the same handler for all of the specified attrs
1344
+ * @param {String} attrs Pipe-separated list of attributes
1345
+ * @param {Function} handler The method that will be applied
1346
+ */
1347
+ function addHandle( attrs, handler ) {
1348
+ var arr = attrs.split("|"),
1349
+ i = attrs.length;
1350
+
1351
+ while ( i-- ) {
1352
+ Expr.attrHandle[ arr[i] ] = handler;
1353
+ }
1354
+ }
1355
+
1356
+ /**
1357
+ * Checks document order of two siblings
1358
+ * @param {Element} a
1359
+ * @param {Element} b
1360
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
1361
+ */
1362
+ function siblingCheck( a, b ) {
1363
+ var cur = b && a,
1364
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
1365
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
1366
+ ( ~a.sourceIndex || MAX_NEGATIVE );
1367
+
1368
+ // Use IE sourceIndex if available on both nodes
1369
+ if ( diff ) {
1370
+ return diff;
1371
+ }
1372
+
1373
+ // Check if b follows a
1374
+ if ( cur ) {
1375
+ while ( (cur = cur.nextSibling) ) {
1376
+ if ( cur === b ) {
1377
+ return -1;
1378
+ }
1379
+ }
1380
+ }
1381
+
1382
+ return a ? 1 : -1;
1383
+ }
1384
+
1385
+ /**
1386
+ * Returns a function to use in pseudos for input types
1387
+ * @param {String} type
1388
+ */
1389
+ function createInputPseudo( type ) {
1390
+ return function( elem ) {
1391
+ var name = elem.nodeName.toLowerCase();
1392
+ return name === "input" && elem.type === type;
1393
+ };
1394
+ }
1395
+
1396
+ /**
1397
+ * Returns a function to use in pseudos for buttons
1398
+ * @param {String} type
1399
+ */
1400
+ function createButtonPseudo( type ) {
1401
+ return function( elem ) {
1402
+ var name = elem.nodeName.toLowerCase();
1403
+ return (name === "input" || name === "button") && elem.type === type;
1404
+ };
1405
+ }
1406
+
1407
+ /**
1408
+ * Returns a function to use in pseudos for positionals
1409
+ * @param {Function} fn
1410
+ */
1411
+ function createPositionalPseudo( fn ) {
1412
+ return markFunction(function( argument ) {
1413
+ argument = +argument;
1414
+ return markFunction(function( seed, matches ) {
1415
+ var j,
1416
+ matchIndexes = fn( [], seed.length, argument ),
1417
+ i = matchIndexes.length;
1418
+
1419
+ // Match elements found at the specified indexes
1420
+ while ( i-- ) {
1421
+ if ( seed[ (j = matchIndexes[i]) ] ) {
1422
+ seed[j] = !(matches[j] = seed[j]);
1423
+ }
1424
+ }
1425
+ });
1426
+ });
1427
+ }
1428
+
1429
+ /**
1430
+ * Detect xml
1431
+ * @param {Element|Object} elem An element or a document
1432
+ */
1433
+ isXML = Sizzle.isXML = function( elem ) {
1434
+ // documentElement is verified for cases where it doesn't yet exist
1435
+ // (such as loading iframes in IE - #4833)
1436
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1437
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
1438
+ };
1439
+
1440
+ // Expose support vars for convenience
1441
+ support = Sizzle.support = {};
1442
+
1443
+ /**
1444
+ * Sets document-related variables once based on the current document
1445
+ * @param {Element|Object} [doc] An element or document object to use to set the document
1446
+ * @returns {Object} Returns the current document
1447
+ */
1448
+ setDocument = Sizzle.setDocument = function( node ) {
1449
+ var doc = node ? node.ownerDocument || node : preferredDoc,
1450
+ parent = doc.defaultView;
1451
+
1452
+ // If no document and documentElement is available, return
1453
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1454
+ return document;
1455
+ }
1456
+
1457
+ // Set our document
1458
+ document = doc;
1459
+ docElem = doc.documentElement;
1460
+
1461
+ // Support tests
1462
+ documentIsHTML = !isXML( doc );
1463
+
1464
+ // Support: IE>8
1465
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
1466
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
1467
+ // IE6-8 do not support the defaultView property so parent will be undefined
1468
+ if ( parent && parent.attachEvent && parent !== parent.top ) {
1469
+ parent.attachEvent( "onbeforeunload", function() {
1470
+ setDocument();
1471
+ });
1472
+ }
1473
+
1474
+ /* Attributes
1475
+ ---------------------------------------------------------------------- */
1476
+
1477
+ // Support: IE<8
1478
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
1479
+ support.attributes = assert(function( div ) {
1480
+ div.className = "i";
1481
+ return !div.getAttribute("className");
1482
+ });
1483
+
1484
+ /* getElement(s)By*
1485
+ ---------------------------------------------------------------------- */
1486
+
1487
+ // Check if getElementsByTagName("*") returns only elements
1488
+ support.getElementsByTagName = assert(function( div ) {
1489
+ div.appendChild( doc.createComment("") );
1490
+ return !div.getElementsByTagName("*").length;
1491
+ });
1492
+
1493
+ // Check if getElementsByClassName can be trusted
1494
+ support.getElementsByClassName = assert(function( div ) {
1495
+ div.innerHTML = "<div class='a'></div><div class='a i'></div>";
1496
+
1497
+ // Support: Safari<4
1498
+ // Catch class over-caching
1499
+ div.firstChild.className = "i";
1500
+ // Support: Opera<10
1501
+ // Catch gEBCN failure to find non-leading classes
1502
+ return div.getElementsByClassName("i").length === 2;
1503
+ });
1504
+
1505
+ // Support: IE<10
1506
+ // Check if getElementById returns elements by name
1507
+ // The broken getElementById methods don't pick up programatically-set names,
1508
+ // so use a roundabout getElementsByName test
1509
+ support.getById = assert(function( div ) {
1510
+ docElem.appendChild( div ).id = expando;
1511
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
1512
+ });
1513
+
1514
+ // ID find and filter
1515
+ if ( support.getById ) {
1516
+ Expr.find["ID"] = function( id, context ) {
1517
+ if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
1518
+ var m = context.getElementById( id );
1519
+ // Check parentNode to catch when Blackberry 4.6 returns
1520
+ // nodes that are no longer in the document #6963
1521
+ return m && m.parentNode ? [m] : [];
1522
+ }
1523
+ };
1524
+ Expr.filter["ID"] = function( id ) {
1525
+ var attrId = id.replace( runescape, funescape );
1526
+ return function( elem ) {
1527
+ return elem.getAttribute("id") === attrId;
1528
+ };
1529
+ };
1530
+ } else {
1531
+ // Support: IE6/7
1532
+ // getElementById is not reliable as a find shortcut
1533
+ delete Expr.find["ID"];
1534
+
1535
+ Expr.filter["ID"] = function( id ) {
1536
+ var attrId = id.replace( runescape, funescape );
1537
+ return function( elem ) {
1538
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
1539
+ return node && node.value === attrId;
1540
+ };
1541
+ };
1542
+ }
1543
+
1544
+ // Tag
1545
+ Expr.find["TAG"] = support.getElementsByTagName ?
1546
+ function( tag, context ) {
1547
+ if ( typeof context.getElementsByTagName !== strundefined ) {
1548
+ return context.getElementsByTagName( tag );
1549
+ }
1550
+ } :
1551
+ function( tag, context ) {
1552
+ var elem,
1553
+ tmp = [],
1554
+ i = 0,
1555
+ results = context.getElementsByTagName( tag );
1556
+
1557
+ // Filter out possible comments
1558
+ if ( tag === "*" ) {
1559
+ while ( (elem = results[i++]) ) {
1560
+ if ( elem.nodeType === 1 ) {
1561
+ tmp.push( elem );
1562
+ }
1563
+ }
1564
+
1565
+ return tmp;
1566
+ }
1567
+ return results;
1568
+ };
1569
+
1570
+ // Class
1571
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1572
+ if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
1573
+ return context.getElementsByClassName( className );
1574
+ }
1575
+ };
1576
+
1577
+ /* QSA/matchesSelector
1578
+ ---------------------------------------------------------------------- */
1579
+
1580
+ // QSA and matchesSelector support
1581
+
1582
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1583
+ rbuggyMatches = [];
1584
+
1585
+ // qSa(:focus) reports false when true (Chrome 21)
1586
+ // We allow this because of a bug in IE8/9 that throws an error
1587
+ // whenever `document.activeElement` is accessed on an iframe
1588
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
1589
+ // See http://bugs.jquery.com/ticket/13378
1590
+ rbuggyQSA = [];
1591
+
1592
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
1593
+ // Build QSA regex
1594
+ // Regex strategy adopted from Diego Perini
1595
+ assert(function( div ) {
1596
+ // Select is set to empty string on purpose
1597
+ // This is to test IE's treatment of not explicitly
1598
+ // setting a boolean content attribute,
1599
+ // since its presence should be enough
1600
+ // http://bugs.jquery.com/ticket/12359
1601
+ div.innerHTML = "<select><option selected=''></option></select>";
1602
+
1603
+ // Support: IE8
1604
+ // Boolean attributes and "value" are not treated correctly
1605
+ if ( !div.querySelectorAll("[selected]").length ) {
1606
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1607
+ }
1608
+
1609
+ // Webkit/Opera - :checked should return selected option elements
1610
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1611
+ // IE8 throws error here and will not see later tests
1612
+ if ( !div.querySelectorAll(":checked").length ) {
1613
+ rbuggyQSA.push(":checked");
1614
+ }
1615
+ });
1616
+
1617
+ assert(function( div ) {
1618
+
1619
+ // Support: Opera 10-12/IE8
1620
+ // ^= $= *= and empty values
1621
+ // Should not select anything
1622
+ // Support: Windows 8 Native Apps
1623
+ // The type attribute is restricted during .innerHTML assignment
1624
+ var input = doc.createElement("input");
1625
+ input.setAttribute( "type", "hidden" );
1626
+ div.appendChild( input ).setAttribute( "t", "" );
1627
+
1628
+ if ( div.querySelectorAll("[t^='']").length ) {
1629
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1630
+ }
1631
+
1632
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1633
+ // IE8 throws error here and will not see later tests
1634
+ if ( !div.querySelectorAll(":enabled").length ) {
1635
+ rbuggyQSA.push( ":enabled", ":disabled" );
1636
+ }
1637
+
1638
+ // Opera 10-11 does not throw on post-comma invalid pseudos
1639
+ div.querySelectorAll("*,:x");
1640
+ rbuggyQSA.push(",.*:");
1641
+ });
1642
+ }
1643
+
1644
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
1645
+ docElem.mozMatchesSelector ||
1646
+ docElem.oMatchesSelector ||
1647
+ docElem.msMatchesSelector) )) ) {
1648
+
1649
+ assert(function( div ) {
1650
+ // Check to see if it's possible to do matchesSelector
1651
+ // on a disconnected node (IE 9)
1652
+ support.disconnectedMatch = matches.call( div, "div" );
1653
+
1654
+ // This should fail with an exception
1655
+ // Gecko does not error, returns false instead
1656
+ matches.call( div, "[s!='']:x" );
1657
+ rbuggyMatches.push( "!=", pseudos );
1658
+ });
1659
+ }
1660
+
1661
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1662
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1663
+
1664
+ /* Contains
1665
+ ---------------------------------------------------------------------- */
1666
+
1667
+ // Element contains another
1668
+ // Purposefully does not implement inclusive descendent
1669
+ // As in, an element does not contain itself
1670
+ contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
1671
+ function( a, b ) {
1672
+ var adown = a.nodeType === 9 ? a.documentElement : a,
1673
+ bup = b && b.parentNode;
1674
+ return a === bup || !!( bup && bup.nodeType === 1 && (
1675
+ adown.contains ?
1676
+ adown.contains( bup ) :
1677
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1678
+ ));
1679
+ } :
1680
+ function( a, b ) {
1681
+ if ( b ) {
1682
+ while ( (b = b.parentNode) ) {
1683
+ if ( b === a ) {
1684
+ return true;
1685
+ }
1686
+ }
1687
+ }
1688
+ return false;
1689
+ };
1690
+
1691
+ /* Sorting
1692
+ ---------------------------------------------------------------------- */
1693
+
1694
+ // Document order sorting
1695
+ sortOrder = docElem.compareDocumentPosition ?
1696
+ function( a, b ) {
1697
+
1698
+ // Flag for duplicate removal
1699
+ if ( a === b ) {
1700
+ hasDuplicate = true;
1701
+ return 0;
1702
+ }
1703
+
1704
+ var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
1705
+
1706
+ if ( compare ) {
1707
+ // Disconnected nodes
1708
+ if ( compare & 1 ||
1709
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1710
+
1711
+ // Choose the first element that is related to our preferred document
1712
+ if ( a === doc || contains(preferredDoc, a) ) {
1713
+ return -1;
1714
+ }
1715
+ if ( b === doc || contains(preferredDoc, b) ) {
1716
+ return 1;
1717
+ }
1718
+
1719
+ // Maintain original order
1720
+ return sortInput ?
1721
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1722
+ 0;
1723
+ }
1724
+
1725
+ return compare & 4 ? -1 : 1;
1726
+ }
1727
+
1728
+ // Not directly comparable, sort on existence of method
1729
+ return a.compareDocumentPosition ? -1 : 1;
1730
+ } :
1731
+ function( a, b ) {
1732
+ var cur,
1733
+ i = 0,
1734
+ aup = a.parentNode,
1735
+ bup = b.parentNode,
1736
+ ap = [ a ],
1737
+ bp = [ b ];
1738
+
1739
+ // Exit early if the nodes are identical
1740
+ if ( a === b ) {
1741
+ hasDuplicate = true;
1742
+ return 0;
1743
+
1744
+ // Parentless nodes are either documents or disconnected
1745
+ } else if ( !aup || !bup ) {
1746
+ return a === doc ? -1 :
1747
+ b === doc ? 1 :
1748
+ aup ? -1 :
1749
+ bup ? 1 :
1750
+ sortInput ?
1751
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1752
+ 0;
1753
+
1754
+ // If the nodes are siblings, we can do a quick check
1755
+ } else if ( aup === bup ) {
1756
+ return siblingCheck( a, b );
1757
+ }
1758
+
1759
+ // Otherwise we need full lists of their ancestors for comparison
1760
+ cur = a;
1761
+ while ( (cur = cur.parentNode) ) {
1762
+ ap.unshift( cur );
1763
+ }
1764
+ cur = b;
1765
+ while ( (cur = cur.parentNode) ) {
1766
+ bp.unshift( cur );
1767
+ }
1768
+
1769
+ // Walk down the tree looking for a discrepancy
1770
+ while ( ap[i] === bp[i] ) {
1771
+ i++;
1772
+ }
1773
+
1774
+ return i ?
1775
+ // Do a sibling check if the nodes have a common ancestor
1776
+ siblingCheck( ap[i], bp[i] ) :
1777
+
1778
+ // Otherwise nodes in our document sort first
1779
+ ap[i] === preferredDoc ? -1 :
1780
+ bp[i] === preferredDoc ? 1 :
1781
+ 0;
1782
+ };
1783
+
1784
+ return doc;
1785
+ };
1786
+
1787
+ Sizzle.matches = function( expr, elements ) {
1788
+ return Sizzle( expr, null, null, elements );
1789
+ };
1790
+
1791
+ Sizzle.matchesSelector = function( elem, expr ) {
1792
+ // Set document vars if needed
1793
+ if ( ( elem.ownerDocument || elem ) !== document ) {
1794
+ setDocument( elem );
1795
+ }
1796
+
1797
+ // Make sure that attribute selectors are quoted
1798
+ expr = expr.replace( rattributeQuotes, "='$1']" );
1799
+
1800
+ if ( support.matchesSelector && documentIsHTML &&
1801
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1802
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
1803
+
1804
+ try {
1805
+ var ret = matches.call( elem, expr );
1806
+
1807
+ // IE 9's matchesSelector returns false on disconnected nodes
1808
+ if ( ret || support.disconnectedMatch ||
1809
+ // As well, disconnected nodes are said to be in a document
1810
+ // fragment in IE 9
1811
+ elem.document && elem.document.nodeType !== 11 ) {
1812
+ return ret;
1813
+ }
1814
+ } catch(e) {}
1815
+ }
1816
+
1817
+ return Sizzle( expr, document, null, [elem] ).length > 0;
1818
+ };
1819
+
1820
+ Sizzle.contains = function( context, elem ) {
1821
+ // Set document vars if needed
1822
+ if ( ( context.ownerDocument || context ) !== document ) {
1823
+ setDocument( context );
1824
+ }
1825
+ return contains( context, elem );
1826
+ };
1827
+
1828
+ Sizzle.attr = function( elem, name ) {
1829
+ // Set document vars if needed
1830
+ if ( ( elem.ownerDocument || elem ) !== document ) {
1831
+ setDocument( elem );
1832
+ }
1833
+
1834
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
1835
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
1836
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1837
+ fn( elem, name, !documentIsHTML ) :
1838
+ undefined;
1839
+
1840
+ return val === undefined ?
1841
+ support.attributes || !documentIsHTML ?
1842
+ elem.getAttribute( name ) :
1843
+ (val = elem.getAttributeNode(name)) && val.specified ?
1844
+ val.value :
1845
+ null :
1846
+ val;
1847
+ };
1848
+
1849
+ Sizzle.error = function( msg ) {
1850
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
1851
+ };
1852
+
1853
+ /**
1854
+ * Document sorting and removing duplicates
1855
+ * @param {ArrayLike} results
1856
+ */
1857
+ Sizzle.uniqueSort = function( results ) {
1858
+ var elem,
1859
+ duplicates = [],
1860
+ j = 0,
1861
+ i = 0;
1862
+
1863
+ // Unless we *know* we can detect duplicates, assume their presence
1864
+ hasDuplicate = !support.detectDuplicates;
1865
+ sortInput = !support.sortStable && results.slice( 0 );
1866
+ results.sort( sortOrder );
1867
+
1868
+ if ( hasDuplicate ) {
1869
+ while ( (elem = results[i++]) ) {
1870
+ if ( elem === results[ i ] ) {
1871
+ j = duplicates.push( i );
1872
+ }
1873
+ }
1874
+ while ( j-- ) {
1875
+ results.splice( duplicates[ j ], 1 );
1876
+ }
1877
+ }
1878
+
1879
+ return results;
1880
+ };
1881
+
1882
+ /**
1883
+ * Utility function for retrieving the text value of an array of DOM nodes
1884
+ * @param {Array|Element} elem
1885
+ */
1886
+ getText = Sizzle.getText = function( elem ) {
1887
+ var node,
1888
+ ret = "",
1889
+ i = 0,
1890
+ nodeType = elem.nodeType;
1891
+
1892
+ if ( !nodeType ) {
1893
+ // If no nodeType, this is expected to be an array
1894
+ for ( ; (node = elem[i]); i++ ) {
1895
+ // Do not traverse comment nodes
1896
+ ret += getText( node );
1897
+ }
1898
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1899
+ // Use textContent for elements
1900
+ // innerText usage removed for consistency of new lines (see #11153)
1901
+ if ( typeof elem.textContent === "string" ) {
1902
+ return elem.textContent;
1903
+ } else {
1904
+ // Traverse its children
1905
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1906
+ ret += getText( elem );
1907
+ }
1908
+ }
1909
+ } else if ( nodeType === 3 || nodeType === 4 ) {
1910
+ return elem.nodeValue;
1911
+ }
1912
+ // Do not include comment or processing instruction nodes
1913
+
1914
+ return ret;
1915
+ };
1916
+
1917
+ Expr = Sizzle.selectors = {
1918
+
1919
+ // Can be adjusted by the user
1920
+ cacheLength: 50,
1921
+
1922
+ createPseudo: markFunction,
1923
+
1924
+ match: matchExpr,
1925
+
1926
+ attrHandle: {},
1927
+
1928
+ find: {},
1929
+
1930
+ relative: {
1931
+ ">": { dir: "parentNode", first: true },
1932
+ " ": { dir: "parentNode" },
1933
+ "+": { dir: "previousSibling", first: true },
1934
+ "~": { dir: "previousSibling" }
1935
+ },
1936
+
1937
+ preFilter: {
1938
+ "ATTR": function( match ) {
1939
+ match[1] = match[1].replace( runescape, funescape );
1940
+
1941
+ // Move the given value to match[3] whether quoted or unquoted
1942
+ match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
1943
+
1944
+ if ( match[2] === "~=" ) {
1945
+ match[3] = " " + match[3] + " ";
1946
+ }
1947
+
1948
+ return match.slice( 0, 4 );
1949
+ },
1950
+
1951
+ "CHILD": function( match ) {
1952
+ /* matches from matchExpr["CHILD"]
1953
+ 1 type (only|nth|...)
1954
+ 2 what (child|of-type)
1955
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1956
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
1957
+ 5 sign of xn-component
1958
+ 6 x of xn-component
1959
+ 7 sign of y-component
1960
+ 8 y of y-component
1961
+ */
1962
+ match[1] = match[1].toLowerCase();
1963
+
1964
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
1965
+ // nth-* requires argument
1966
+ if ( !match[3] ) {
1967
+ Sizzle.error( match[0] );
1968
+ }
1969
+
1970
+ // numeric x and y parameters for Expr.filter.CHILD
1971
+ // remember that false/true cast respectively to 0/1
1972
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1973
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1974
+
1975
+ // other types prohibit arguments
1976
+ } else if ( match[3] ) {
1977
+ Sizzle.error( match[0] );
1978
+ }
1979
+
1980
+ return match;
1981
+ },
1982
+
1983
+ "PSEUDO": function( match ) {
1984
+ var excess,
1985
+ unquoted = !match[5] && match[2];
1986
+
1987
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
1988
+ return null;
1989
+ }
1990
+
1991
+ // Accept quoted arguments as-is
1992
+ if ( match[3] && match[4] !== undefined ) {
1993
+ match[2] = match[4];
1994
+
1995
+ // Strip excess characters from unquoted arguments
1996
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
1997
+ // Get excess from tokenize (recursively)
1998
+ (excess = tokenize( unquoted, true )) &&
1999
+ // advance to the next closing parenthesis
2000
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
2001
+
2002
+ // excess is a negative index
2003
+ match[0] = match[0].slice( 0, excess );
2004
+ match[2] = unquoted.slice( 0, excess );
2005
+ }
2006
+
2007
+ // Return only captures needed by the pseudo filter method (type and argument)
2008
+ return match.slice( 0, 3 );
2009
+ }
2010
+ },
2011
+
2012
+ filter: {
2013
+
2014
+ "TAG": function( nodeNameSelector ) {
2015
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
2016
+ return nodeNameSelector === "*" ?
2017
+ function() { return true; } :
2018
+ function( elem ) {
2019
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
2020
+ };
2021
+ },
2022
+
2023
+ "CLASS": function( className ) {
2024
+ var pattern = classCache[ className + " " ];
2025
+
2026
+ return pattern ||
2027
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
2028
+ classCache( className, function( elem ) {
2029
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
2030
+ });
2031
+ },
2032
+
2033
+ "ATTR": function( name, operator, check ) {
2034
+ return function( elem ) {
2035
+ var result = Sizzle.attr( elem, name );
2036
+
2037
+ if ( result == null ) {
2038
+ return operator === "!=";
2039
+ }
2040
+ if ( !operator ) {
2041
+ return true;
2042
+ }
2043
+
2044
+ result += "";
2045
+
2046
+ return operator === "=" ? result === check :
2047
+ operator === "!=" ? result !== check :
2048
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
2049
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
2050
+ operator === "$=" ? check && result.slice( -check.length ) === check :
2051
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
2052
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
2053
+ false;
2054
+ };
2055
+ },
2056
+
2057
+ "CHILD": function( type, what, argument, first, last ) {
2058
+ var simple = type.slice( 0, 3 ) !== "nth",
2059
+ forward = type.slice( -4 ) !== "last",
2060
+ ofType = what === "of-type";
2061
+
2062
+ return first === 1 && last === 0 ?
2063
+
2064
+ // Shortcut for :nth-*(n)
2065
+ function( elem ) {
2066
+ return !!elem.parentNode;
2067
+ } :
2068
+
2069
+ function( elem, context, xml ) {
2070
+ var cache, outerCache, node, diff, nodeIndex, start,
2071
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
2072
+ parent = elem.parentNode,
2073
+ name = ofType && elem.nodeName.toLowerCase(),
2074
+ useCache = !xml && !ofType;
2075
+
2076
+ if ( parent ) {
2077
+
2078
+ // :(first|last|only)-(child|of-type)
2079
+ if ( simple ) {
2080
+ while ( dir ) {
2081
+ node = elem;
2082
+ while ( (node = node[ dir ]) ) {
2083
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
2084
+ return false;
2085
+ }
2086
+ }
2087
+ // Reverse direction for :only-* (if we haven't yet done so)
2088
+ start = dir = type === "only" && !start && "nextSibling";
2089
+ }
2090
+ return true;
2091
+ }
2092
+
2093
+ start = [ forward ? parent.firstChild : parent.lastChild ];
2094
+
2095
+ // non-xml :nth-child(...) stores cache data on `parent`
2096
+ if ( forward && useCache ) {
2097
+ // Seek `elem` from a previously-cached index
2098
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
2099
+ cache = outerCache[ type ] || [];
2100
+ nodeIndex = cache[0] === dirruns && cache[1];
2101
+ diff = cache[0] === dirruns && cache[2];
2102
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
2103
+
2104
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
2105
+
2106
+ // Fallback to seeking `elem` from the start
2107
+ (diff = nodeIndex = 0) || start.pop()) ) {
2108
+
2109
+ // When found, cache indexes on `parent` and break
2110
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
2111
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
2112
+ break;
2113
+ }
2114
+ }
2115
+
2116
+ // Use previously-cached element index if available
2117
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
2118
+ diff = cache[1];
2119
+
2120
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
2121
+ } else {
2122
+ // Use the same loop as above to seek `elem` from the start
2123
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
2124
+ (diff = nodeIndex = 0) || start.pop()) ) {
2125
+
2126
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
2127
+ // Cache the index of each encountered element
2128
+ if ( useCache ) {
2129
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
2130
+ }
2131
+
2132
+ if ( node === elem ) {
2133
+ break;
2134
+ }
2135
+ }
2136
+ }
2137
+ }
2138
+
2139
+ // Incorporate the offset, then check against cycle size
2140
+ diff -= last;
2141
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
2142
+ }
2143
+ };
2144
+ },
2145
+
2146
+ "PSEUDO": function( pseudo, argument ) {
2147
+ // pseudo-class names are case-insensitive
2148
+ // http://www.w3.org/TR/selectors/#pseudo-classes
2149
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
2150
+ // Remember that setFilters inherits from pseudos
2151
+ var args,
2152
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
2153
+ Sizzle.error( "unsupported pseudo: " + pseudo );
2154
+
2155
+ // The user may use createPseudo to indicate that
2156
+ // arguments are needed to create the filter function
2157
+ // just as Sizzle does
2158
+ if ( fn[ expando ] ) {
2159
+ return fn( argument );
2160
+ }
2161
+
2162
+ // But maintain support for old signatures
2163
+ if ( fn.length > 1 ) {
2164
+ args = [ pseudo, pseudo, "", argument ];
2165
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
2166
+ markFunction(function( seed, matches ) {
2167
+ var idx,
2168
+ matched = fn( seed, argument ),
2169
+ i = matched.length;
2170
+ while ( i-- ) {
2171
+ idx = indexOf.call( seed, matched[i] );
2172
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
2173
+ }
2174
+ }) :
2175
+ function( elem ) {
2176
+ return fn( elem, 0, args );
2177
+ };
2178
+ }
2179
+
2180
+ return fn;
2181
+ }
2182
+ },
2183
+
2184
+ pseudos: {
2185
+ // Potentially complex pseudos
2186
+ "not": markFunction(function( selector ) {
2187
+ // Trim the selector passed to compile
2188
+ // to avoid treating leading and trailing
2189
+ // spaces as combinators
2190
+ var input = [],
2191
+ results = [],
2192
+ matcher = compile( selector.replace( rtrim, "$1" ) );
2193
+
2194
+ return matcher[ expando ] ?
2195
+ markFunction(function( seed, matches, context, xml ) {
2196
+ var elem,
2197
+ unmatched = matcher( seed, null, xml, [] ),
2198
+ i = seed.length;
2199
+
2200
+ // Match elements unmatched by `matcher`
2201
+ while ( i-- ) {
2202
+ if ( (elem = unmatched[i]) ) {
2203
+ seed[i] = !(matches[i] = elem);
2204
+ }
2205
+ }
2206
+ }) :
2207
+ function( elem, context, xml ) {
2208
+ input[0] = elem;
2209
+ matcher( input, null, xml, results );
2210
+ return !results.pop();
2211
+ };
2212
+ }),
2213
+
2214
+ "has": markFunction(function( selector ) {
2215
+ return function( elem ) {
2216
+ return Sizzle( selector, elem ).length > 0;
2217
+ };
2218
+ }),
2219
+
2220
+ "contains": markFunction(function( text ) {
2221
+ return function( elem ) {
2222
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
2223
+ };
2224
+ }),
2225
+
2226
+ // "Whether an element is represented by a :lang() selector
2227
+ // is based solely on the element's language value
2228
+ // being equal to the identifier C,
2229
+ // or beginning with the identifier C immediately followed by "-".
2230
+ // The matching of C against the element's language value is performed case-insensitively.
2231
+ // The identifier C does not have to be a valid language name."
2232
+ // http://www.w3.org/TR/selectors/#lang-pseudo
2233
+ "lang": markFunction( function( lang ) {
2234
+ // lang value must be a valid identifier
2235
+ if ( !ridentifier.test(lang || "") ) {
2236
+ Sizzle.error( "unsupported lang: " + lang );
2237
+ }
2238
+ lang = lang.replace( runescape, funescape ).toLowerCase();
2239
+ return function( elem ) {
2240
+ var elemLang;
2241
+ do {
2242
+ if ( (elemLang = documentIsHTML ?
2243
+ elem.lang :
2244
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2245
+
2246
+ elemLang = elemLang.toLowerCase();
2247
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2248
+ }
2249
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2250
+ return false;
2251
+ };
2252
+ }),
2253
+
2254
+ // Miscellaneous
2255
+ "target": function( elem ) {
2256
+ var hash = window.location && window.location.hash;
2257
+ return hash && hash.slice( 1 ) === elem.id;
2258
+ },
2259
+
2260
+ "root": function( elem ) {
2261
+ return elem === docElem;
2262
+ },
2263
+
2264
+ "focus": function( elem ) {
2265
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2266
+ },
2267
+
2268
+ // Boolean properties
2269
+ "enabled": function( elem ) {
2270
+ return elem.disabled === false;
2271
+ },
2272
+
2273
+ "disabled": function( elem ) {
2274
+ return elem.disabled === true;
2275
+ },
2276
+
2277
+ "checked": function( elem ) {
2278
+ // In CSS3, :checked should return both checked and selected elements
2279
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2280
+ var nodeName = elem.nodeName.toLowerCase();
2281
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2282
+ },
2283
+
2284
+ "selected": function( elem ) {
2285
+ // Accessing this property makes selected-by-default
2286
+ // options in Safari work properly
2287
+ if ( elem.parentNode ) {
2288
+ elem.parentNode.selectedIndex;
2289
+ }
2290
+
2291
+ return elem.selected === true;
2292
+ },
2293
+
2294
+ // Contents
2295
+ "empty": function( elem ) {
2296
+ // http://www.w3.org/TR/selectors/#empty-pseudo
2297
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
2298
+ // not comment, processing instructions, or others
2299
+ // Thanks to Diego Perini for the nodeName shortcut
2300
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
2301
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2302
+ if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
2303
+ return false;
2304
+ }
2305
+ }
2306
+ return true;
2307
+ },
2308
+
2309
+ "parent": function( elem ) {
2310
+ return !Expr.pseudos["empty"]( elem );
2311
+ },
2312
+
2313
+ // Element/input types
2314
+ "header": function( elem ) {
2315
+ return rheader.test( elem.nodeName );
2316
+ },
2317
+
2318
+ "input": function( elem ) {
2319
+ return rinputs.test( elem.nodeName );
2320
+ },
2321
+
2322
+ "button": function( elem ) {
2323
+ var name = elem.nodeName.toLowerCase();
2324
+ return name === "input" && elem.type === "button" || name === "button";
2325
+ },
2326
+
2327
+ "text": function( elem ) {
2328
+ var attr;
2329
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
2330
+ // use getAttribute instead to test this case
2331
+ return elem.nodeName.toLowerCase() === "input" &&
2332
+ elem.type === "text" &&
2333
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
2334
+ },
2335
+
2336
+ // Position-in-collection
2337
+ "first": createPositionalPseudo(function() {
2338
+ return [ 0 ];
2339
+ }),
2340
+
2341
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
2342
+ return [ length - 1 ];
2343
+ }),
2344
+
2345
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2346
+ return [ argument < 0 ? argument + length : argument ];
2347
+ }),
2348
+
2349
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
2350
+ var i = 0;
2351
+ for ( ; i < length; i += 2 ) {
2352
+ matchIndexes.push( i );
2353
+ }
2354
+ return matchIndexes;
2355
+ }),
2356
+
2357
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
2358
+ var i = 1;
2359
+ for ( ; i < length; i += 2 ) {
2360
+ matchIndexes.push( i );
2361
+ }
2362
+ return matchIndexes;
2363
+ }),
2364
+
2365
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2366
+ var i = argument < 0 ? argument + length : argument;
2367
+ for ( ; --i >= 0; ) {
2368
+ matchIndexes.push( i );
2369
+ }
2370
+ return matchIndexes;
2371
+ }),
2372
+
2373
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2374
+ var i = argument < 0 ? argument + length : argument;
2375
+ for ( ; ++i < length; ) {
2376
+ matchIndexes.push( i );
2377
+ }
2378
+ return matchIndexes;
2379
+ })
2380
+ }
2381
+ };
2382
+
2383
+ Expr.pseudos["nth"] = Expr.pseudos["eq"];
2384
+
2385
+ // Add button/input type pseudos
2386
+ for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2387
+ Expr.pseudos[ i ] = createInputPseudo( i );
2388
+ }
2389
+ for ( i in { submit: true, reset: true } ) {
2390
+ Expr.pseudos[ i ] = createButtonPseudo( i );
2391
+ }
2392
+
2393
+ // Easy API for creating new setFilters
2394
+ function setFilters() {}
2395
+ setFilters.prototype = Expr.filters = Expr.pseudos;
2396
+ Expr.setFilters = new setFilters();
2397
+
2398
+ function tokenize( selector, parseOnly ) {
2399
+ var matched, match, tokens, type,
2400
+ soFar, groups, preFilters,
2401
+ cached = tokenCache[ selector + " " ];
2402
+
2403
+ if ( cached ) {
2404
+ return parseOnly ? 0 : cached.slice( 0 );
2405
+ }
2406
+
2407
+ soFar = selector;
2408
+ groups = [];
2409
+ preFilters = Expr.preFilter;
2410
+
2411
+ while ( soFar ) {
2412
+
2413
+ // Comma and first run
2414
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
2415
+ if ( match ) {
2416
+ // Don't consume trailing commas as valid
2417
+ soFar = soFar.slice( match[0].length ) || soFar;
2418
+ }
2419
+ groups.push( tokens = [] );
2420
+ }
2421
+
2422
+ matched = false;
2423
+
2424
+ // Combinators
2425
+ if ( (match = rcombinators.exec( soFar )) ) {
2426
+ matched = match.shift();
2427
+ tokens.push({
2428
+ value: matched,
2429
+ // Cast descendant combinators to space
2430
+ type: match[0].replace( rtrim, " " )
2431
+ });
2432
+ soFar = soFar.slice( matched.length );
2433
+ }
2434
+
2435
+ // Filters
2436
+ for ( type in Expr.filter ) {
2437
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2438
+ (match = preFilters[ type ]( match ))) ) {
2439
+ matched = match.shift();
2440
+ tokens.push({
2441
+ value: matched,
2442
+ type: type,
2443
+ matches: match
2444
+ });
2445
+ soFar = soFar.slice( matched.length );
2446
+ }
2447
+ }
2448
+
2449
+ if ( !matched ) {
2450
+ break;
2451
+ }
2452
+ }
2453
+
2454
+ // Return the length of the invalid excess
2455
+ // if we're just parsing
2456
+ // Otherwise, throw an error or return tokens
2457
+ return parseOnly ?
2458
+ soFar.length :
2459
+ soFar ?
2460
+ Sizzle.error( selector ) :
2461
+ // Cache the tokens
2462
+ tokenCache( selector, groups ).slice( 0 );
2463
+ }
2464
+
2465
+ function toSelector( tokens ) {
2466
+ var i = 0,
2467
+ len = tokens.length,
2468
+ selector = "";
2469
+ for ( ; i < len; i++ ) {
2470
+ selector += tokens[i].value;
2471
+ }
2472
+ return selector;
2473
+ }
2474
+
2475
+ function addCombinator( matcher, combinator, base ) {
2476
+ var dir = combinator.dir,
2477
+ checkNonElements = base && dir === "parentNode",
2478
+ doneName = done++;
2479
+
2480
+ return combinator.first ?
2481
+ // Check against closest ancestor/preceding element
2482
+ function( elem, context, xml ) {
2483
+ while ( (elem = elem[ dir ]) ) {
2484
+ if ( elem.nodeType === 1 || checkNonElements ) {
2485
+ return matcher( elem, context, xml );
2486
+ }
2487
+ }
2488
+ } :
2489
+
2490
+ // Check against all ancestor/preceding elements
2491
+ function( elem, context, xml ) {
2492
+ var data, cache, outerCache,
2493
+ dirkey = dirruns + " " + doneName;
2494
+
2495
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
2496
+ if ( xml ) {
2497
+ while ( (elem = elem[ dir ]) ) {
2498
+ if ( elem.nodeType === 1 || checkNonElements ) {
2499
+ if ( matcher( elem, context, xml ) ) {
2500
+ return true;
2501
+ }
2502
+ }
2503
+ }
2504
+ } else {
2505
+ while ( (elem = elem[ dir ]) ) {
2506
+ if ( elem.nodeType === 1 || checkNonElements ) {
2507
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
2508
+ if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
2509
+ if ( (data = cache[1]) === true || data === cachedruns ) {
2510
+ return data === true;
2511
+ }
2512
+ } else {
2513
+ cache = outerCache[ dir ] = [ dirkey ];
2514
+ cache[1] = matcher( elem, context, xml ) || cachedruns;
2515
+ if ( cache[1] === true ) {
2516
+ return true;
2517
+ }
2518
+ }
2519
+ }
2520
+ }
2521
+ }
2522
+ };
2523
+ }
2524
+
2525
+ function elementMatcher( matchers ) {
2526
+ return matchers.length > 1 ?
2527
+ function( elem, context, xml ) {
2528
+ var i = matchers.length;
2529
+ while ( i-- ) {
2530
+ if ( !matchers[i]( elem, context, xml ) ) {
2531
+ return false;
2532
+ }
2533
+ }
2534
+ return true;
2535
+ } :
2536
+ matchers[0];
2537
+ }
2538
+
2539
+ function condense( unmatched, map, filter, context, xml ) {
2540
+ var elem,
2541
+ newUnmatched = [],
2542
+ i = 0,
2543
+ len = unmatched.length,
2544
+ mapped = map != null;
2545
+
2546
+ for ( ; i < len; i++ ) {
2547
+ if ( (elem = unmatched[i]) ) {
2548
+ if ( !filter || filter( elem, context, xml ) ) {
2549
+ newUnmatched.push( elem );
2550
+ if ( mapped ) {
2551
+ map.push( i );
2552
+ }
2553
+ }
2554
+ }
2555
+ }
2556
+
2557
+ return newUnmatched;
2558
+ }
2559
+
2560
+ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2561
+ if ( postFilter && !postFilter[ expando ] ) {
2562
+ postFilter = setMatcher( postFilter );
2563
+ }
2564
+ if ( postFinder && !postFinder[ expando ] ) {
2565
+ postFinder = setMatcher( postFinder, postSelector );
2566
+ }
2567
+ return markFunction(function( seed, results, context, xml ) {
2568
+ var temp, i, elem,
2569
+ preMap = [],
2570
+ postMap = [],
2571
+ preexisting = results.length,
2572
+
2573
+ // Get initial elements from seed or context
2574
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2575
+
2576
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
2577
+ matcherIn = preFilter && ( seed || !selector ) ?
2578
+ condense( elems, preMap, preFilter, context, xml ) :
2579
+ elems,
2580
+
2581
+ matcherOut = matcher ?
2582
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2583
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2584
+
2585
+ // ...intermediate processing is necessary
2586
+ [] :
2587
+
2588
+ // ...otherwise use results directly
2589
+ results :
2590
+ matcherIn;
2591
+
2592
+ // Find primary matches
2593
+ if ( matcher ) {
2594
+ matcher( matcherIn, matcherOut, context, xml );
2595
+ }
2596
+
2597
+ // Apply postFilter
2598
+ if ( postFilter ) {
2599
+ temp = condense( matcherOut, postMap );
2600
+ postFilter( temp, [], context, xml );
2601
+
2602
+ // Un-match failing elements by moving them back to matcherIn
2603
+ i = temp.length;
2604
+ while ( i-- ) {
2605
+ if ( (elem = temp[i]) ) {
2606
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2607
+ }
2608
+ }
2609
+ }
2610
+
2611
+ if ( seed ) {
2612
+ if ( postFinder || preFilter ) {
2613
+ if ( postFinder ) {
2614
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
2615
+ temp = [];
2616
+ i = matcherOut.length;
2617
+ while ( i-- ) {
2618
+ if ( (elem = matcherOut[i]) ) {
2619
+ // Restore matcherIn since elem is not yet a final match
2620
+ temp.push( (matcherIn[i] = elem) );
2621
+ }
2622
+ }
2623
+ postFinder( null, (matcherOut = []), temp, xml );
2624
+ }
2625
+
2626
+ // Move matched elements from seed to results to keep them synchronized
2627
+ i = matcherOut.length;
2628
+ while ( i-- ) {
2629
+ if ( (elem = matcherOut[i]) &&
2630
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
2631
+
2632
+ seed[temp] = !(results[temp] = elem);
2633
+ }
2634
+ }
2635
+ }
2636
+
2637
+ // Add elements to results, through postFinder if defined
2638
+ } else {
2639
+ matcherOut = condense(
2640
+ matcherOut === results ?
2641
+ matcherOut.splice( preexisting, matcherOut.length ) :
2642
+ matcherOut
2643
+ );
2644
+ if ( postFinder ) {
2645
+ postFinder( null, results, matcherOut, xml );
2646
+ } else {
2647
+ push.apply( results, matcherOut );
2648
+ }
2649
+ }
2650
+ });
2651
+ }
2652
+
2653
+ function matcherFromTokens( tokens ) {
2654
+ var checkContext, matcher, j,
2655
+ len = tokens.length,
2656
+ leadingRelative = Expr.relative[ tokens[0].type ],
2657
+ implicitRelative = leadingRelative || Expr.relative[" "],
2658
+ i = leadingRelative ? 1 : 0,
2659
+
2660
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
2661
+ matchContext = addCombinator( function( elem ) {
2662
+ return elem === checkContext;
2663
+ }, implicitRelative, true ),
2664
+ matchAnyContext = addCombinator( function( elem ) {
2665
+ return indexOf.call( checkContext, elem ) > -1;
2666
+ }, implicitRelative, true ),
2667
+ matchers = [ function( elem, context, xml ) {
2668
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2669
+ (checkContext = context).nodeType ?
2670
+ matchContext( elem, context, xml ) :
2671
+ matchAnyContext( elem, context, xml ) );
2672
+ } ];
2673
+
2674
+ for ( ; i < len; i++ ) {
2675
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2676
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2677
+ } else {
2678
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2679
+
2680
+ // Return special upon seeing a positional matcher
2681
+ if ( matcher[ expando ] ) {
2682
+ // Find the next relative operator (if any) for proper handling
2683
+ j = ++i;
2684
+ for ( ; j < len; j++ ) {
2685
+ if ( Expr.relative[ tokens[j].type ] ) {
2686
+ break;
2687
+ }
2688
+ }
2689
+ return setMatcher(
2690
+ i > 1 && elementMatcher( matchers ),
2691
+ i > 1 && toSelector(
2692
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2693
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2694
+ ).replace( rtrim, "$1" ),
2695
+ matcher,
2696
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
2697
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2698
+ j < len && toSelector( tokens )
2699
+ );
2700
+ }
2701
+ matchers.push( matcher );
2702
+ }
2703
+ }
2704
+
2705
+ return elementMatcher( matchers );
2706
+ }
2707
+
2708
+ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2709
+ // A counter to specify which element is currently being matched
2710
+ var matcherCachedRuns = 0,
2711
+ bySet = setMatchers.length > 0,
2712
+ byElement = elementMatchers.length > 0,
2713
+ superMatcher = function( seed, context, xml, results, expandContext ) {
2714
+ var elem, j, matcher,
2715
+ setMatched = [],
2716
+ matchedCount = 0,
2717
+ i = "0",
2718
+ unmatched = seed && [],
2719
+ outermost = expandContext != null,
2720
+ contextBackup = outermostContext,
2721
+ // We must always have either seed elements or context
2722
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
2723
+ // Use integer dirruns iff this is the outermost matcher
2724
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
2725
+
2726
+ if ( outermost ) {
2727
+ outermostContext = context !== document && context;
2728
+ cachedruns = matcherCachedRuns;
2729
+ }
2730
+
2731
+ // Add elements passing elementMatchers directly to results
2732
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
2733
+ for ( ; (elem = elems[i]) != null; i++ ) {
2734
+ if ( byElement && elem ) {
2735
+ j = 0;
2736
+ while ( (matcher = elementMatchers[j++]) ) {
2737
+ if ( matcher( elem, context, xml ) ) {
2738
+ results.push( elem );
2739
+ break;
2740
+ }
2741
+ }
2742
+ if ( outermost ) {
2743
+ dirruns = dirrunsUnique;
2744
+ cachedruns = ++matcherCachedRuns;
2745
+ }
2746
+ }
2747
+
2748
+ // Track unmatched elements for set filters
2749
+ if ( bySet ) {
2750
+ // They will have gone through all possible matchers
2751
+ if ( (elem = !matcher && elem) ) {
2752
+ matchedCount--;
2753
+ }
2754
+
2755
+ // Lengthen the array for every element, matched or not
2756
+ if ( seed ) {
2757
+ unmatched.push( elem );
2758
+ }
2759
+ }
2760
+ }
2761
+
2762
+ // Apply set filters to unmatched elements
2763
+ matchedCount += i;
2764
+ if ( bySet && i !== matchedCount ) {
2765
+ j = 0;
2766
+ while ( (matcher = setMatchers[j++]) ) {
2767
+ matcher( unmatched, setMatched, context, xml );
2768
+ }
2769
+
2770
+ if ( seed ) {
2771
+ // Reintegrate element matches to eliminate the need for sorting
2772
+ if ( matchedCount > 0 ) {
2773
+ while ( i-- ) {
2774
+ if ( !(unmatched[i] || setMatched[i]) ) {
2775
+ setMatched[i] = pop.call( results );
2776
+ }
2777
+ }
2778
+ }
2779
+
2780
+ // Discard index placeholder values to get only actual matches
2781
+ setMatched = condense( setMatched );
2782
+ }
2783
+
2784
+ // Add matches to results
2785
+ push.apply( results, setMatched );
2786
+
2787
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
2788
+ if ( outermost && !seed && setMatched.length > 0 &&
2789
+ ( matchedCount + setMatchers.length ) > 1 ) {
2790
+
2791
+ Sizzle.uniqueSort( results );
2792
+ }
2793
+ }
2794
+
2795
+ // Override manipulation of globals by nested matchers
2796
+ if ( outermost ) {
2797
+ dirruns = dirrunsUnique;
2798
+ outermostContext = contextBackup;
2799
+ }
2800
+
2801
+ return unmatched;
2802
+ };
2803
+
2804
+ return bySet ?
2805
+ markFunction( superMatcher ) :
2806
+ superMatcher;
2807
+ }
2808
+
2809
+ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
2810
+ var i,
2811
+ setMatchers = [],
2812
+ elementMatchers = [],
2813
+ cached = compilerCache[ selector + " " ];
2814
+
2815
+ if ( !cached ) {
2816
+ // Generate a function of recursive functions that can be used to check each element
2817
+ if ( !group ) {
2818
+ group = tokenize( selector );
2819
+ }
2820
+ i = group.length;
2821
+ while ( i-- ) {
2822
+ cached = matcherFromTokens( group[i] );
2823
+ if ( cached[ expando ] ) {
2824
+ setMatchers.push( cached );
2825
+ } else {
2826
+ elementMatchers.push( cached );
2827
+ }
2828
+ }
2829
+
2830
+ // Cache the compiled function
2831
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2832
+ }
2833
+ return cached;
2834
+ };
2835
+
2836
+ function multipleContexts( selector, contexts, results ) {
2837
+ var i = 0,
2838
+ len = contexts.length;
2839
+ for ( ; i < len; i++ ) {
2840
+ Sizzle( selector, contexts[i], results );
2841
+ }
2842
+ return results;
2843
+ }
2844
+
2845
+ function select( selector, context, results, seed ) {
2846
+ var i, tokens, token, type, find,
2847
+ match = tokenize( selector );
2848
+
2849
+ if ( !seed ) {
2850
+ // Try to minimize operations if there is only one group
2851
+ if ( match.length === 1 ) {
2852
+
2853
+ // Take a shortcut and set the context if the root selector is an ID
2854
+ tokens = match[0] = match[0].slice( 0 );
2855
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2856
+ support.getById && context.nodeType === 9 && documentIsHTML &&
2857
+ Expr.relative[ tokens[1].type ] ) {
2858
+
2859
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2860
+ if ( !context ) {
2861
+ return results;
2862
+ }
2863
+ selector = selector.slice( tokens.shift().value.length );
2864
+ }
2865
+
2866
+ // Fetch a seed set for right-to-left matching
2867
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2868
+ while ( i-- ) {
2869
+ token = tokens[i];
2870
+
2871
+ // Abort if we hit a combinator
2872
+ if ( Expr.relative[ (type = token.type) ] ) {
2873
+ break;
2874
+ }
2875
+ if ( (find = Expr.find[ type ]) ) {
2876
+ // Search, expanding context for leading sibling combinators
2877
+ if ( (seed = find(
2878
+ token.matches[0].replace( runescape, funescape ),
2879
+ rsibling.test( tokens[0].type ) && context.parentNode || context
2880
+ )) ) {
2881
+
2882
+ // If seed is empty or no tokens remain, we can return early
2883
+ tokens.splice( i, 1 );
2884
+ selector = seed.length && toSelector( tokens );
2885
+ if ( !selector ) {
2886
+ push.apply( results, seed );
2887
+ return results;
2888
+ }
2889
+
2890
+ break;
2891
+ }
2892
+ }
2893
+ }
2894
+ }
2895
+ }
2896
+
2897
+ // Compile and execute a filtering function
2898
+ // Provide `match` to avoid retokenization if we modified the selector above
2899
+ compile( selector, match )(
2900
+ seed,
2901
+ context,
2902
+ !documentIsHTML,
2903
+ results,
2904
+ rsibling.test( selector )
2905
+ );
2906
+ return results;
2907
+ }
2908
+
2909
+ // One-time assignments
2910
+
2911
+ // Sort stability
2912
+ support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2913
+
2914
+ // Support: Chrome<14
2915
+ // Always assume duplicates if they aren't passed to the comparison function
2916
+ support.detectDuplicates = hasDuplicate;
2917
+
2918
+ // Initialize against the default document
2919
+ setDocument();
2920
+
2921
+ // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2922
+ // Detached nodes confoundingly follow *each other*
2923
+ support.sortDetached = assert(function( div1 ) {
2924
+ // Should return 1, but returns 4 (following)
2925
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2926
+ });
2927
+
2928
+ // Support: IE<8
2929
+ // Prevent attribute/property "interpolation"
2930
+ // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2931
+ if ( !assert(function( div ) {
2932
+ div.innerHTML = "<a href='#'></a>";
2933
+ return div.firstChild.getAttribute("href") === "#" ;
2934
+ }) ) {
2935
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
2936
+ if ( !isXML ) {
2937
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2938
+ }
2939
+ });
2940
+ }
2941
+
2942
+ // Support: IE<9
2943
+ // Use defaultValue in place of getAttribute("value")
2944
+ if ( !support.attributes || !assert(function( div ) {
2945
+ div.innerHTML = "<input/>";
2946
+ div.firstChild.setAttribute( "value", "" );
2947
+ return div.firstChild.getAttribute( "value" ) === "";
2948
+ }) ) {
2949
+ addHandle( "value", function( elem, name, isXML ) {
2950
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2951
+ return elem.defaultValue;
2952
+ }
2953
+ });
2954
+ }
2955
+
2956
+ // Support: IE<9
2957
+ // Use getAttributeNode to fetch booleans when getAttribute lies
2958
+ if ( !assert(function( div ) {
2959
+ return div.getAttribute("disabled") == null;
2960
+ }) ) {
2961
+ addHandle( booleans, function( elem, name, isXML ) {
2962
+ var val;
2963
+ if ( !isXML ) {
2964
+ return (val = elem.getAttributeNode( name )) && val.specified ?
2965
+ val.value :
2966
+ elem[ name ] === true ? name.toLowerCase() : null;
2967
+ }
2968
+ });
2969
+ }
2970
+
2971
+ jQuery.find = Sizzle;
2972
+ jQuery.expr = Sizzle.selectors;
2973
+ jQuery.expr[":"] = jQuery.expr.pseudos;
2974
+ jQuery.unique = Sizzle.uniqueSort;
2975
+ jQuery.text = Sizzle.getText;
2976
+ jQuery.isXMLDoc = Sizzle.isXML;
2977
+ jQuery.contains = Sizzle.contains;
2978
+
2979
+
2980
+ })( window );
2981
+ // String to Object options format cache
2982
+ var optionsCache = {};
2983
+
2984
+ // Convert String-formatted options into Object-formatted ones and store in cache
2985
+ function createOptions( options ) {
2986
+ var object = optionsCache[ options ] = {};
2987
+ jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
2988
+ object[ flag ] = true;
2989
+ });
2990
+ return object;
2991
+ }
2992
+
2993
+ /*
2994
+ * Create a callback list using the following parameters:
2995
+ *
2996
+ * options: an optional list of space-separated options that will change how
2997
+ * the callback list behaves or a more traditional option object
2998
+ *
2999
+ * By default a callback list will act like an event callback list and can be
3000
+ * "fired" multiple times.
3001
+ *
3002
+ * Possible options:
3003
+ *
3004
+ * once: will ensure the callback list can only be fired once (like a Deferred)
3005
+ *
3006
+ * memory: will keep track of previous values and will call any callback added
3007
+ * after the list has been fired right away with the latest "memorized"
3008
+ * values (like a Deferred)
3009
+ *
3010
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
3011
+ *
3012
+ * stopOnFalse: interrupt callings when a callback returns false
3013
+ *
3014
+ */
3015
+ jQuery.Callbacks = function( options ) {
3016
+
3017
+ // Convert options from String-formatted to Object-formatted if needed
3018
+ // (we check in cache first)
3019
+ options = typeof options === "string" ?
3020
+ ( optionsCache[ options ] || createOptions( options ) ) :
3021
+ jQuery.extend( {}, options );
3022
+
3023
+ var // Flag to know if list is currently firing
3024
+ firing,
3025
+ // Last fire value (for non-forgettable lists)
3026
+ memory,
3027
+ // Flag to know if list was already fired
3028
+ fired,
3029
+ // End of the loop when firing
3030
+ firingLength,
3031
+ // Index of currently firing callback (modified by remove if needed)
3032
+ firingIndex,
3033
+ // First callback to fire (used internally by add and fireWith)
3034
+ firingStart,
3035
+ // Actual callback list
3036
+ list = [],
3037
+ // Stack of fire calls for repeatable lists
3038
+ stack = !options.once && [],
3039
+ // Fire callbacks
3040
+ fire = function( data ) {
3041
+ memory = options.memory && data;
3042
+ fired = true;
3043
+ firingIndex = firingStart || 0;
3044
+ firingStart = 0;
3045
+ firingLength = list.length;
3046
+ firing = true;
3047
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
3048
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
3049
+ memory = false; // To prevent further calls using add
3050
+ break;
3051
+ }
3052
+ }
3053
+ firing = false;
3054
+ if ( list ) {
3055
+ if ( stack ) {
3056
+ if ( stack.length ) {
3057
+ fire( stack.shift() );
3058
+ }
3059
+ } else if ( memory ) {
3060
+ list = [];
3061
+ } else {
3062
+ self.disable();
3063
+ }
3064
+ }
3065
+ },
3066
+ // Actual Callbacks object
3067
+ self = {
3068
+ // Add a callback or a collection of callbacks to the list
3069
+ add: function() {
3070
+ if ( list ) {
3071
+ // First, we save the current length
3072
+ var start = list.length;
3073
+ (function add( args ) {
3074
+ jQuery.each( args, function( _, arg ) {
3075
+ var type = jQuery.type( arg );
3076
+ if ( type === "function" ) {
3077
+ if ( !options.unique || !self.has( arg ) ) {
3078
+ list.push( arg );
3079
+ }
3080
+ } else if ( arg && arg.length && type !== "string" ) {
3081
+ // Inspect recursively
3082
+ add( arg );
3083
+ }
3084
+ });
3085
+ })( arguments );
3086
+ // Do we need to add the callbacks to the
3087
+ // current firing batch?
3088
+ if ( firing ) {
3089
+ firingLength = list.length;
3090
+ // With memory, if we're not firing then
3091
+ // we should call right away
3092
+ } else if ( memory ) {
3093
+ firingStart = start;
3094
+ fire( memory );
3095
+ }
3096
+ }
3097
+ return this;
3098
+ },
3099
+ // Remove a callback from the list
3100
+ remove: function() {
3101
+ if ( list ) {
3102
+ jQuery.each( arguments, function( _, arg ) {
3103
+ var index;
3104
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3105
+ list.splice( index, 1 );
3106
+ // Handle firing indexes
3107
+ if ( firing ) {
3108
+ if ( index <= firingLength ) {
3109
+ firingLength--;
3110
+ }
3111
+ if ( index <= firingIndex ) {
3112
+ firingIndex--;
3113
+ }
3114
+ }
3115
+ }
3116
+ });
3117
+ }
3118
+ return this;
3119
+ },
3120
+ // Check if a given callback is in the list.
3121
+ // If no argument is given, return whether or not list has callbacks attached.
3122
+ has: function( fn ) {
3123
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
3124
+ },
3125
+ // Remove all callbacks from the list
3126
+ empty: function() {
3127
+ list = [];
3128
+ firingLength = 0;
3129
+ return this;
3130
+ },
3131
+ // Have the list do nothing anymore
3132
+ disable: function() {
3133
+ list = stack = memory = undefined;
3134
+ return this;
3135
+ },
3136
+ // Is it disabled?
3137
+ disabled: function() {
3138
+ return !list;
3139
+ },
3140
+ // Lock the list in its current state
3141
+ lock: function() {
3142
+ stack = undefined;
3143
+ if ( !memory ) {
3144
+ self.disable();
3145
+ }
3146
+ return this;
3147
+ },
3148
+ // Is it locked?
3149
+ locked: function() {
3150
+ return !stack;
3151
+ },
3152
+ // Call all callbacks with the given context and arguments
3153
+ fireWith: function( context, args ) {
3154
+ if ( list && ( !fired || stack ) ) {
3155
+ args = args || [];
3156
+ args = [ context, args.slice ? args.slice() : args ];
3157
+ if ( firing ) {
3158
+ stack.push( args );
3159
+ } else {
3160
+ fire( args );
3161
+ }
3162
+ }
3163
+ return this;
3164
+ },
3165
+ // Call all the callbacks with the given arguments
3166
+ fire: function() {
3167
+ self.fireWith( this, arguments );
3168
+ return this;
3169
+ },
3170
+ // To know if the callbacks have already been called at least once
3171
+ fired: function() {
3172
+ return !!fired;
3173
+ }
3174
+ };
3175
+
3176
+ return self;
3177
+ };
3178
+ jQuery.extend({
3179
+
3180
+ Deferred: function( func ) {
3181
+ var tuples = [
3182
+ // action, add listener, listener list, final state
3183
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
3184
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
3185
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
3186
+ ],
3187
+ state = "pending",
3188
+ promise = {
3189
+ state: function() {
3190
+ return state;
3191
+ },
3192
+ always: function() {
3193
+ deferred.done( arguments ).fail( arguments );
3194
+ return this;
3195
+ },
3196
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
3197
+ var fns = arguments;
3198
+ return jQuery.Deferred(function( newDefer ) {
3199
+ jQuery.each( tuples, function( i, tuple ) {
3200
+ var action = tuple[ 0 ],
3201
+ fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3202
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
3203
+ deferred[ tuple[1] ](function() {
3204
+ var returned = fn && fn.apply( this, arguments );
3205
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
3206
+ returned.promise()
3207
+ .done( newDefer.resolve )
3208
+ .fail( newDefer.reject )
3209
+ .progress( newDefer.notify );
3210
+ } else {
3211
+ newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
3212
+ }
3213
+ });
3214
+ });
3215
+ fns = null;
3216
+ }).promise();
3217
+ },
3218
+ // Get a promise for this deferred
3219
+ // If obj is provided, the promise aspect is added to the object
3220
+ promise: function( obj ) {
3221
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
3222
+ }
3223
+ },
3224
+ deferred = {};
3225
+
3226
+ // Keep pipe for back-compat
3227
+ promise.pipe = promise.then;
3228
+
3229
+ // Add list-specific methods
3230
+ jQuery.each( tuples, function( i, tuple ) {
3231
+ var list = tuple[ 2 ],
3232
+ stateString = tuple[ 3 ];
3233
+
3234
+ // promise[ done | fail | progress ] = list.add
3235
+ promise[ tuple[1] ] = list.add;
3236
+
3237
+ // Handle state
3238
+ if ( stateString ) {
3239
+ list.add(function() {
3240
+ // state = [ resolved | rejected ]
3241
+ state = stateString;
3242
+
3243
+ // [ reject_list | resolve_list ].disable; progress_list.lock
3244
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3245
+ }
3246
+
3247
+ // deferred[ resolve | reject | notify ]
3248
+ deferred[ tuple[0] ] = function() {
3249
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
3250
+ return this;
3251
+ };
3252
+ deferred[ tuple[0] + "With" ] = list.fireWith;
3253
+ });
3254
+
3255
+ // Make the deferred a promise
3256
+ promise.promise( deferred );
3257
+
3258
+ // Call given func if any
3259
+ if ( func ) {
3260
+ func.call( deferred, deferred );
3261
+ }
3262
+
3263
+ // All done!
3264
+ return deferred;
3265
+ },
3266
+
3267
+ // Deferred helper
3268
+ when: function( subordinate /* , ..., subordinateN */ ) {
3269
+ var i = 0,
3270
+ resolveValues = core_slice.call( arguments ),
3271
+ length = resolveValues.length,
3272
+
3273
+ // the count of uncompleted subordinates
3274
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3275
+
3276
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
3277
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3278
+
3279
+ // Update function for both resolve and progress values
3280
+ updateFunc = function( i, contexts, values ) {
3281
+ return function( value ) {
3282
+ contexts[ i ] = this;
3283
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
3284
+ if( values === progressValues ) {
3285
+ deferred.notifyWith( contexts, values );
3286
+ } else if ( !( --remaining ) ) {
3287
+ deferred.resolveWith( contexts, values );
3288
+ }
3289
+ };
3290
+ },
3291
+
3292
+ progressValues, progressContexts, resolveContexts;
3293
+
3294
+ // add listeners to Deferred subordinates; treat others as resolved
3295
+ if ( length > 1 ) {
3296
+ progressValues = new Array( length );
3297
+ progressContexts = new Array( length );
3298
+ resolveContexts = new Array( length );
3299
+ for ( ; i < length; i++ ) {
3300
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3301
+ resolveValues[ i ].promise()
3302
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
3303
+ .fail( deferred.reject )
3304
+ .progress( updateFunc( i, progressContexts, progressValues ) );
3305
+ } else {
3306
+ --remaining;
3307
+ }
3308
+ }
3309
+ }
3310
+
3311
+ // if we're not waiting on anything, resolve the master
3312
+ if ( !remaining ) {
3313
+ deferred.resolveWith( resolveContexts, resolveValues );
3314
+ }
3315
+
3316
+ return deferred.promise();
3317
+ }
3318
+ });
3319
+ jQuery.support = (function( support ) {
3320
+
3321
+ var all, a, input, select, fragment, opt, eventName, isSupported, i,
3322
+ div = document.createElement("div");
3323
+
3324
+ // Setup
3325
+ div.setAttribute( "className", "t" );
3326
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
3327
+
3328
+ // Finish early in limited (non-browser) environments
3329
+ all = div.getElementsByTagName("*") || [];
3330
+ a = div.getElementsByTagName("a")[ 0 ];
3331
+ if ( !a || !a.style || !all.length ) {
3332
+ return support;
3333
+ }
3334
+
3335
+ // First batch of tests
3336
+ select = document.createElement("select");
3337
+ opt = select.appendChild( document.createElement("option") );
3338
+ input = div.getElementsByTagName("input")[ 0 ];
3339
+
3340
+ a.style.cssText = "top:1px;float:left;opacity:.5";
3341
+
3342
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
3343
+ support.getSetAttribute = div.className !== "t";
3344
+
3345
+ // IE strips leading whitespace when .innerHTML is used
3346
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
3347
+
3348
+ // Make sure that tbody elements aren't automatically inserted
3349
+ // IE will insert them into empty tables
3350
+ support.tbody = !div.getElementsByTagName("tbody").length;
3351
+
3352
+ // Make sure that link elements get serialized correctly by innerHTML
3353
+ // This requires a wrapper element in IE
3354
+ support.htmlSerialize = !!div.getElementsByTagName("link").length;
3355
+
3356
+ // Get the style information from getAttribute
3357
+ // (IE uses .cssText instead)
3358
+ support.style = /top/.test( a.getAttribute("style") );
3359
+
3360
+ // Make sure that URLs aren't manipulated
3361
+ // (IE normalizes it by default)
3362
+ support.hrefNormalized = a.getAttribute("href") === "/a";
3363
+
3364
+ // Make sure that element opacity exists
3365
+ // (IE uses filter instead)
3366
+ // Use a regex to work around a WebKit issue. See #5145
3367
+ support.opacity = /^0.5/.test( a.style.opacity );
3368
+
3369
+ // Verify style float existence
3370
+ // (IE uses styleFloat instead of cssFloat)
3371
+ support.cssFloat = !!a.style.cssFloat;
3372
+
3373
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
3374
+ support.checkOn = !!input.value;
3375
+
3376
+ // Make sure that a selected-by-default option has a working selected property.
3377
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
3378
+ support.optSelected = opt.selected;
3379
+
3380
+ // Tests for enctype support on a form (#6743)
3381
+ support.enctype = !!document.createElement("form").enctype;
3382
+
3383
+ // Makes sure cloning an html5 element does not cause problems
3384
+ // Where outerHTML is undefined, this still works
3385
+ support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>";
3386
+
3387
+ // Will be defined later
3388
+ support.inlineBlockNeedsLayout = false;
3389
+ support.shrinkWrapBlocks = false;
3390
+ support.pixelPosition = false;
3391
+ support.deleteExpando = true;
3392
+ support.noCloneEvent = true;
3393
+ support.reliableMarginRight = true;
3394
+ support.boxSizingReliable = true;
3395
+
3396
+ // Make sure checked status is properly cloned
3397
+ input.checked = true;
3398
+ support.noCloneChecked = input.cloneNode( true ).checked;
3399
+
3400
+ // Make sure that the options inside disabled selects aren't marked as disabled
3401
+ // (WebKit marks them as disabled)
3402
+ select.disabled = true;
3403
+ support.optDisabled = !opt.disabled;
3404
+
3405
+ // Support: IE<9
3406
+ try {
3407
+ delete div.test;
3408
+ } catch( e ) {
3409
+ support.deleteExpando = false;
3410
+ }
3411
+
3412
+ // Check if we can trust getAttribute("value")
3413
+ input = document.createElement("input");
3414
+ input.setAttribute( "value", "" );
3415
+ support.input = input.getAttribute( "value" ) === "";
3416
+
3417
+ // Check if an input maintains its value after becoming a radio
3418
+ input.value = "t";
3419
+ input.setAttribute( "type", "radio" );
3420
+ support.radioValue = input.value === "t";
3421
+
3422
+ // #11217 - WebKit loses check when the name is after the checked attribute
3423
+ input.setAttribute( "checked", "t" );
3424
+ input.setAttribute( "name", "t" );
3425
+
3426
+ fragment = document.createDocumentFragment();
3427
+ fragment.appendChild( input );
3428
+
3429
+ // Check if a disconnected checkbox will retain its checked
3430
+ // value of true after appended to the DOM (IE6/7)
3431
+ support.appendChecked = input.checked;
3432
+
3433
+ // WebKit doesn't clone checked state correctly in fragments
3434
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
3435
+
3436
+ // Support: IE<9
3437
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
3438
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
3439
+ if ( div.attachEvent ) {
3440
+ div.attachEvent( "onclick", function() {
3441
+ support.noCloneEvent = false;
3442
+ });
3443
+
3444
+ div.cloneNode( true ).click();
3445
+ }
3446
+
3447
+ // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
3448
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
3449
+ for ( i in { submit: true, change: true, focusin: true }) {
3450
+ div.setAttribute( eventName = "on" + i, "t" );
3451
+
3452
+ support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
3453
+ }
3454
+
3455
+ div.style.backgroundClip = "content-box";
3456
+ div.cloneNode( true ).style.backgroundClip = "";
3457
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
3458
+
3459
+ // Support: IE<9
3460
+ // Iteration over object's inherited properties before its own.
3461
+ for ( i in jQuery( support ) ) {
3462
+ break;
3463
+ }
3464
+ support.ownLast = i !== "0";
3465
+
3466
+ // Run tests that need a body at doc ready
3467
+ jQuery(function() {
3468
+ var container, marginDiv, tds,
3469
+ divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
3470
+ body = document.getElementsByTagName("body")[0];
3471
+
3472
+ if ( !body ) {
3473
+ // Return for frameset docs that don't have a body
3474
+ return;
3475
+ }
3476
+
3477
+ container = document.createElement("div");
3478
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
3479
+
3480
+ body.appendChild( container ).appendChild( div );
3481
+
3482
+ // Support: IE8
3483
+ // Check if table cells still have offsetWidth/Height when they are set
3484
+ // to display:none and there are still other visible table cells in a
3485
+ // table row; if so, offsetWidth/Height are not reliable for use when
3486
+ // determining if an element has been hidden directly using
3487
+ // display:none (it is still safe to use offsets if a parent element is
3488
+ // hidden; don safety goggles and see bug #4512 for more information).
3489
+ div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
3490
+ tds = div.getElementsByTagName("td");
3491
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
3492
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
3493
+
3494
+ tds[ 0 ].style.display = "";
3495
+ tds[ 1 ].style.display = "none";
3496
+
3497
+ // Support: IE8
3498
+ // Check if empty table cells still have offsetWidth/Height
3499
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
3500
+
3501
+ // Check box-sizing and margin behavior.
3502
+ div.innerHTML = "";
3503
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
3504
+
3505
+ // Workaround failing boxSizing test due to offsetWidth returning wrong value
3506
+ // with some non-1 values of body zoom, ticket #13543
3507
+ jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
3508
+ support.boxSizing = div.offsetWidth === 4;
3509
+ });
3510
+
3511
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
3512
+ if ( window.getComputedStyle ) {
3513
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
3514
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
3515
+
3516
+ // Check if div with explicit width and no margin-right incorrectly
3517
+ // gets computed margin-right based on width of container. (#3333)
3518
+ // Fails in WebKit before Feb 2011 nightlies
3519
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
3520
+ marginDiv = div.appendChild( document.createElement("div") );
3521
+ marginDiv.style.cssText = div.style.cssText = divReset;
3522
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
3523
+ div.style.width = "1px";
3524
+
3525
+ support.reliableMarginRight =
3526
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
3527
+ }
3528
+
3529
+ if ( typeof div.style.zoom !== core_strundefined ) {
3530
+ // Support: IE<8
3531
+ // Check if natively block-level elements act like inline-block
3532
+ // elements when setting their display to 'inline' and giving
3533
+ // them layout
3534
+ div.innerHTML = "";
3535
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
3536
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
3537
+
3538
+ // Support: IE6
3539
+ // Check if elements with layout shrink-wrap their children
3540
+ div.style.display = "block";
3541
+ div.innerHTML = "<div></div>";
3542
+ div.firstChild.style.width = "5px";
3543
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
3544
+
3545
+ if ( support.inlineBlockNeedsLayout ) {
3546
+ // Prevent IE 6 from affecting layout for positioned elements #11048
3547
+ // Prevent IE from shrinking the body in IE 7 mode #12869
3548
+ // Support: IE<8
3549
+ body.style.zoom = 1;
3550
+ }
3551
+ }
3552
+
3553
+ body.removeChild( container );
3554
+
3555
+ // Null elements to avoid leaks in IE
3556
+ container = div = tds = marginDiv = null;
3557
+ });
3558
+
3559
+ // Null elements to avoid leaks in IE
3560
+ all = select = fragment = opt = a = input = null;
3561
+
3562
+ return support;
3563
+ })({});
3564
+
3565
+ var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
3566
+ rmultiDash = /([A-Z])/g;
3567
+
3568
+ function internalData( elem, name, data, pvt /* Internal Use Only */ ){
3569
+ if ( !jQuery.acceptData( elem ) ) {
3570
+ return;
3571
+ }
3572
+
3573
+ var ret, thisCache,
3574
+ internalKey = jQuery.expando,
3575
+
3576
+ // We have to handle DOM nodes and JS objects differently because IE6-7
3577
+ // can't GC object references properly across the DOM-JS boundary
3578
+ isNode = elem.nodeType,
3579
+
3580
+ // Only DOM nodes need the global jQuery cache; JS object data is
3581
+ // attached directly to the object so GC can occur automatically
3582
+ cache = isNode ? jQuery.cache : elem,
3583
+
3584
+ // Only defining an ID for JS objects if its cache already exists allows
3585
+ // the code to shortcut on the same path as a DOM node with no cache
3586
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
3587
+
3588
+ // Avoid doing any more work than we need to when trying to get data on an
3589
+ // object that has no data at all
3590
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
3591
+ return;
3592
+ }
3593
+
3594
+ if ( !id ) {
3595
+ // Only DOM nodes need a new unique ID for each element since their data
3596
+ // ends up in the global cache
3597
+ if ( isNode ) {
3598
+ id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++;
3599
+ } else {
3600
+ id = internalKey;
3601
+ }
3602
+ }
3603
+
3604
+ if ( !cache[ id ] ) {
3605
+ // Avoid exposing jQuery metadata on plain JS objects when the object
3606
+ // is serialized using JSON.stringify
3607
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
3608
+ }
3609
+
3610
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
3611
+ // shallow copied over onto the existing cache
3612
+ if ( typeof name === "object" || typeof name === "function" ) {
3613
+ if ( pvt ) {
3614
+ cache[ id ] = jQuery.extend( cache[ id ], name );
3615
+ } else {
3616
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
3617
+ }
3618
+ }
3619
+
3620
+ thisCache = cache[ id ];
3621
+
3622
+ // jQuery data() is stored in a separate object inside the object's internal data
3623
+ // cache in order to avoid key collisions between internal data and user-defined
3624
+ // data.
3625
+ if ( !pvt ) {
3626
+ if ( !thisCache.data ) {
3627
+ thisCache.data = {};
3628
+ }
3629
+
3630
+ thisCache = thisCache.data;
3631
+ }
3632
+
3633
+ if ( data !== undefined ) {
3634
+ thisCache[ jQuery.camelCase( name ) ] = data;
3635
+ }
3636
+
3637
+ // Check for both converted-to-camel and non-converted data property names
3638
+ // If a data property was specified
3639
+ if ( typeof name === "string" ) {
3640
+
3641
+ // First Try to find as-is property data
3642
+ ret = thisCache[ name ];
3643
+
3644
+ // Test for null|undefined property data
3645
+ if ( ret == null ) {
3646
+
3647
+ // Try to find the camelCased property
3648
+ ret = thisCache[ jQuery.camelCase( name ) ];
3649
+ }
3650
+ } else {
3651
+ ret = thisCache;
3652
+ }
3653
+
3654
+ return ret;
3655
+ }
3656
+
3657
+ function internalRemoveData( elem, name, pvt ) {
3658
+ if ( !jQuery.acceptData( elem ) ) {
3659
+ return;
3660
+ }
3661
+
3662
+ var thisCache, i,
3663
+ isNode = elem.nodeType,
3664
+
3665
+ // See jQuery.data for more information
3666
+ cache = isNode ? jQuery.cache : elem,
3667
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
3668
+
3669
+ // If there is already no cache entry for this object, there is no
3670
+ // purpose in continuing
3671
+ if ( !cache[ id ] ) {
3672
+ return;
3673
+ }
3674
+
3675
+ if ( name ) {
3676
+
3677
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
3678
+
3679
+ if ( thisCache ) {
3680
+
3681
+ // Support array or space separated string names for data keys
3682
+ if ( !jQuery.isArray( name ) ) {
3683
+
3684
+ // try the string as a key before any manipulation
3685
+ if ( name in thisCache ) {
3686
+ name = [ name ];
3687
+ } else {
3688
+
3689
+ // split the camel cased version by spaces unless a key with the spaces exists
3690
+ name = jQuery.camelCase( name );
3691
+ if ( name in thisCache ) {
3692
+ name = [ name ];
3693
+ } else {
3694
+ name = name.split(" ");
3695
+ }
3696
+ }
3697
+ } else {
3698
+ // If "name" is an array of keys...
3699
+ // When data is initially created, via ("key", "val") signature,
3700
+ // keys will be converted to camelCase.
3701
+ // Since there is no way to tell _how_ a key was added, remove
3702
+ // both plain key and camelCase key. #12786
3703
+ // This will only penalize the array argument path.
3704
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
3705
+ }
3706
+
3707
+ i = name.length;
3708
+ while ( i-- ) {
3709
+ delete thisCache[ name[i] ];
3710
+ }
3711
+
3712
+ // If there is no data left in the cache, we want to continue
3713
+ // and let the cache object itself get destroyed
3714
+ if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
3715
+ return;
3716
+ }
3717
+ }
3718
+ }
3719
+
3720
+ // See jQuery.data for more information
3721
+ if ( !pvt ) {
3722
+ delete cache[ id ].data;
3723
+
3724
+ // Don't destroy the parent cache unless the internal data object
3725
+ // had been the only thing left in it
3726
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
3727
+ return;
3728
+ }
3729
+ }
3730
+
3731
+ // Destroy the cache
3732
+ if ( isNode ) {
3733
+ jQuery.cleanData( [ elem ], true );
3734
+
3735
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
3736
+ /* jshint eqeqeq: false */
3737
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
3738
+ /* jshint eqeqeq: true */
3739
+ delete cache[ id ];
3740
+
3741
+ // When all else fails, null
3742
+ } else {
3743
+ cache[ id ] = null;
3744
+ }
3745
+ }
3746
+
3747
+ jQuery.extend({
3748
+ cache: {},
3749
+
3750
+ // The following elements throw uncatchable exceptions if you
3751
+ // attempt to add expando properties to them.
3752
+ noData: {
3753
+ "applet": true,
3754
+ "embed": true,
3755
+ // Ban all objects except for Flash (which handle expandos)
3756
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
3757
+ },
3758
+
3759
+ hasData: function( elem ) {
3760
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
3761
+ return !!elem && !isEmptyDataObject( elem );
3762
+ },
3763
+
3764
+ data: function( elem, name, data ) {
3765
+ return internalData( elem, name, data );
3766
+ },
3767
+
3768
+ removeData: function( elem, name ) {
3769
+ return internalRemoveData( elem, name );
3770
+ },
3771
+
3772
+ // For internal use only.
3773
+ _data: function( elem, name, data ) {
3774
+ return internalData( elem, name, data, true );
3775
+ },
3776
+
3777
+ _removeData: function( elem, name ) {
3778
+ return internalRemoveData( elem, name, true );
3779
+ },
3780
+
3781
+ // A method for determining if a DOM node can handle the data expando
3782
+ acceptData: function( elem ) {
3783
+ // Do not set data on non-element because it will not be cleared (#8335).
3784
+ if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
3785
+ return false;
3786
+ }
3787
+
3788
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
3789
+
3790
+ // nodes accept data unless otherwise specified; rejection can be conditional
3791
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
3792
+ }
3793
+ });
3794
+
3795
+ jQuery.fn.extend({
3796
+ data: function( key, value ) {
3797
+ var attrs, name,
3798
+ data = null,
3799
+ i = 0,
3800
+ elem = this[0];
3801
+
3802
+ // Special expections of .data basically thwart jQuery.access,
3803
+ // so implement the relevant behavior ourselves
3804
+
3805
+ // Gets all values
3806
+ if ( key === undefined ) {
3807
+ if ( this.length ) {
3808
+ data = jQuery.data( elem );
3809
+
3810
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
3811
+ attrs = elem.attributes;
3812
+ for ( ; i < attrs.length; i++ ) {
3813
+ name = attrs[i].name;
3814
+
3815
+ if ( name.indexOf("data-") === 0 ) {
3816
+ name = jQuery.camelCase( name.slice(5) );
3817
+
3818
+ dataAttr( elem, name, data[ name ] );
3819
+ }
3820
+ }
3821
+ jQuery._data( elem, "parsedAttrs", true );
3822
+ }
3823
+ }
3824
+
3825
+ return data;
3826
+ }
3827
+
3828
+ // Sets multiple values
3829
+ if ( typeof key === "object" ) {
3830
+ return this.each(function() {
3831
+ jQuery.data( this, key );
3832
+ });
3833
+ }
3834
+
3835
+ return arguments.length > 1 ?
3836
+
3837
+ // Sets one value
3838
+ this.each(function() {
3839
+ jQuery.data( this, key, value );
3840
+ }) :
3841
+
3842
+ // Gets one value
3843
+ // Try to fetch any internally stored data first
3844
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
3845
+ },
3846
+
3847
+ removeData: function( key ) {
3848
+ return this.each(function() {
3849
+ jQuery.removeData( this, key );
3850
+ });
3851
+ }
3852
+ });
3853
+
3854
+ function dataAttr( elem, key, data ) {
3855
+ // If nothing was found internally, try to fetch any
3856
+ // data from the HTML5 data-* attribute
3857
+ if ( data === undefined && elem.nodeType === 1 ) {
3858
+
3859
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
3860
+
3861
+ data = elem.getAttribute( name );
3862
+
3863
+ if ( typeof data === "string" ) {
3864
+ try {
3865
+ data = data === "true" ? true :
3866
+ data === "false" ? false :
3867
+ data === "null" ? null :
3868
+ // Only convert to a number if it doesn't change the string
3869
+ +data + "" === data ? +data :
3870
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
3871
+ data;
3872
+ } catch( e ) {}
3873
+
3874
+ // Make sure we set the data so it isn't changed later
3875
+ jQuery.data( elem, key, data );
3876
+
3877
+ } else {
3878
+ data = undefined;
3879
+ }
3880
+ }
3881
+
3882
+ return data;
3883
+ }
3884
+
3885
+ // checks a cache object for emptiness
3886
+ function isEmptyDataObject( obj ) {
3887
+ var name;
3888
+ for ( name in obj ) {
3889
+
3890
+ // if the public data object is empty, the private is still empty
3891
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
3892
+ continue;
3893
+ }
3894
+ if ( name !== "toJSON" ) {
3895
+ return false;
3896
+ }
3897
+ }
3898
+
3899
+ return true;
3900
+ }
3901
+ jQuery.extend({
3902
+ queue: function( elem, type, data ) {
3903
+ var queue;
3904
+
3905
+ if ( elem ) {
3906
+ type = ( type || "fx" ) + "queue";
3907
+ queue = jQuery._data( elem, type );
3908
+
3909
+ // Speed up dequeue by getting out quickly if this is just a lookup
3910
+ if ( data ) {
3911
+ if ( !queue || jQuery.isArray(data) ) {
3912
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
3913
+ } else {
3914
+ queue.push( data );
3915
+ }
3916
+ }
3917
+ return queue || [];
3918
+ }
3919
+ },
3920
+
3921
+ dequeue: function( elem, type ) {
3922
+ type = type || "fx";
3923
+
3924
+ var queue = jQuery.queue( elem, type ),
3925
+ startLength = queue.length,
3926
+ fn = queue.shift(),
3927
+ hooks = jQuery._queueHooks( elem, type ),
3928
+ next = function() {
3929
+ jQuery.dequeue( elem, type );
3930
+ };
3931
+
3932
+ // If the fx queue is dequeued, always remove the progress sentinel
3933
+ if ( fn === "inprogress" ) {
3934
+ fn = queue.shift();
3935
+ startLength--;
3936
+ }
3937
+
3938
+ if ( fn ) {
3939
+
3940
+ // Add a progress sentinel to prevent the fx queue from being
3941
+ // automatically dequeued
3942
+ if ( type === "fx" ) {
3943
+ queue.unshift( "inprogress" );
3944
+ }
3945
+
3946
+ // clear up the last queue stop function
3947
+ delete hooks.stop;
3948
+ fn.call( elem, next, hooks );
3949
+ }
3950
+
3951
+ if ( !startLength && hooks ) {
3952
+ hooks.empty.fire();
3953
+ }
3954
+ },
3955
+
3956
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
3957
+ _queueHooks: function( elem, type ) {
3958
+ var key = type + "queueHooks";
3959
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
3960
+ empty: jQuery.Callbacks("once memory").add(function() {
3961
+ jQuery._removeData( elem, type + "queue" );
3962
+ jQuery._removeData( elem, key );
3963
+ })
3964
+ });
3965
+ }
3966
+ });
3967
+
3968
+ jQuery.fn.extend({
3969
+ queue: function( type, data ) {
3970
+ var setter = 2;
3971
+
3972
+ if ( typeof type !== "string" ) {
3973
+ data = type;
3974
+ type = "fx";
3975
+ setter--;
3976
+ }
3977
+
3978
+ if ( arguments.length < setter ) {
3979
+ return jQuery.queue( this[0], type );
3980
+ }
3981
+
3982
+ return data === undefined ?
3983
+ this :
3984
+ this.each(function() {
3985
+ var queue = jQuery.queue( this, type, data );
3986
+
3987
+ // ensure a hooks for this queue
3988
+ jQuery._queueHooks( this, type );
3989
+
3990
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
3991
+ jQuery.dequeue( this, type );
3992
+ }
3993
+ });
3994
+ },
3995
+ dequeue: function( type ) {
3996
+ return this.each(function() {
3997
+ jQuery.dequeue( this, type );
3998
+ });
3999
+ },
4000
+ // Based off of the plugin by Clint Helfers, with permission.
4001
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
4002
+ delay: function( time, type ) {
4003
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
4004
+ type = type || "fx";
4005
+
4006
+ return this.queue( type, function( next, hooks ) {
4007
+ var timeout = setTimeout( next, time );
4008
+ hooks.stop = function() {
4009
+ clearTimeout( timeout );
4010
+ };
4011
+ });
4012
+ },
4013
+ clearQueue: function( type ) {
4014
+ return this.queue( type || "fx", [] );
4015
+ },
4016
+ // Get a promise resolved when queues of a certain type
4017
+ // are emptied (fx is the type by default)
4018
+ promise: function( type, obj ) {
4019
+ var tmp,
4020
+ count = 1,
4021
+ defer = jQuery.Deferred(),
4022
+ elements = this,
4023
+ i = this.length,
4024
+ resolve = function() {
4025
+ if ( !( --count ) ) {
4026
+ defer.resolveWith( elements, [ elements ] );
4027
+ }
4028
+ };
4029
+
4030
+ if ( typeof type !== "string" ) {
4031
+ obj = type;
4032
+ type = undefined;
4033
+ }
4034
+ type = type || "fx";
4035
+
4036
+ while( i-- ) {
4037
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
4038
+ if ( tmp && tmp.empty ) {
4039
+ count++;
4040
+ tmp.empty.add( resolve );
4041
+ }
4042
+ }
4043
+ resolve();
4044
+ return defer.promise( obj );
4045
+ }
4046
+ });
4047
+ var nodeHook, boolHook,
4048
+ rclass = /[\t\r\n\f]/g,
4049
+ rreturn = /\r/g,
4050
+ rfocusable = /^(?:input|select|textarea|button|object)$/i,
4051
+ rclickable = /^(?:a|area)$/i,
4052
+ ruseDefault = /^(?:checked|selected)$/i,
4053
+ getSetAttribute = jQuery.support.getSetAttribute,
4054
+ getSetInput = jQuery.support.input;
4055
+
4056
+ jQuery.fn.extend({
4057
+ attr: function( name, value ) {
4058
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
4059
+ },
4060
+
4061
+ removeAttr: function( name ) {
4062
+ return this.each(function() {
4063
+ jQuery.removeAttr( this, name );
4064
+ });
4065
+ },
4066
+
4067
+ prop: function( name, value ) {
4068
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
4069
+ },
4070
+
4071
+ removeProp: function( name ) {
4072
+ name = jQuery.propFix[ name ] || name;
4073
+ return this.each(function() {
4074
+ // try/catch handles cases where IE balks (such as removing a property on window)
4075
+ try {
4076
+ this[ name ] = undefined;
4077
+ delete this[ name ];
4078
+ } catch( e ) {}
4079
+ });
4080
+ },
4081
+
4082
+ addClass: function( value ) {
4083
+ var classes, elem, cur, clazz, j,
4084
+ i = 0,
4085
+ len = this.length,
4086
+ proceed = typeof value === "string" && value;
4087
+
4088
+ if ( jQuery.isFunction( value ) ) {
4089
+ return this.each(function( j ) {
4090
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
4091
+ });
4092
+ }
4093
+
4094
+ if ( proceed ) {
4095
+ // The disjunction here is for better compressibility (see removeClass)
4096
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
4097
+
4098
+ for ( ; i < len; i++ ) {
4099
+ elem = this[ i ];
4100
+ cur = elem.nodeType === 1 && ( elem.className ?
4101
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
4102
+ " "
4103
+ );
4104
+
4105
+ if ( cur ) {
4106
+ j = 0;
4107
+ while ( (clazz = classes[j++]) ) {
4108
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
4109
+ cur += clazz + " ";
4110
+ }
4111
+ }
4112
+ elem.className = jQuery.trim( cur );
4113
+
4114
+ }
4115
+ }
4116
+ }
4117
+
4118
+ return this;
4119
+ },
4120
+
4121
+ removeClass: function( value ) {
4122
+ var classes, elem, cur, clazz, j,
4123
+ i = 0,
4124
+ len = this.length,
4125
+ proceed = arguments.length === 0 || typeof value === "string" && value;
4126
+
4127
+ if ( jQuery.isFunction( value ) ) {
4128
+ return this.each(function( j ) {
4129
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
4130
+ });
4131
+ }
4132
+ if ( proceed ) {
4133
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
4134
+
4135
+ for ( ; i < len; i++ ) {
4136
+ elem = this[ i ];
4137
+ // This expression is here for better compressibility (see addClass)
4138
+ cur = elem.nodeType === 1 && ( elem.className ?
4139
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
4140
+ ""
4141
+ );
4142
+
4143
+ if ( cur ) {
4144
+ j = 0;
4145
+ while ( (clazz = classes[j++]) ) {
4146
+ // Remove *all* instances
4147
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
4148
+ cur = cur.replace( " " + clazz + " ", " " );
4149
+ }
4150
+ }
4151
+ elem.className = value ? jQuery.trim( cur ) : "";
4152
+ }
4153
+ }
4154
+ }
4155
+
4156
+ return this;
4157
+ },
4158
+
4159
+ toggleClass: function( value, stateVal ) {
4160
+ var type = typeof value;
4161
+
4162
+ if ( typeof stateVal === "boolean" && type === "string" ) {
4163
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
4164
+ }
4165
+
4166
+ if ( jQuery.isFunction( value ) ) {
4167
+ return this.each(function( i ) {
4168
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
4169
+ });
4170
+ }
4171
+
4172
+ return this.each(function() {
4173
+ if ( type === "string" ) {
4174
+ // toggle individual class names
4175
+ var className,
4176
+ i = 0,
4177
+ self = jQuery( this ),
4178
+ classNames = value.match( core_rnotwhite ) || [];
4179
+
4180
+ while ( (className = classNames[ i++ ]) ) {
4181
+ // check each className given, space separated list
4182
+ if ( self.hasClass( className ) ) {
4183
+ self.removeClass( className );
4184
+ } else {
4185
+ self.addClass( className );
4186
+ }
4187
+ }
4188
+
4189
+ // Toggle whole class name
4190
+ } else if ( type === core_strundefined || type === "boolean" ) {
4191
+ if ( this.className ) {
4192
+ // store className if set
4193
+ jQuery._data( this, "__className__", this.className );
4194
+ }
4195
+
4196
+ // If the element has a class name or if we're passed "false",
4197
+ // then remove the whole classname (if there was one, the above saved it).
4198
+ // Otherwise bring back whatever was previously saved (if anything),
4199
+ // falling back to the empty string if nothing was stored.
4200
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
4201
+ }
4202
+ });
4203
+ },
4204
+
4205
+ hasClass: function( selector ) {
4206
+ var className = " " + selector + " ",
4207
+ i = 0,
4208
+ l = this.length;
4209
+ for ( ; i < l; i++ ) {
4210
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
4211
+ return true;
4212
+ }
4213
+ }
4214
+
4215
+ return false;
4216
+ },
4217
+
4218
+ val: function( value ) {
4219
+ var ret, hooks, isFunction,
4220
+ elem = this[0];
4221
+
4222
+ if ( !arguments.length ) {
4223
+ if ( elem ) {
4224
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
4225
+
4226
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
4227
+ return ret;
4228
+ }
4229
+
4230
+ ret = elem.value;
4231
+
4232
+ return typeof ret === "string" ?
4233
+ // handle most common string cases
4234
+ ret.replace(rreturn, "") :
4235
+ // handle cases where value is null/undef or number
4236
+ ret == null ? "" : ret;
4237
+ }
4238
+
4239
+ return;
4240
+ }
4241
+
4242
+ isFunction = jQuery.isFunction( value );
4243
+
4244
+ return this.each(function( i ) {
4245
+ var val;
4246
+
4247
+ if ( this.nodeType !== 1 ) {
4248
+ return;
4249
+ }
4250
+
4251
+ if ( isFunction ) {
4252
+ val = value.call( this, i, jQuery( this ).val() );
4253
+ } else {
4254
+ val = value;
4255
+ }
4256
+
4257
+ // Treat null/undefined as ""; convert numbers to string
4258
+ if ( val == null ) {
4259
+ val = "";
4260
+ } else if ( typeof val === "number" ) {
4261
+ val += "";
4262
+ } else if ( jQuery.isArray( val ) ) {
4263
+ val = jQuery.map(val, function ( value ) {
4264
+ return value == null ? "" : value + "";
4265
+ });
4266
+ }
4267
+
4268
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
4269
+
4270
+ // If set returns undefined, fall back to normal setting
4271
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
4272
+ this.value = val;
4273
+ }
4274
+ });
4275
+ }
4276
+ });
4277
+
4278
+ jQuery.extend({
4279
+ valHooks: {
4280
+ option: {
4281
+ get: function( elem ) {
4282
+ // Use proper attribute retrieval(#6932, #12072)
4283
+ var val = jQuery.find.attr( elem, "value" );
4284
+ return val != null ?
4285
+ val :
4286
+ elem.text;
4287
+ }
4288
+ },
4289
+ select: {
4290
+ get: function( elem ) {
4291
+ var value, option,
4292
+ options = elem.options,
4293
+ index = elem.selectedIndex,
4294
+ one = elem.type === "select-one" || index < 0,
4295
+ values = one ? null : [],
4296
+ max = one ? index + 1 : options.length,
4297
+ i = index < 0 ?
4298
+ max :
4299
+ one ? index : 0;
4300
+
4301
+ // Loop through all the selected options
4302
+ for ( ; i < max; i++ ) {
4303
+ option = options[ i ];
4304
+
4305
+ // oldIE doesn't update selected after form reset (#2551)
4306
+ if ( ( option.selected || i === index ) &&
4307
+ // Don't return options that are disabled or in a disabled optgroup
4308
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
4309
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
4310
+
4311
+ // Get the specific value for the option
4312
+ value = jQuery( option ).val();
4313
+
4314
+ // We don't need an array for one selects
4315
+ if ( one ) {
4316
+ return value;
4317
+ }
4318
+
4319
+ // Multi-Selects return an array
4320
+ values.push( value );
4321
+ }
4322
+ }
4323
+
4324
+ return values;
4325
+ },
4326
+
4327
+ set: function( elem, value ) {
4328
+ var optionSet, option,
4329
+ options = elem.options,
4330
+ values = jQuery.makeArray( value ),
4331
+ i = options.length;
4332
+
4333
+ while ( i-- ) {
4334
+ option = options[ i ];
4335
+ if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
4336
+ optionSet = true;
4337
+ }
4338
+ }
4339
+
4340
+ // force browsers to behave consistently when non-matching value is set
4341
+ if ( !optionSet ) {
4342
+ elem.selectedIndex = -1;
4343
+ }
4344
+ return values;
4345
+ }
4346
+ }
4347
+ },
4348
+
4349
+ attr: function( elem, name, value ) {
4350
+ var hooks, ret,
4351
+ nType = elem.nodeType;
4352
+
4353
+ // don't get/set attributes on text, comment and attribute nodes
4354
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4355
+ return;
4356
+ }
4357
+
4358
+ // Fallback to prop when attributes are not supported
4359
+ if ( typeof elem.getAttribute === core_strundefined ) {
4360
+ return jQuery.prop( elem, name, value );
4361
+ }
4362
+
4363
+ // All attributes are lowercase
4364
+ // Grab necessary hook if one is defined
4365
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
4366
+ name = name.toLowerCase();
4367
+ hooks = jQuery.attrHooks[ name ] ||
4368
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
4369
+ }
4370
+
4371
+ if ( value !== undefined ) {
4372
+
4373
+ if ( value === null ) {
4374
+ jQuery.removeAttr( elem, name );
4375
+
4376
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
4377
+ return ret;
4378
+
4379
+ } else {
4380
+ elem.setAttribute( name, value + "" );
4381
+ return value;
4382
+ }
4383
+
4384
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
4385
+ return ret;
4386
+
4387
+ } else {
4388
+ ret = jQuery.find.attr( elem, name );
4389
+
4390
+ // Non-existent attributes return null, we normalize to undefined
4391
+ return ret == null ?
4392
+ undefined :
4393
+ ret;
4394
+ }
4395
+ },
4396
+
4397
+ removeAttr: function( elem, value ) {
4398
+ var name, propName,
4399
+ i = 0,
4400
+ attrNames = value && value.match( core_rnotwhite );
4401
+
4402
+ if ( attrNames && elem.nodeType === 1 ) {
4403
+ while ( (name = attrNames[i++]) ) {
4404
+ propName = jQuery.propFix[ name ] || name;
4405
+
4406
+ // Boolean attributes get special treatment (#10870)
4407
+ if ( jQuery.expr.match.bool.test( name ) ) {
4408
+ // Set corresponding property to false
4409
+ if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
4410
+ elem[ propName ] = false;
4411
+ // Support: IE<9
4412
+ // Also clear defaultChecked/defaultSelected (if appropriate)
4413
+ } else {
4414
+ elem[ jQuery.camelCase( "default-" + name ) ] =
4415
+ elem[ propName ] = false;
4416
+ }
4417
+
4418
+ // See #9699 for explanation of this approach (setting first, then removal)
4419
+ } else {
4420
+ jQuery.attr( elem, name, "" );
4421
+ }
4422
+
4423
+ elem.removeAttribute( getSetAttribute ? name : propName );
4424
+ }
4425
+ }
4426
+ },
4427
+
4428
+ attrHooks: {
4429
+ type: {
4430
+ set: function( elem, value ) {
4431
+ if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
4432
+ // Setting the type on a radio button after the value resets the value in IE6-9
4433
+ // Reset value to default in case type is set after value during creation
4434
+ var val = elem.value;
4435
+ elem.setAttribute( "type", value );
4436
+ if ( val ) {
4437
+ elem.value = val;
4438
+ }
4439
+ return value;
4440
+ }
4441
+ }
4442
+ }
4443
+ },
4444
+
4445
+ propFix: {
4446
+ "for": "htmlFor",
4447
+ "class": "className"
4448
+ },
4449
+
4450
+ prop: function( elem, name, value ) {
4451
+ var ret, hooks, notxml,
4452
+ nType = elem.nodeType;
4453
+
4454
+ // don't get/set properties on text, comment and attribute nodes
4455
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4456
+ return;
4457
+ }
4458
+
4459
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
4460
+
4461
+ if ( notxml ) {
4462
+ // Fix name and attach hooks
4463
+ name = jQuery.propFix[ name ] || name;
4464
+ hooks = jQuery.propHooks[ name ];
4465
+ }
4466
+
4467
+ if ( value !== undefined ) {
4468
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
4469
+ ret :
4470
+ ( elem[ name ] = value );
4471
+
4472
+ } else {
4473
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
4474
+ ret :
4475
+ elem[ name ];
4476
+ }
4477
+ },
4478
+
4479
+ propHooks: {
4480
+ tabIndex: {
4481
+ get: function( elem ) {
4482
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
4483
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
4484
+ // Use proper attribute retrieval(#12072)
4485
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
4486
+
4487
+ return tabindex ?
4488
+ parseInt( tabindex, 10 ) :
4489
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
4490
+ 0 :
4491
+ -1;
4492
+ }
4493
+ }
4494
+ }
4495
+ });
4496
+
4497
+ // Hooks for boolean attributes
4498
+ boolHook = {
4499
+ set: function( elem, value, name ) {
4500
+ if ( value === false ) {
4501
+ // Remove boolean attributes when set to false
4502
+ jQuery.removeAttr( elem, name );
4503
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
4504
+ // IE<8 needs the *property* name
4505
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
4506
+
4507
+ // Use defaultChecked and defaultSelected for oldIE
4508
+ } else {
4509
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
4510
+ }
4511
+
4512
+ return name;
4513
+ }
4514
+ };
4515
+ jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
4516
+ var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
4517
+
4518
+ jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
4519
+ function( elem, name, isXML ) {
4520
+ var fn = jQuery.expr.attrHandle[ name ],
4521
+ ret = isXML ?
4522
+ undefined :
4523
+ /* jshint eqeqeq: false */
4524
+ (jQuery.expr.attrHandle[ name ] = undefined) !=
4525
+ getter( elem, name, isXML ) ?
4526
+
4527
+ name.toLowerCase() :
4528
+ null;
4529
+ jQuery.expr.attrHandle[ name ] = fn;
4530
+ return ret;
4531
+ } :
4532
+ function( elem, name, isXML ) {
4533
+ return isXML ?
4534
+ undefined :
4535
+ elem[ jQuery.camelCase( "default-" + name ) ] ?
4536
+ name.toLowerCase() :
4537
+ null;
4538
+ };
4539
+ });
4540
+
4541
+ // fix oldIE attroperties
4542
+ if ( !getSetInput || !getSetAttribute ) {
4543
+ jQuery.attrHooks.value = {
4544
+ set: function( elem, value, name ) {
4545
+ if ( jQuery.nodeName( elem, "input" ) ) {
4546
+ // Does not return so that setAttribute is also used
4547
+ elem.defaultValue = value;
4548
+ } else {
4549
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
4550
+ return nodeHook && nodeHook.set( elem, value, name );
4551
+ }
4552
+ }
4553
+ };
4554
+ }
4555
+
4556
+ // IE6/7 do not support getting/setting some attributes with get/setAttribute
4557
+ if ( !getSetAttribute ) {
4558
+
4559
+ // Use this for any attribute in IE6/7
4560
+ // This fixes almost every IE6/7 issue
4561
+ nodeHook = {
4562
+ set: function( elem, value, name ) {
4563
+ // Set the existing or create a new attribute node
4564
+ var ret = elem.getAttributeNode( name );
4565
+ if ( !ret ) {
4566
+ elem.setAttributeNode(
4567
+ (ret = elem.ownerDocument.createAttribute( name ))
4568
+ );
4569
+ }
4570
+
4571
+ ret.value = value += "";
4572
+
4573
+ // Break association with cloned elements by also using setAttribute (#9646)
4574
+ return name === "value" || value === elem.getAttribute( name ) ?
4575
+ value :
4576
+ undefined;
4577
+ }
4578
+ };
4579
+ jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords =
4580
+ // Some attributes are constructed with empty-string values when not defined
4581
+ function( elem, name, isXML ) {
4582
+ var ret;
4583
+ return isXML ?
4584
+ undefined :
4585
+ (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
4586
+ ret.value :
4587
+ null;
4588
+ };
4589
+ jQuery.valHooks.button = {
4590
+ get: function( elem, name ) {
4591
+ var ret = elem.getAttributeNode( name );
4592
+ return ret && ret.specified ?
4593
+ ret.value :
4594
+ undefined;
4595
+ },
4596
+ set: nodeHook.set
4597
+ };
4598
+
4599
+ // Set contenteditable to false on removals(#10429)
4600
+ // Setting to empty string throws an error as an invalid value
4601
+ jQuery.attrHooks.contenteditable = {
4602
+ set: function( elem, value, name ) {
4603
+ nodeHook.set( elem, value === "" ? false : value, name );
4604
+ }
4605
+ };
4606
+
4607
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
4608
+ // This is for removals
4609
+ jQuery.each([ "width", "height" ], function( i, name ) {
4610
+ jQuery.attrHooks[ name ] = {
4611
+ set: function( elem, value ) {
4612
+ if ( value === "" ) {
4613
+ elem.setAttribute( name, "auto" );
4614
+ return value;
4615
+ }
4616
+ }
4617
+ };
4618
+ });
4619
+ }
4620
+
4621
+
4622
+ // Some attributes require a special call on IE
4623
+ // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
4624
+ if ( !jQuery.support.hrefNormalized ) {
4625
+ // href/src property should get the full normalized URL (#10299/#12915)
4626
+ jQuery.each([ "href", "src" ], function( i, name ) {
4627
+ jQuery.propHooks[ name ] = {
4628
+ get: function( elem ) {
4629
+ return elem.getAttribute( name, 4 );
4630
+ }
4631
+ };
4632
+ });
4633
+ }
4634
+
4635
+ if ( !jQuery.support.style ) {
4636
+ jQuery.attrHooks.style = {
4637
+ get: function( elem ) {
4638
+ // Return undefined in the case of empty string
4639
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
4640
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
4641
+ return elem.style.cssText || undefined;
4642
+ },
4643
+ set: function( elem, value ) {
4644
+ return ( elem.style.cssText = value + "" );
4645
+ }
4646
+ };
4647
+ }
4648
+
4649
+ // Safari mis-reports the default selected property of an option
4650
+ // Accessing the parent's selectedIndex property fixes it
4651
+ if ( !jQuery.support.optSelected ) {
4652
+ jQuery.propHooks.selected = {
4653
+ get: function( elem ) {
4654
+ var parent = elem.parentNode;
4655
+
4656
+ if ( parent ) {
4657
+ parent.selectedIndex;
4658
+
4659
+ // Make sure that it also works with optgroups, see #5701
4660
+ if ( parent.parentNode ) {
4661
+ parent.parentNode.selectedIndex;
4662
+ }
4663
+ }
4664
+ return null;
4665
+ }
4666
+ };
4667
+ }
4668
+
4669
+ jQuery.each([
4670
+ "tabIndex",
4671
+ "readOnly",
4672
+ "maxLength",
4673
+ "cellSpacing",
4674
+ "cellPadding",
4675
+ "rowSpan",
4676
+ "colSpan",
4677
+ "useMap",
4678
+ "frameBorder",
4679
+ "contentEditable"
4680
+ ], function() {
4681
+ jQuery.propFix[ this.toLowerCase() ] = this;
4682
+ });
4683
+
4684
+ // IE6/7 call enctype encoding
4685
+ if ( !jQuery.support.enctype ) {
4686
+ jQuery.propFix.enctype = "encoding";
4687
+ }
4688
+
4689
+ // Radios and checkboxes getter/setter
4690
+ jQuery.each([ "radio", "checkbox" ], function() {
4691
+ jQuery.valHooks[ this ] = {
4692
+ set: function( elem, value ) {
4693
+ if ( jQuery.isArray( value ) ) {
4694
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
4695
+ }
4696
+ }
4697
+ };
4698
+ if ( !jQuery.support.checkOn ) {
4699
+ jQuery.valHooks[ this ].get = function( elem ) {
4700
+ // Support: Webkit
4701
+ // "" is returned instead of "on" if a value isn't specified
4702
+ return elem.getAttribute("value") === null ? "on" : elem.value;
4703
+ };
4704
+ }
4705
+ });
4706
+ var rformElems = /^(?:input|select|textarea)$/i,
4707
+ rkeyEvent = /^key/,
4708
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
4709
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
4710
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
4711
+
4712
+ function returnTrue() {
4713
+ return true;
4714
+ }
4715
+
4716
+ function returnFalse() {
4717
+ return false;
4718
+ }
4719
+
4720
+ function safeActiveElement() {
4721
+ try {
4722
+ return document.activeElement;
4723
+ } catch ( err ) { }
4724
+ }
4725
+
4726
+ /*
4727
+ * Helper functions for managing events -- not part of the public interface.
4728
+ * Props to Dean Edwards' addEvent library for many of the ideas.
4729
+ */
4730
+ jQuery.event = {
4731
+
4732
+ global: {},
4733
+
4734
+ add: function( elem, types, handler, data, selector ) {
4735
+ var tmp, events, t, handleObjIn,
4736
+ special, eventHandle, handleObj,
4737
+ handlers, type, namespaces, origType,
4738
+ elemData = jQuery._data( elem );
4739
+
4740
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
4741
+ if ( !elemData ) {
4742
+ return;
4743
+ }
4744
+
4745
+ // Caller can pass in an object of custom data in lieu of the handler
4746
+ if ( handler.handler ) {
4747
+ handleObjIn = handler;
4748
+ handler = handleObjIn.handler;
4749
+ selector = handleObjIn.selector;
4750
+ }
4751
+
4752
+ // Make sure that the handler has a unique ID, used to find/remove it later
4753
+ if ( !handler.guid ) {
4754
+ handler.guid = jQuery.guid++;
4755
+ }
4756
+
4757
+ // Init the element's event structure and main handler, if this is the first
4758
+ if ( !(events = elemData.events) ) {
4759
+ events = elemData.events = {};
4760
+ }
4761
+ if ( !(eventHandle = elemData.handle) ) {
4762
+ eventHandle = elemData.handle = function( e ) {
4763
+ // Discard the second event of a jQuery.event.trigger() and
4764
+ // when an event is called after a page has unloaded
4765
+ return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
4766
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
4767
+ undefined;
4768
+ };
4769
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
4770
+ eventHandle.elem = elem;
4771
+ }
4772
+
4773
+ // Handle multiple events separated by a space
4774
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
4775
+ t = types.length;
4776
+ while ( t-- ) {
4777
+ tmp = rtypenamespace.exec( types[t] ) || [];
4778
+ type = origType = tmp[1];
4779
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
4780
+
4781
+ // There *must* be a type, no attaching namespace-only handlers
4782
+ if ( !type ) {
4783
+ continue;
4784
+ }
4785
+
4786
+ // If event changes its type, use the special event handlers for the changed type
4787
+ special = jQuery.event.special[ type ] || {};
4788
+
4789
+ // If selector defined, determine special event api type, otherwise given type
4790
+ type = ( selector ? special.delegateType : special.bindType ) || type;
4791
+
4792
+ // Update special based on newly reset type
4793
+ special = jQuery.event.special[ type ] || {};
4794
+
4795
+ // handleObj is passed to all event handlers
4796
+ handleObj = jQuery.extend({
4797
+ type: type,
4798
+ origType: origType,
4799
+ data: data,
4800
+ handler: handler,
4801
+ guid: handler.guid,
4802
+ selector: selector,
4803
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4804
+ namespace: namespaces.join(".")
4805
+ }, handleObjIn );
4806
+
4807
+ // Init the event handler queue if we're the first
4808
+ if ( !(handlers = events[ type ]) ) {
4809
+ handlers = events[ type ] = [];
4810
+ handlers.delegateCount = 0;
4811
+
4812
+ // Only use addEventListener/attachEvent if the special events handler returns false
4813
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4814
+ // Bind the global event handler to the element
4815
+ if ( elem.addEventListener ) {
4816
+ elem.addEventListener( type, eventHandle, false );
4817
+
4818
+ } else if ( elem.attachEvent ) {
4819
+ elem.attachEvent( "on" + type, eventHandle );
4820
+ }
4821
+ }
4822
+ }
4823
+
4824
+ if ( special.add ) {
4825
+ special.add.call( elem, handleObj );
4826
+
4827
+ if ( !handleObj.handler.guid ) {
4828
+ handleObj.handler.guid = handler.guid;
4829
+ }
4830
+ }
4831
+
4832
+ // Add to the element's handler list, delegates in front
4833
+ if ( selector ) {
4834
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
4835
+ } else {
4836
+ handlers.push( handleObj );
4837
+ }
4838
+
4839
+ // Keep track of which events have ever been used, for event optimization
4840
+ jQuery.event.global[ type ] = true;
4841
+ }
4842
+
4843
+ // Nullify elem to prevent memory leaks in IE
4844
+ elem = null;
4845
+ },
4846
+
4847
+ // Detach an event or set of events from an element
4848
+ remove: function( elem, types, handler, selector, mappedTypes ) {
4849
+ var j, handleObj, tmp,
4850
+ origCount, t, events,
4851
+ special, handlers, type,
4852
+ namespaces, origType,
4853
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
4854
+
4855
+ if ( !elemData || !(events = elemData.events) ) {
4856
+ return;
4857
+ }
4858
+
4859
+ // Once for each type.namespace in types; type may be omitted
4860
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
4861
+ t = types.length;
4862
+ while ( t-- ) {
4863
+ tmp = rtypenamespace.exec( types[t] ) || [];
4864
+ type = origType = tmp[1];
4865
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
4866
+
4867
+ // Unbind all events (on this namespace, if provided) for the element
4868
+ if ( !type ) {
4869
+ for ( type in events ) {
4870
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4871
+ }
4872
+ continue;
4873
+ }
4874
+
4875
+ special = jQuery.event.special[ type ] || {};
4876
+ type = ( selector ? special.delegateType : special.bindType ) || type;
4877
+ handlers = events[ type ] || [];
4878
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
4879
+
4880
+ // Remove matching events
4881
+ origCount = j = handlers.length;
4882
+ while ( j-- ) {
4883
+ handleObj = handlers[ j ];
4884
+
4885
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
4886
+ ( !handler || handler.guid === handleObj.guid ) &&
4887
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
4888
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
4889
+ handlers.splice( j, 1 );
4890
+
4891
+ if ( handleObj.selector ) {
4892
+ handlers.delegateCount--;
4893
+ }
4894
+ if ( special.remove ) {
4895
+ special.remove.call( elem, handleObj );
4896
+ }
4897
+ }
4898
+ }
4899
+
4900
+ // Remove generic event handler if we removed something and no more handlers exist
4901
+ // (avoids potential for endless recursion during removal of special event handlers)
4902
+ if ( origCount && !handlers.length ) {
4903
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4904
+ jQuery.removeEvent( elem, type, elemData.handle );
4905
+ }
4906
+
4907
+ delete events[ type ];
4908
+ }
4909
+ }
4910
+
4911
+ // Remove the expando if it's no longer used
4912
+ if ( jQuery.isEmptyObject( events ) ) {
4913
+ delete elemData.handle;
4914
+
4915
+ // removeData also checks for emptiness and clears the expando if empty
4916
+ // so use it instead of delete
4917
+ jQuery._removeData( elem, "events" );
4918
+ }
4919
+ },
4920
+
4921
+ trigger: function( event, data, elem, onlyHandlers ) {
4922
+ var handle, ontype, cur,
4923
+ bubbleType, special, tmp, i,
4924
+ eventPath = [ elem || document ],
4925
+ type = core_hasOwn.call( event, "type" ) ? event.type : event,
4926
+ namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
4927
+
4928
+ cur = tmp = elem = elem || document;
4929
+
4930
+ // Don't do events on text and comment nodes
4931
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
4932
+ return;
4933
+ }
4934
+
4935
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
4936
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
4937
+ return;
4938
+ }
4939
+
4940
+ if ( type.indexOf(".") >= 0 ) {
4941
+ // Namespaced trigger; create a regexp to match event type in handle()
4942
+ namespaces = type.split(".");
4943
+ type = namespaces.shift();
4944
+ namespaces.sort();
4945
+ }
4946
+ ontype = type.indexOf(":") < 0 && "on" + type;
4947
+
4948
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
4949
+ event = event[ jQuery.expando ] ?
4950
+ event :
4951
+ new jQuery.Event( type, typeof event === "object" && event );
4952
+
4953
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
4954
+ event.isTrigger = onlyHandlers ? 2 : 3;
4955
+ event.namespace = namespaces.join(".");
4956
+ event.namespace_re = event.namespace ?
4957
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
4958
+ null;
4959
+
4960
+ // Clean up the event in case it is being reused
4961
+ event.result = undefined;
4962
+ if ( !event.target ) {
4963
+ event.target = elem;
4964
+ }
4965
+
4966
+ // Clone any incoming data and prepend the event, creating the handler arg list
4967
+ data = data == null ?
4968
+ [ event ] :
4969
+ jQuery.makeArray( data, [ event ] );
4970
+
4971
+ // Allow special events to draw outside the lines
4972
+ special = jQuery.event.special[ type ] || {};
4973
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
4974
+ return;
4975
+ }
4976
+
4977
+ // Determine event propagation path in advance, per W3C events spec (#9951)
4978
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
4979
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
4980
+
4981
+ bubbleType = special.delegateType || type;
4982
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
4983
+ cur = cur.parentNode;
4984
+ }
4985
+ for ( ; cur; cur = cur.parentNode ) {
4986
+ eventPath.push( cur );
4987
+ tmp = cur;
4988
+ }
4989
+
4990
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
4991
+ if ( tmp === (elem.ownerDocument || document) ) {
4992
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
4993
+ }
4994
+ }
4995
+
4996
+ // Fire handlers on the event path
4997
+ i = 0;
4998
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
4999
+
5000
+ event.type = i > 1 ?
5001
+ bubbleType :
5002
+ special.bindType || type;
5003
+
5004
+ // jQuery handler
5005
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
5006
+ if ( handle ) {
5007
+ handle.apply( cur, data );
5008
+ }
5009
+
5010
+ // Native handler
5011
+ handle = ontype && cur[ ontype ];
5012
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
5013
+ event.preventDefault();
5014
+ }
5015
+ }
5016
+ event.type = type;
5017
+
5018
+ // If nobody prevented the default action, do it now
5019
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
5020
+
5021
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
5022
+ jQuery.acceptData( elem ) ) {
5023
+
5024
+ // Call a native DOM method on the target with the same name name as the event.
5025
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
5026
+ // Don't do default actions on window, that's where global variables be (#6170)
5027
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
5028
+
5029
+ // Don't re-trigger an onFOO event when we call its FOO() method
5030
+ tmp = elem[ ontype ];
5031
+
5032
+ if ( tmp ) {
5033
+ elem[ ontype ] = null;
5034
+ }
5035
+
5036
+ // Prevent re-triggering of the same event, since we already bubbled it above
5037
+ jQuery.event.triggered = type;
5038
+ try {
5039
+ elem[ type ]();
5040
+ } catch ( e ) {
5041
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
5042
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
5043
+ }
5044
+ jQuery.event.triggered = undefined;
5045
+
5046
+ if ( tmp ) {
5047
+ elem[ ontype ] = tmp;
5048
+ }
5049
+ }
5050
+ }
5051
+ }
5052
+
5053
+ return event.result;
5054
+ },
5055
+
5056
+ dispatch: function( event ) {
5057
+
5058
+ // Make a writable jQuery.Event from the native event object
5059
+ event = jQuery.event.fix( event );
5060
+
5061
+ var i, ret, handleObj, matched, j,
5062
+ handlerQueue = [],
5063
+ args = core_slice.call( arguments ),
5064
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
5065
+ special = jQuery.event.special[ event.type ] || {};
5066
+
5067
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
5068
+ args[0] = event;
5069
+ event.delegateTarget = this;
5070
+
5071
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
5072
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
5073
+ return;
5074
+ }
5075
+
5076
+ // Determine handlers
5077
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
5078
+
5079
+ // Run delegates first; they may want to stop propagation beneath us
5080
+ i = 0;
5081
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
5082
+ event.currentTarget = matched.elem;
5083
+
5084
+ j = 0;
5085
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
5086
+
5087
+ // Triggered event must either 1) have no namespace, or
5088
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
5089
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
5090
+
5091
+ event.handleObj = handleObj;
5092
+ event.data = handleObj.data;
5093
+
5094
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
5095
+ .apply( matched.elem, args );
5096
+
5097
+ if ( ret !== undefined ) {
5098
+ if ( (event.result = ret) === false ) {
5099
+ event.preventDefault();
5100
+ event.stopPropagation();
5101
+ }
5102
+ }
5103
+ }
5104
+ }
5105
+ }
5106
+
5107
+ // Call the postDispatch hook for the mapped type
5108
+ if ( special.postDispatch ) {
5109
+ special.postDispatch.call( this, event );
5110
+ }
5111
+
5112
+ return event.result;
5113
+ },
5114
+
5115
+ handlers: function( event, handlers ) {
5116
+ var sel, handleObj, matches, i,
5117
+ handlerQueue = [],
5118
+ delegateCount = handlers.delegateCount,
5119
+ cur = event.target;
5120
+
5121
+ // Find delegate handlers
5122
+ // Black-hole SVG <use> instance trees (#13180)
5123
+ // Avoid non-left-click bubbling in Firefox (#3861)
5124
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
5125
+
5126
+ /* jshint eqeqeq: false */
5127
+ for ( ; cur != this; cur = cur.parentNode || this ) {
5128
+ /* jshint eqeqeq: true */
5129
+
5130
+ // Don't check non-elements (#13208)
5131
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
5132
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
5133
+ matches = [];
5134
+ for ( i = 0; i < delegateCount; i++ ) {
5135
+ handleObj = handlers[ i ];
5136
+
5137
+ // Don't conflict with Object.prototype properties (#13203)
5138
+ sel = handleObj.selector + " ";
5139
+
5140
+ if ( matches[ sel ] === undefined ) {
5141
+ matches[ sel ] = handleObj.needsContext ?
5142
+ jQuery( sel, this ).index( cur ) >= 0 :
5143
+ jQuery.find( sel, this, null, [ cur ] ).length;
5144
+ }
5145
+ if ( matches[ sel ] ) {
5146
+ matches.push( handleObj );
5147
+ }
5148
+ }
5149
+ if ( matches.length ) {
5150
+ handlerQueue.push({ elem: cur, handlers: matches });
5151
+ }
5152
+ }
5153
+ }
5154
+ }
5155
+
5156
+ // Add the remaining (directly-bound) handlers
5157
+ if ( delegateCount < handlers.length ) {
5158
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
5159
+ }
5160
+
5161
+ return handlerQueue;
5162
+ },
5163
+
5164
+ fix: function( event ) {
5165
+ if ( event[ jQuery.expando ] ) {
5166
+ return event;
5167
+ }
5168
+
5169
+ // Create a writable copy of the event object and normalize some properties
5170
+ var i, prop, copy,
5171
+ type = event.type,
5172
+ originalEvent = event,
5173
+ fixHook = this.fixHooks[ type ];
5174
+
5175
+ if ( !fixHook ) {
5176
+ this.fixHooks[ type ] = fixHook =
5177
+ rmouseEvent.test( type ) ? this.mouseHooks :
5178
+ rkeyEvent.test( type ) ? this.keyHooks :
5179
+ {};
5180
+ }
5181
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
5182
+
5183
+ event = new jQuery.Event( originalEvent );
5184
+
5185
+ i = copy.length;
5186
+ while ( i-- ) {
5187
+ prop = copy[ i ];
5188
+ event[ prop ] = originalEvent[ prop ];
5189
+ }
5190
+
5191
+ // Support: IE<9
5192
+ // Fix target property (#1925)
5193
+ if ( !event.target ) {
5194
+ event.target = originalEvent.srcElement || document;
5195
+ }
5196
+
5197
+ // Support: Chrome 23+, Safari?
5198
+ // Target should not be a text node (#504, #13143)
5199
+ if ( event.target.nodeType === 3 ) {
5200
+ event.target = event.target.parentNode;
5201
+ }
5202
+
5203
+ // Support: IE<9
5204
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
5205
+ event.metaKey = !!event.metaKey;
5206
+
5207
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
5208
+ },
5209
+
5210
+ // Includes some event props shared by KeyEvent and MouseEvent
5211
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
5212
+
5213
+ fixHooks: {},
5214
+
5215
+ keyHooks: {
5216
+ props: "char charCode key keyCode".split(" "),
5217
+ filter: function( event, original ) {
5218
+
5219
+ // Add which for key events
5220
+ if ( event.which == null ) {
5221
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
5222
+ }
5223
+
5224
+ return event;
5225
+ }
5226
+ },
5227
+
5228
+ mouseHooks: {
5229
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
5230
+ filter: function( event, original ) {
5231
+ var body, eventDoc, doc,
5232
+ button = original.button,
5233
+ fromElement = original.fromElement;
5234
+
5235
+ // Calculate pageX/Y if missing and clientX/Y available
5236
+ if ( event.pageX == null && original.clientX != null ) {
5237
+ eventDoc = event.target.ownerDocument || document;
5238
+ doc = eventDoc.documentElement;
5239
+ body = eventDoc.body;
5240
+
5241
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
5242
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
5243
+ }
5244
+
5245
+ // Add relatedTarget, if necessary
5246
+ if ( !event.relatedTarget && fromElement ) {
5247
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
5248
+ }
5249
+
5250
+ // Add which for click: 1 === left; 2 === middle; 3 === right
5251
+ // Note: button is not normalized, so don't use it
5252
+ if ( !event.which && button !== undefined ) {
5253
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
5254
+ }
5255
+
5256
+ return event;
5257
+ }
5258
+ },
5259
+
5260
+ special: {
5261
+ load: {
5262
+ // Prevent triggered image.load events from bubbling to window.load
5263
+ noBubble: true
5264
+ },
5265
+ focus: {
5266
+ // Fire native event if possible so blur/focus sequence is correct
5267
+ trigger: function() {
5268
+ if ( this !== safeActiveElement() && this.focus ) {
5269
+ try {
5270
+ this.focus();
5271
+ return false;
5272
+ } catch ( e ) {
5273
+ // Support: IE<9
5274
+ // If we error on focus to hidden element (#1486, #12518),
5275
+ // let .trigger() run the handlers
5276
+ }
5277
+ }
5278
+ },
5279
+ delegateType: "focusin"
5280
+ },
5281
+ blur: {
5282
+ trigger: function() {
5283
+ if ( this === safeActiveElement() && this.blur ) {
5284
+ this.blur();
5285
+ return false;
5286
+ }
5287
+ },
5288
+ delegateType: "focusout"
5289
+ },
5290
+ click: {
5291
+ // For checkbox, fire native event so checked state will be right
5292
+ trigger: function() {
5293
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
5294
+ this.click();
5295
+ return false;
5296
+ }
5297
+ },
5298
+
5299
+ // For cross-browser consistency, don't fire native .click() on links
5300
+ _default: function( event ) {
5301
+ return jQuery.nodeName( event.target, "a" );
5302
+ }
5303
+ },
5304
+
5305
+ beforeunload: {
5306
+ postDispatch: function( event ) {
5307
+
5308
+ // Even when returnValue equals to undefined Firefox will still show alert
5309
+ if ( event.result !== undefined ) {
5310
+ event.originalEvent.returnValue = event.result;
5311
+ }
5312
+ }
5313
+ }
5314
+ },
5315
+
5316
+ simulate: function( type, elem, event, bubble ) {
5317
+ // Piggyback on a donor event to simulate a different one.
5318
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
5319
+ // simulated event prevents default then we do the same on the donor.
5320
+ var e = jQuery.extend(
5321
+ new jQuery.Event(),
5322
+ event,
5323
+ {
5324
+ type: type,
5325
+ isSimulated: true,
5326
+ originalEvent: {}
5327
+ }
5328
+ );
5329
+ if ( bubble ) {
5330
+ jQuery.event.trigger( e, null, elem );
5331
+ } else {
5332
+ jQuery.event.dispatch.call( elem, e );
5333
+ }
5334
+ if ( e.isDefaultPrevented() ) {
5335
+ event.preventDefault();
5336
+ }
5337
+ }
5338
+ };
5339
+
5340
+ jQuery.removeEvent = document.removeEventListener ?
5341
+ function( elem, type, handle ) {
5342
+ if ( elem.removeEventListener ) {
5343
+ elem.removeEventListener( type, handle, false );
5344
+ }
5345
+ } :
5346
+ function( elem, type, handle ) {
5347
+ var name = "on" + type;
5348
+
5349
+ if ( elem.detachEvent ) {
5350
+
5351
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
5352
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
5353
+ if ( typeof elem[ name ] === core_strundefined ) {
5354
+ elem[ name ] = null;
5355
+ }
5356
+
5357
+ elem.detachEvent( name, handle );
5358
+ }
5359
+ };
5360
+
5361
+ jQuery.Event = function( src, props ) {
5362
+ // Allow instantiation without the 'new' keyword
5363
+ if ( !(this instanceof jQuery.Event) ) {
5364
+ return new jQuery.Event( src, props );
5365
+ }
5366
+
5367
+ // Event object
5368
+ if ( src && src.type ) {
5369
+ this.originalEvent = src;
5370
+ this.type = src.type;
5371
+
5372
+ // Events bubbling up the document may have been marked as prevented
5373
+ // by a handler lower down the tree; reflect the correct value.
5374
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
5375
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
5376
+
5377
+ // Event type
5378
+ } else {
5379
+ this.type = src;
5380
+ }
5381
+
5382
+ // Put explicitly provided properties onto the event object
5383
+ if ( props ) {
5384
+ jQuery.extend( this, props );
5385
+ }
5386
+
5387
+ // Create a timestamp if incoming event doesn't have one
5388
+ this.timeStamp = src && src.timeStamp || jQuery.now();
5389
+
5390
+ // Mark it as fixed
5391
+ this[ jQuery.expando ] = true;
5392
+ };
5393
+
5394
+ // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
5395
+ // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
5396
+ jQuery.Event.prototype = {
5397
+ isDefaultPrevented: returnFalse,
5398
+ isPropagationStopped: returnFalse,
5399
+ isImmediatePropagationStopped: returnFalse,
5400
+
5401
+ preventDefault: function() {
5402
+ var e = this.originalEvent;
5403
+
5404
+ this.isDefaultPrevented = returnTrue;
5405
+ if ( !e ) {
5406
+ return;
5407
+ }
5408
+
5409
+ // If preventDefault exists, run it on the original event
5410
+ if ( e.preventDefault ) {
5411
+ e.preventDefault();
5412
+
5413
+ // Support: IE
5414
+ // Otherwise set the returnValue property of the original event to false
5415
+ } else {
5416
+ e.returnValue = false;
5417
+ }
5418
+ },
5419
+ stopPropagation: function() {
5420
+ var e = this.originalEvent;
5421
+
5422
+ this.isPropagationStopped = returnTrue;
5423
+ if ( !e ) {
5424
+ return;
5425
+ }
5426
+ // If stopPropagation exists, run it on the original event
5427
+ if ( e.stopPropagation ) {
5428
+ e.stopPropagation();
5429
+ }
5430
+
5431
+ // Support: IE
5432
+ // Set the cancelBubble property of the original event to true
5433
+ e.cancelBubble = true;
5434
+ },
5435
+ stopImmediatePropagation: function() {
5436
+ this.isImmediatePropagationStopped = returnTrue;
5437
+ this.stopPropagation();
5438
+ }
5439
+ };
5440
+
5441
+ // Create mouseenter/leave events using mouseover/out and event-time checks
5442
+ jQuery.each({
5443
+ mouseenter: "mouseover",
5444
+ mouseleave: "mouseout"
5445
+ }, function( orig, fix ) {
5446
+ jQuery.event.special[ orig ] = {
5447
+ delegateType: fix,
5448
+ bindType: fix,
5449
+
5450
+ handle: function( event ) {
5451
+ var ret,
5452
+ target = this,
5453
+ related = event.relatedTarget,
5454
+ handleObj = event.handleObj;
5455
+
5456
+ // For mousenter/leave call the handler if related is outside the target.
5457
+ // NB: No relatedTarget if the mouse left/entered the browser window
5458
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
5459
+ event.type = handleObj.origType;
5460
+ ret = handleObj.handler.apply( this, arguments );
5461
+ event.type = fix;
5462
+ }
5463
+ return ret;
5464
+ }
5465
+ };
5466
+ });
5467
+
5468
+ // IE submit delegation
5469
+ if ( !jQuery.support.submitBubbles ) {
5470
+
5471
+ jQuery.event.special.submit = {
5472
+ setup: function() {
5473
+ // Only need this for delegated form submit events
5474
+ if ( jQuery.nodeName( this, "form" ) ) {
5475
+ return false;
5476
+ }
5477
+
5478
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
5479
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
5480
+ // Node name check avoids a VML-related crash in IE (#9807)
5481
+ var elem = e.target,
5482
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
5483
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
5484
+ jQuery.event.add( form, "submit._submit", function( event ) {
5485
+ event._submit_bubble = true;
5486
+ });
5487
+ jQuery._data( form, "submitBubbles", true );
5488
+ }
5489
+ });
5490
+ // return undefined since we don't need an event listener
5491
+ },
5492
+
5493
+ postDispatch: function( event ) {
5494
+ // If form was submitted by the user, bubble the event up the tree
5495
+ if ( event._submit_bubble ) {
5496
+ delete event._submit_bubble;
5497
+ if ( this.parentNode && !event.isTrigger ) {
5498
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
5499
+ }
5500
+ }
5501
+ },
5502
+
5503
+ teardown: function() {
5504
+ // Only need this for delegated form submit events
5505
+ if ( jQuery.nodeName( this, "form" ) ) {
5506
+ return false;
5507
+ }
5508
+
5509
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
5510
+ jQuery.event.remove( this, "._submit" );
5511
+ }
5512
+ };
5513
+ }
5514
+
5515
+ // IE change delegation and checkbox/radio fix
5516
+ if ( !jQuery.support.changeBubbles ) {
5517
+
5518
+ jQuery.event.special.change = {
5519
+
5520
+ setup: function() {
5521
+
5522
+ if ( rformElems.test( this.nodeName ) ) {
5523
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
5524
+ // after a propertychange. Eat the blur-change in special.change.handle.
5525
+ // This still fires onchange a second time for check/radio after blur.
5526
+ if ( this.type === "checkbox" || this.type === "radio" ) {
5527
+ jQuery.event.add( this, "propertychange._change", function( event ) {
5528
+ if ( event.originalEvent.propertyName === "checked" ) {
5529
+ this._just_changed = true;
5530
+ }
5531
+ });
5532
+ jQuery.event.add( this, "click._change", function( event ) {
5533
+ if ( this._just_changed && !event.isTrigger ) {
5534
+ this._just_changed = false;
5535
+ }
5536
+ // Allow triggered, simulated change events (#11500)
5537
+ jQuery.event.simulate( "change", this, event, true );
5538
+ });
5539
+ }
5540
+ return false;
5541
+ }
5542
+ // Delegated event; lazy-add a change handler on descendant inputs
5543
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
5544
+ var elem = e.target;
5545
+
5546
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
5547
+ jQuery.event.add( elem, "change._change", function( event ) {
5548
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
5549
+ jQuery.event.simulate( "change", this.parentNode, event, true );
5550
+ }
5551
+ });
5552
+ jQuery._data( elem, "changeBubbles", true );
5553
+ }
5554
+ });
5555
+ },
5556
+
5557
+ handle: function( event ) {
5558
+ var elem = event.target;
5559
+
5560
+ // Swallow native change events from checkbox/radio, we already triggered them above
5561
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
5562
+ return event.handleObj.handler.apply( this, arguments );
5563
+ }
5564
+ },
5565
+
5566
+ teardown: function() {
5567
+ jQuery.event.remove( this, "._change" );
5568
+
5569
+ return !rformElems.test( this.nodeName );
5570
+ }
5571
+ };
5572
+ }
5573
+
5574
+ // Create "bubbling" focus and blur events
5575
+ if ( !jQuery.support.focusinBubbles ) {
5576
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
5577
+
5578
+ // Attach a single capturing handler while someone wants focusin/focusout
5579
+ var attaches = 0,
5580
+ handler = function( event ) {
5581
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
5582
+ };
5583
+
5584
+ jQuery.event.special[ fix ] = {
5585
+ setup: function() {
5586
+ if ( attaches++ === 0 ) {
5587
+ document.addEventListener( orig, handler, true );
5588
+ }
5589
+ },
5590
+ teardown: function() {
5591
+ if ( --attaches === 0 ) {
5592
+ document.removeEventListener( orig, handler, true );
5593
+ }
5594
+ }
5595
+ };
5596
+ });
5597
+ }
5598
+
5599
+ jQuery.fn.extend({
5600
+
5601
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
5602
+ var type, origFn;
5603
+
5604
+ // Types can be a map of types/handlers
5605
+ if ( typeof types === "object" ) {
5606
+ // ( types-Object, selector, data )
5607
+ if ( typeof selector !== "string" ) {
5608
+ // ( types-Object, data )
5609
+ data = data || selector;
5610
+ selector = undefined;
5611
+ }
5612
+ for ( type in types ) {
5613
+ this.on( type, selector, data, types[ type ], one );
5614
+ }
5615
+ return this;
5616
+ }
5617
+
5618
+ if ( data == null && fn == null ) {
5619
+ // ( types, fn )
5620
+ fn = selector;
5621
+ data = selector = undefined;
5622
+ } else if ( fn == null ) {
5623
+ if ( typeof selector === "string" ) {
5624
+ // ( types, selector, fn )
5625
+ fn = data;
5626
+ data = undefined;
5627
+ } else {
5628
+ // ( types, data, fn )
5629
+ fn = data;
5630
+ data = selector;
5631
+ selector = undefined;
5632
+ }
5633
+ }
5634
+ if ( fn === false ) {
5635
+ fn = returnFalse;
5636
+ } else if ( !fn ) {
5637
+ return this;
5638
+ }
5639
+
5640
+ if ( one === 1 ) {
5641
+ origFn = fn;
5642
+ fn = function( event ) {
5643
+ // Can use an empty set, since event contains the info
5644
+ jQuery().off( event );
5645
+ return origFn.apply( this, arguments );
5646
+ };
5647
+ // Use same guid so caller can remove using origFn
5648
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
5649
+ }
5650
+ return this.each( function() {
5651
+ jQuery.event.add( this, types, fn, data, selector );
5652
+ });
5653
+ },
5654
+ one: function( types, selector, data, fn ) {
5655
+ return this.on( types, selector, data, fn, 1 );
5656
+ },
5657
+ off: function( types, selector, fn ) {
5658
+ var handleObj, type;
5659
+ if ( types && types.preventDefault && types.handleObj ) {
5660
+ // ( event ) dispatched jQuery.Event
5661
+ handleObj = types.handleObj;
5662
+ jQuery( types.delegateTarget ).off(
5663
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
5664
+ handleObj.selector,
5665
+ handleObj.handler
5666
+ );
5667
+ return this;
5668
+ }
5669
+ if ( typeof types === "object" ) {
5670
+ // ( types-object [, selector] )
5671
+ for ( type in types ) {
5672
+ this.off( type, selector, types[ type ] );
5673
+ }
5674
+ return this;
5675
+ }
5676
+ if ( selector === false || typeof selector === "function" ) {
5677
+ // ( types [, fn] )
5678
+ fn = selector;
5679
+ selector = undefined;
5680
+ }
5681
+ if ( fn === false ) {
5682
+ fn = returnFalse;
5683
+ }
5684
+ return this.each(function() {
5685
+ jQuery.event.remove( this, types, fn, selector );
5686
+ });
5687
+ },
5688
+
5689
+ trigger: function( type, data ) {
5690
+ return this.each(function() {
5691
+ jQuery.event.trigger( type, data, this );
5692
+ });
5693
+ },
5694
+ triggerHandler: function( type, data ) {
5695
+ var elem = this[0];
5696
+ if ( elem ) {
5697
+ return jQuery.event.trigger( type, data, elem, true );
5698
+ }
5699
+ }
5700
+ });
5701
+ var isSimple = /^.[^:#\[\.,]*$/,
5702
+ rparentsprev = /^(?:parents|prev(?:Until|All))/,
5703
+ rneedsContext = jQuery.expr.match.needsContext,
5704
+ // methods guaranteed to produce a unique set when starting from a unique set
5705
+ guaranteedUnique = {
5706
+ children: true,
5707
+ contents: true,
5708
+ next: true,
5709
+ prev: true
5710
+ };
5711
+
5712
+ jQuery.fn.extend({
5713
+ find: function( selector ) {
5714
+ var i,
5715
+ ret = [],
5716
+ self = this,
5717
+ len = self.length;
5718
+
5719
+ if ( typeof selector !== "string" ) {
5720
+ return this.pushStack( jQuery( selector ).filter(function() {
5721
+ for ( i = 0; i < len; i++ ) {
5722
+ if ( jQuery.contains( self[ i ], this ) ) {
5723
+ return true;
5724
+ }
5725
+ }
5726
+ }) );
5727
+ }
5728
+
5729
+ for ( i = 0; i < len; i++ ) {
5730
+ jQuery.find( selector, self[ i ], ret );
5731
+ }
5732
+
5733
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
5734
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
5735
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
5736
+ return ret;
5737
+ },
5738
+
5739
+ has: function( target ) {
5740
+ var i,
5741
+ targets = jQuery( target, this ),
5742
+ len = targets.length;
5743
+
5744
+ return this.filter(function() {
5745
+ for ( i = 0; i < len; i++ ) {
5746
+ if ( jQuery.contains( this, targets[i] ) ) {
5747
+ return true;
5748
+ }
5749
+ }
5750
+ });
5751
+ },
5752
+
5753
+ not: function( selector ) {
5754
+ return this.pushStack( winnow(this, selector || [], true) );
5755
+ },
5756
+
5757
+ filter: function( selector ) {
5758
+ return this.pushStack( winnow(this, selector || [], false) );
5759
+ },
5760
+
5761
+ is: function( selector ) {
5762
+ return !!winnow(
5763
+ this,
5764
+
5765
+ // If this is a positional/relative selector, check membership in the returned set
5766
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
5767
+ typeof selector === "string" && rneedsContext.test( selector ) ?
5768
+ jQuery( selector ) :
5769
+ selector || [],
5770
+ false
5771
+ ).length;
5772
+ },
5773
+
5774
+ closest: function( selectors, context ) {
5775
+ var cur,
5776
+ i = 0,
5777
+ l = this.length,
5778
+ ret = [],
5779
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
5780
+ jQuery( selectors, context || this.context ) :
5781
+ 0;
5782
+
5783
+ for ( ; i < l; i++ ) {
5784
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
5785
+ // Always skip document fragments
5786
+ if ( cur.nodeType < 11 && (pos ?
5787
+ pos.index(cur) > -1 :
5788
+
5789
+ // Don't pass non-elements to Sizzle
5790
+ cur.nodeType === 1 &&
5791
+ jQuery.find.matchesSelector(cur, selectors)) ) {
5792
+
5793
+ cur = ret.push( cur );
5794
+ break;
5795
+ }
5796
+ }
5797
+ }
5798
+
5799
+ return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
5800
+ },
5801
+
5802
+ // Determine the position of an element within
5803
+ // the matched set of elements
5804
+ index: function( elem ) {
5805
+
5806
+ // No argument, return index in parent
5807
+ if ( !elem ) {
5808
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
5809
+ }
5810
+
5811
+ // index in selector
5812
+ if ( typeof elem === "string" ) {
5813
+ return jQuery.inArray( this[0], jQuery( elem ) );
5814
+ }
5815
+
5816
+ // Locate the position of the desired element
5817
+ return jQuery.inArray(
5818
+ // If it receives a jQuery object, the first element is used
5819
+ elem.jquery ? elem[0] : elem, this );
5820
+ },
5821
+
5822
+ add: function( selector, context ) {
5823
+ var set = typeof selector === "string" ?
5824
+ jQuery( selector, context ) :
5825
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
5826
+ all = jQuery.merge( this.get(), set );
5827
+
5828
+ return this.pushStack( jQuery.unique(all) );
5829
+ },
5830
+
5831
+ addBack: function( selector ) {
5832
+ return this.add( selector == null ?
5833
+ this.prevObject : this.prevObject.filter(selector)
5834
+ );
5835
+ }
5836
+ });
5837
+
5838
+ function sibling( cur, dir ) {
5839
+ do {
5840
+ cur = cur[ dir ];
5841
+ } while ( cur && cur.nodeType !== 1 );
5842
+
5843
+ return cur;
5844
+ }
5845
+
5846
+ jQuery.each({
5847
+ parent: function( elem ) {
5848
+ var parent = elem.parentNode;
5849
+ return parent && parent.nodeType !== 11 ? parent : null;
5850
+ },
5851
+ parents: function( elem ) {
5852
+ return jQuery.dir( elem, "parentNode" );
5853
+ },
5854
+ parentsUntil: function( elem, i, until ) {
5855
+ return jQuery.dir( elem, "parentNode", until );
5856
+ },
5857
+ next: function( elem ) {
5858
+ return sibling( elem, "nextSibling" );
5859
+ },
5860
+ prev: function( elem ) {
5861
+ return sibling( elem, "previousSibling" );
5862
+ },
5863
+ nextAll: function( elem ) {
5864
+ return jQuery.dir( elem, "nextSibling" );
5865
+ },
5866
+ prevAll: function( elem ) {
5867
+ return jQuery.dir( elem, "previousSibling" );
5868
+ },
5869
+ nextUntil: function( elem, i, until ) {
5870
+ return jQuery.dir( elem, "nextSibling", until );
5871
+ },
5872
+ prevUntil: function( elem, i, until ) {
5873
+ return jQuery.dir( elem, "previousSibling", until );
5874
+ },
5875
+ siblings: function( elem ) {
5876
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
5877
+ },
5878
+ children: function( elem ) {
5879
+ return jQuery.sibling( elem.firstChild );
5880
+ },
5881
+ contents: function( elem ) {
5882
+ return jQuery.nodeName( elem, "iframe" ) ?
5883
+ elem.contentDocument || elem.contentWindow.document :
5884
+ jQuery.merge( [], elem.childNodes );
5885
+ }
5886
+ }, function( name, fn ) {
5887
+ jQuery.fn[ name ] = function( until, selector ) {
5888
+ var ret = jQuery.map( this, fn, until );
5889
+
5890
+ if ( name.slice( -5 ) !== "Until" ) {
5891
+ selector = until;
5892
+ }
5893
+
5894
+ if ( selector && typeof selector === "string" ) {
5895
+ ret = jQuery.filter( selector, ret );
5896
+ }
5897
+
5898
+ if ( this.length > 1 ) {
5899
+ // Remove duplicates
5900
+ if ( !guaranteedUnique[ name ] ) {
5901
+ ret = jQuery.unique( ret );
5902
+ }
5903
+
5904
+ // Reverse order for parents* and prev-derivatives
5905
+ if ( rparentsprev.test( name ) ) {
5906
+ ret = ret.reverse();
5907
+ }
5908
+ }
5909
+
5910
+ return this.pushStack( ret );
5911
+ };
5912
+ });
5913
+
5914
+ jQuery.extend({
5915
+ filter: function( expr, elems, not ) {
5916
+ var elem = elems[ 0 ];
5917
+
5918
+ if ( not ) {
5919
+ expr = ":not(" + expr + ")";
5920
+ }
5921
+
5922
+ return elems.length === 1 && elem.nodeType === 1 ?
5923
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
5924
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
5925
+ return elem.nodeType === 1;
5926
+ }));
5927
+ },
5928
+
5929
+ dir: function( elem, dir, until ) {
5930
+ var matched = [],
5931
+ cur = elem[ dir ];
5932
+
5933
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
5934
+ if ( cur.nodeType === 1 ) {
5935
+ matched.push( cur );
5936
+ }
5937
+ cur = cur[dir];
5938
+ }
5939
+ return matched;
5940
+ },
5941
+
5942
+ sibling: function( n, elem ) {
5943
+ var r = [];
5944
+
5945
+ for ( ; n; n = n.nextSibling ) {
5946
+ if ( n.nodeType === 1 && n !== elem ) {
5947
+ r.push( n );
5948
+ }
5949
+ }
5950
+
5951
+ return r;
5952
+ }
5953
+ });
5954
+
5955
+ // Implement the identical functionality for filter and not
5956
+ function winnow( elements, qualifier, not ) {
5957
+ if ( jQuery.isFunction( qualifier ) ) {
5958
+ return jQuery.grep( elements, function( elem, i ) {
5959
+ /* jshint -W018 */
5960
+ return !!qualifier.call( elem, i, elem ) !== not;
5961
+ });
5962
+
5963
+ }
5964
+
5965
+ if ( qualifier.nodeType ) {
5966
+ return jQuery.grep( elements, function( elem ) {
5967
+ return ( elem === qualifier ) !== not;
5968
+ });
5969
+
5970
+ }
5971
+
5972
+ if ( typeof qualifier === "string" ) {
5973
+ if ( isSimple.test( qualifier ) ) {
5974
+ return jQuery.filter( qualifier, elements, not );
5975
+ }
5976
+
5977
+ qualifier = jQuery.filter( qualifier, elements );
5978
+ }
5979
+
5980
+ return jQuery.grep( elements, function( elem ) {
5981
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
5982
+ });
5983
+ }
5984
+ function createSafeFragment( document ) {
5985
+ var list = nodeNames.split( "|" ),
5986
+ safeFrag = document.createDocumentFragment();
5987
+
5988
+ if ( safeFrag.createElement ) {
5989
+ while ( list.length ) {
5990
+ safeFrag.createElement(
5991
+ list.pop()
5992
+ );
5993
+ }
5994
+ }
5995
+ return safeFrag;
5996
+ }
5997
+
5998
+ var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
5999
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
6000
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
6001
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
6002
+ rleadingWhitespace = /^\s+/,
6003
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
6004
+ rtagName = /<([\w:]+)/,
6005
+ rtbody = /<tbody/i,
6006
+ rhtml = /<|&#?\w+;/,
6007
+ rnoInnerhtml = /<(?:script|style|link)/i,
6008
+ manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
6009
+ // checked="checked" or checked
6010
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
6011
+ rscriptType = /^$|\/(?:java|ecma)script/i,
6012
+ rscriptTypeMasked = /^true\/(.*)/,
6013
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
6014
+
6015
+ // We have to close these tags to support XHTML (#13200)
6016
+ wrapMap = {
6017
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
6018
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
6019
+ area: [ 1, "<map>", "</map>" ],
6020
+ param: [ 1, "<object>", "</object>" ],
6021
+ thead: [ 1, "<table>", "</table>" ],
6022
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
6023
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
6024
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
6025
+
6026
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
6027
+ // unless wrapped in a div with non-breaking characters in front of it.
6028
+ _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
6029
+ },
6030
+ safeFragment = createSafeFragment( document ),
6031
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
6032
+
6033
+ wrapMap.optgroup = wrapMap.option;
6034
+ wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
6035
+ wrapMap.th = wrapMap.td;
6036
+
6037
+ jQuery.fn.extend({
6038
+ text: function( value ) {
6039
+ return jQuery.access( this, function( value ) {
6040
+ return value === undefined ?
6041
+ jQuery.text( this ) :
6042
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
6043
+ }, null, value, arguments.length );
6044
+ },
6045
+
6046
+ append: function() {
6047
+ return this.domManip( arguments, function( elem ) {
6048
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6049
+ var target = manipulationTarget( this, elem );
6050
+ target.appendChild( elem );
6051
+ }
6052
+ });
6053
+ },
6054
+
6055
+ prepend: function() {
6056
+ return this.domManip( arguments, function( elem ) {
6057
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6058
+ var target = manipulationTarget( this, elem );
6059
+ target.insertBefore( elem, target.firstChild );
6060
+ }
6061
+ });
6062
+ },
6063
+
6064
+ before: function() {
6065
+ return this.domManip( arguments, function( elem ) {
6066
+ if ( this.parentNode ) {
6067
+ this.parentNode.insertBefore( elem, this );
6068
+ }
6069
+ });
6070
+ },
6071
+
6072
+ after: function() {
6073
+ return this.domManip( arguments, function( elem ) {
6074
+ if ( this.parentNode ) {
6075
+ this.parentNode.insertBefore( elem, this.nextSibling );
6076
+ }
6077
+ });
6078
+ },
6079
+
6080
+ // keepData is for internal use only--do not document
6081
+ remove: function( selector, keepData ) {
6082
+ var elem,
6083
+ elems = selector ? jQuery.filter( selector, this ) : this,
6084
+ i = 0;
6085
+
6086
+ for ( ; (elem = elems[i]) != null; i++ ) {
6087
+
6088
+ if ( !keepData && elem.nodeType === 1 ) {
6089
+ jQuery.cleanData( getAll( elem ) );
6090
+ }
6091
+
6092
+ if ( elem.parentNode ) {
6093
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
6094
+ setGlobalEval( getAll( elem, "script" ) );
6095
+ }
6096
+ elem.parentNode.removeChild( elem );
6097
+ }
6098
+ }
6099
+
6100
+ return this;
6101
+ },
6102
+
6103
+ empty: function() {
6104
+ var elem,
6105
+ i = 0;
6106
+
6107
+ for ( ; (elem = this[i]) != null; i++ ) {
6108
+ // Remove element nodes and prevent memory leaks
6109
+ if ( elem.nodeType === 1 ) {
6110
+ jQuery.cleanData( getAll( elem, false ) );
6111
+ }
6112
+
6113
+ // Remove any remaining nodes
6114
+ while ( elem.firstChild ) {
6115
+ elem.removeChild( elem.firstChild );
6116
+ }
6117
+
6118
+ // If this is a select, ensure that it displays empty (#12336)
6119
+ // Support: IE<9
6120
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
6121
+ elem.options.length = 0;
6122
+ }
6123
+ }
6124
+
6125
+ return this;
6126
+ },
6127
+
6128
+ clone: function( dataAndEvents, deepDataAndEvents ) {
6129
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6130
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6131
+
6132
+ return this.map( function () {
6133
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6134
+ });
6135
+ },
6136
+
6137
+ html: function( value ) {
6138
+ return jQuery.access( this, function( value ) {
6139
+ var elem = this[0] || {},
6140
+ i = 0,
6141
+ l = this.length;
6142
+
6143
+ if ( value === undefined ) {
6144
+ return elem.nodeType === 1 ?
6145
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
6146
+ undefined;
6147
+ }
6148
+
6149
+ // See if we can take a shortcut and just use innerHTML
6150
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6151
+ ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
6152
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
6153
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
6154
+
6155
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
6156
+
6157
+ try {
6158
+ for (; i < l; i++ ) {
6159
+ // Remove element nodes and prevent memory leaks
6160
+ elem = this[i] || {};
6161
+ if ( elem.nodeType === 1 ) {
6162
+ jQuery.cleanData( getAll( elem, false ) );
6163
+ elem.innerHTML = value;
6164
+ }
6165
+ }
6166
+
6167
+ elem = 0;
6168
+
6169
+ // If using innerHTML throws an exception, use the fallback method
6170
+ } catch(e) {}
6171
+ }
6172
+
6173
+ if ( elem ) {
6174
+ this.empty().append( value );
6175
+ }
6176
+ }, null, value, arguments.length );
6177
+ },
6178
+
6179
+ replaceWith: function() {
6180
+ var
6181
+ // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
6182
+ args = jQuery.map( this, function( elem ) {
6183
+ return [ elem.nextSibling, elem.parentNode ];
6184
+ }),
6185
+ i = 0;
6186
+
6187
+ // Make the changes, replacing each context element with the new content
6188
+ this.domManip( arguments, function( elem ) {
6189
+ var next = args[ i++ ],
6190
+ parent = args[ i++ ];
6191
+
6192
+ if ( parent ) {
6193
+ // Don't use the snapshot next if it has moved (#13810)
6194
+ if ( next && next.parentNode !== parent ) {
6195
+ next = this.nextSibling;
6196
+ }
6197
+ jQuery( this ).remove();
6198
+ parent.insertBefore( elem, next );
6199
+ }
6200
+ // Allow new content to include elements from the context set
6201
+ }, true );
6202
+
6203
+ // Force removal if there was no new content (e.g., from empty arguments)
6204
+ return i ? this : this.remove();
6205
+ },
6206
+
6207
+ detach: function( selector ) {
6208
+ return this.remove( selector, true );
6209
+ },
6210
+
6211
+ domManip: function( args, callback, allowIntersection ) {
6212
+
6213
+ // Flatten any nested arrays
6214
+ args = core_concat.apply( [], args );
6215
+
6216
+ var first, node, hasScripts,
6217
+ scripts, doc, fragment,
6218
+ i = 0,
6219
+ l = this.length,
6220
+ set = this,
6221
+ iNoClone = l - 1,
6222
+ value = args[0],
6223
+ isFunction = jQuery.isFunction( value );
6224
+
6225
+ // We can't cloneNode fragments that contain checked, in WebKit
6226
+ if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
6227
+ return this.each(function( index ) {
6228
+ var self = set.eq( index );
6229
+ if ( isFunction ) {
6230
+ args[0] = value.call( this, index, self.html() );
6231
+ }
6232
+ self.domManip( args, callback, allowIntersection );
6233
+ });
6234
+ }
6235
+
6236
+ if ( l ) {
6237
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
6238
+ first = fragment.firstChild;
6239
+
6240
+ if ( fragment.childNodes.length === 1 ) {
6241
+ fragment = first;
6242
+ }
6243
+
6244
+ if ( first ) {
6245
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
6246
+ hasScripts = scripts.length;
6247
+
6248
+ // Use the original fragment for the last item instead of the first because it can end up
6249
+ // being emptied incorrectly in certain situations (#8070).
6250
+ for ( ; i < l; i++ ) {
6251
+ node = fragment;
6252
+
6253
+ if ( i !== iNoClone ) {
6254
+ node = jQuery.clone( node, true, true );
6255
+
6256
+ // Keep references to cloned scripts for later restoration
6257
+ if ( hasScripts ) {
6258
+ jQuery.merge( scripts, getAll( node, "script" ) );
6259
+ }
6260
+ }
6261
+
6262
+ callback.call( this[i], node, i );
6263
+ }
6264
+
6265
+ if ( hasScripts ) {
6266
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
6267
+
6268
+ // Reenable scripts
6269
+ jQuery.map( scripts, restoreScript );
6270
+
6271
+ // Evaluate executable scripts on first document insertion
6272
+ for ( i = 0; i < hasScripts; i++ ) {
6273
+ node = scripts[ i ];
6274
+ if ( rscriptType.test( node.type || "" ) &&
6275
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
6276
+
6277
+ if ( node.src ) {
6278
+ // Hope ajax is available...
6279
+ jQuery._evalUrl( node.src );
6280
+ } else {
6281
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
6282
+ }
6283
+ }
6284
+ }
6285
+ }
6286
+
6287
+ // Fix #11809: Avoid leaking memory
6288
+ fragment = first = null;
6289
+ }
6290
+ }
6291
+
6292
+ return this;
6293
+ }
6294
+ });
6295
+
6296
+ // Support: IE<8
6297
+ // Manipulating tables requires a tbody
6298
+ function manipulationTarget( elem, content ) {
6299
+ return jQuery.nodeName( elem, "table" ) &&
6300
+ jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
6301
+
6302
+ elem.getElementsByTagName("tbody")[0] ||
6303
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
6304
+ elem;
6305
+ }
6306
+
6307
+ // Replace/restore the type attribute of script elements for safe DOM manipulation
6308
+ function disableScript( elem ) {
6309
+ elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
6310
+ return elem;
6311
+ }
6312
+ function restoreScript( elem ) {
6313
+ var match = rscriptTypeMasked.exec( elem.type );
6314
+ if ( match ) {
6315
+ elem.type = match[1];
6316
+ } else {
6317
+ elem.removeAttribute("type");
6318
+ }
6319
+ return elem;
6320
+ }
6321
+
6322
+ // Mark scripts as having already been evaluated
6323
+ function setGlobalEval( elems, refElements ) {
6324
+ var elem,
6325
+ i = 0;
6326
+ for ( ; (elem = elems[i]) != null; i++ ) {
6327
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
6328
+ }
6329
+ }
6330
+
6331
+ function cloneCopyEvent( src, dest ) {
6332
+
6333
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
6334
+ return;
6335
+ }
6336
+
6337
+ var type, i, l,
6338
+ oldData = jQuery._data( src ),
6339
+ curData = jQuery._data( dest, oldData ),
6340
+ events = oldData.events;
6341
+
6342
+ if ( events ) {
6343
+ delete curData.handle;
6344
+ curData.events = {};
6345
+
6346
+ for ( type in events ) {
6347
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
6348
+ jQuery.event.add( dest, type, events[ type ][ i ] );
6349
+ }
6350
+ }
6351
+ }
6352
+
6353
+ // make the cloned public data object a copy from the original
6354
+ if ( curData.data ) {
6355
+ curData.data = jQuery.extend( {}, curData.data );
6356
+ }
6357
+ }
6358
+
6359
+ function fixCloneNodeIssues( src, dest ) {
6360
+ var nodeName, e, data;
6361
+
6362
+ // We do not need to do anything for non-Elements
6363
+ if ( dest.nodeType !== 1 ) {
6364
+ return;
6365
+ }
6366
+
6367
+ nodeName = dest.nodeName.toLowerCase();
6368
+
6369
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
6370
+ if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
6371
+ data = jQuery._data( dest );
6372
+
6373
+ for ( e in data.events ) {
6374
+ jQuery.removeEvent( dest, e, data.handle );
6375
+ }
6376
+
6377
+ // Event data gets referenced instead of copied if the expando gets copied too
6378
+ dest.removeAttribute( jQuery.expando );
6379
+ }
6380
+
6381
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
6382
+ if ( nodeName === "script" && dest.text !== src.text ) {
6383
+ disableScript( dest ).text = src.text;
6384
+ restoreScript( dest );
6385
+
6386
+ // IE6-10 improperly clones children of object elements using classid.
6387
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
6388
+ } else if ( nodeName === "object" ) {
6389
+ if ( dest.parentNode ) {
6390
+ dest.outerHTML = src.outerHTML;
6391
+ }
6392
+
6393
+ // This path appears unavoidable for IE9. When cloning an object
6394
+ // element in IE9, the outerHTML strategy above is not sufficient.
6395
+ // If the src has innerHTML and the destination does not,
6396
+ // copy the src.innerHTML into the dest.innerHTML. #10324
6397
+ if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
6398
+ dest.innerHTML = src.innerHTML;
6399
+ }
6400
+
6401
+ } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
6402
+ // IE6-8 fails to persist the checked state of a cloned checkbox
6403
+ // or radio button. Worse, IE6-7 fail to give the cloned element
6404
+ // a checked appearance if the defaultChecked value isn't also set
6405
+
6406
+ dest.defaultChecked = dest.checked = src.checked;
6407
+
6408
+ // IE6-7 get confused and end up setting the value of a cloned
6409
+ // checkbox/radio button to an empty string instead of "on"
6410
+ if ( dest.value !== src.value ) {
6411
+ dest.value = src.value;
6412
+ }
6413
+
6414
+ // IE6-8 fails to return the selected option to the default selected
6415
+ // state when cloning options
6416
+ } else if ( nodeName === "option" ) {
6417
+ dest.defaultSelected = dest.selected = src.defaultSelected;
6418
+
6419
+ // IE6-8 fails to set the defaultValue to the correct value when
6420
+ // cloning other types of input fields
6421
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
6422
+ dest.defaultValue = src.defaultValue;
6423
+ }
6424
+ }
6425
+
6426
+ jQuery.each({
6427
+ appendTo: "append",
6428
+ prependTo: "prepend",
6429
+ insertBefore: "before",
6430
+ insertAfter: "after",
6431
+ replaceAll: "replaceWith"
6432
+ }, function( name, original ) {
6433
+ jQuery.fn[ name ] = function( selector ) {
6434
+ var elems,
6435
+ i = 0,
6436
+ ret = [],
6437
+ insert = jQuery( selector ),
6438
+ last = insert.length - 1;
6439
+
6440
+ for ( ; i <= last; i++ ) {
6441
+ elems = i === last ? this : this.clone(true);
6442
+ jQuery( insert[i] )[ original ]( elems );
6443
+
6444
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
6445
+ core_push.apply( ret, elems.get() );
6446
+ }
6447
+
6448
+ return this.pushStack( ret );
6449
+ };
6450
+ });
6451
+
6452
+ function getAll( context, tag ) {
6453
+ var elems, elem,
6454
+ i = 0,
6455
+ found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
6456
+ typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
6457
+ undefined;
6458
+
6459
+ if ( !found ) {
6460
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
6461
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
6462
+ found.push( elem );
6463
+ } else {
6464
+ jQuery.merge( found, getAll( elem, tag ) );
6465
+ }
6466
+ }
6467
+ }
6468
+
6469
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
6470
+ jQuery.merge( [ context ], found ) :
6471
+ found;
6472
+ }
6473
+
6474
+ // Used in buildFragment, fixes the defaultChecked property
6475
+ function fixDefaultChecked( elem ) {
6476
+ if ( manipulation_rcheckableType.test( elem.type ) ) {
6477
+ elem.defaultChecked = elem.checked;
6478
+ }
6479
+ }
6480
+
6481
+ jQuery.extend({
6482
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
6483
+ var destElements, node, clone, i, srcElements,
6484
+ inPage = jQuery.contains( elem.ownerDocument, elem );
6485
+
6486
+ if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
6487
+ clone = elem.cloneNode( true );
6488
+
6489
+ // IE<=8 does not properly clone detached, unknown element nodes
6490
+ } else {
6491
+ fragmentDiv.innerHTML = elem.outerHTML;
6492
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
6493
+ }
6494
+
6495
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
6496
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
6497
+
6498
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
6499
+ destElements = getAll( clone );
6500
+ srcElements = getAll( elem );
6501
+
6502
+ // Fix all IE cloning issues
6503
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
6504
+ // Ensure that the destination node is not null; Fixes #9587
6505
+ if ( destElements[i] ) {
6506
+ fixCloneNodeIssues( node, destElements[i] );
6507
+ }
6508
+ }
6509
+ }
6510
+
6511
+ // Copy the events from the original to the clone
6512
+ if ( dataAndEvents ) {
6513
+ if ( deepDataAndEvents ) {
6514
+ srcElements = srcElements || getAll( elem );
6515
+ destElements = destElements || getAll( clone );
6516
+
6517
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
6518
+ cloneCopyEvent( node, destElements[i] );
6519
+ }
6520
+ } else {
6521
+ cloneCopyEvent( elem, clone );
6522
+ }
6523
+ }
6524
+
6525
+ // Preserve script evaluation history
6526
+ destElements = getAll( clone, "script" );
6527
+ if ( destElements.length > 0 ) {
6528
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
6529
+ }
6530
+
6531
+ destElements = srcElements = node = null;
6532
+
6533
+ // Return the cloned set
6534
+ return clone;
6535
+ },
6536
+
6537
+ buildFragment: function( elems, context, scripts, selection ) {
6538
+ var j, elem, contains,
6539
+ tmp, tag, tbody, wrap,
6540
+ l = elems.length,
6541
+
6542
+ // Ensure a safe fragment
6543
+ safe = createSafeFragment( context ),
6544
+
6545
+ nodes = [],
6546
+ i = 0;
6547
+
6548
+ for ( ; i < l; i++ ) {
6549
+ elem = elems[ i ];
6550
+
6551
+ if ( elem || elem === 0 ) {
6552
+
6553
+ // Add nodes directly
6554
+ if ( jQuery.type( elem ) === "object" ) {
6555
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
6556
+
6557
+ // Convert non-html into a text node
6558
+ } else if ( !rhtml.test( elem ) ) {
6559
+ nodes.push( context.createTextNode( elem ) );
6560
+
6561
+ // Convert html into DOM nodes
6562
+ } else {
6563
+ tmp = tmp || safe.appendChild( context.createElement("div") );
6564
+
6565
+ // Deserialize a standard representation
6566
+ tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
6567
+ wrap = wrapMap[ tag ] || wrapMap._default;
6568
+
6569
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
6570
+
6571
+ // Descend through wrappers to the right content
6572
+ j = wrap[0];
6573
+ while ( j-- ) {
6574
+ tmp = tmp.lastChild;
6575
+ }
6576
+
6577
+ // Manually add leading whitespace removed by IE
6578
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
6579
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
6580
+ }
6581
+
6582
+ // Remove IE's autoinserted <tbody> from table fragments
6583
+ if ( !jQuery.support.tbody ) {
6584
+
6585
+ // String was a <table>, *may* have spurious <tbody>
6586
+ elem = tag === "table" && !rtbody.test( elem ) ?
6587
+ tmp.firstChild :
6588
+
6589
+ // String was a bare <thead> or <tfoot>
6590
+ wrap[1] === "<table>" && !rtbody.test( elem ) ?
6591
+ tmp :
6592
+ 0;
6593
+
6594
+ j = elem && elem.childNodes.length;
6595
+ while ( j-- ) {
6596
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
6597
+ elem.removeChild( tbody );
6598
+ }
6599
+ }
6600
+ }
6601
+
6602
+ jQuery.merge( nodes, tmp.childNodes );
6603
+
6604
+ // Fix #12392 for WebKit and IE > 9
6605
+ tmp.textContent = "";
6606
+
6607
+ // Fix #12392 for oldIE
6608
+ while ( tmp.firstChild ) {
6609
+ tmp.removeChild( tmp.firstChild );
6610
+ }
6611
+
6612
+ // Remember the top-level container for proper cleanup
6613
+ tmp = safe.lastChild;
6614
+ }
6615
+ }
6616
+ }
6617
+
6618
+ // Fix #11356: Clear elements from fragment
6619
+ if ( tmp ) {
6620
+ safe.removeChild( tmp );
6621
+ }
6622
+
6623
+ // Reset defaultChecked for any radios and checkboxes
6624
+ // about to be appended to the DOM in IE 6/7 (#8060)
6625
+ if ( !jQuery.support.appendChecked ) {
6626
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
6627
+ }
6628
+
6629
+ i = 0;
6630
+ while ( (elem = nodes[ i++ ]) ) {
6631
+
6632
+ // #4087 - If origin and destination elements are the same, and this is
6633
+ // that element, do not do anything
6634
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
6635
+ continue;
6636
+ }
6637
+
6638
+ contains = jQuery.contains( elem.ownerDocument, elem );
6639
+
6640
+ // Append to fragment
6641
+ tmp = getAll( safe.appendChild( elem ), "script" );
6642
+
6643
+ // Preserve script evaluation history
6644
+ if ( contains ) {
6645
+ setGlobalEval( tmp );
6646
+ }
6647
+
6648
+ // Capture executables
6649
+ if ( scripts ) {
6650
+ j = 0;
6651
+ while ( (elem = tmp[ j++ ]) ) {
6652
+ if ( rscriptType.test( elem.type || "" ) ) {
6653
+ scripts.push( elem );
6654
+ }
6655
+ }
6656
+ }
6657
+ }
6658
+
6659
+ tmp = null;
6660
+
6661
+ return safe;
6662
+ },
6663
+
6664
+ cleanData: function( elems, /* internal */ acceptData ) {
6665
+ var elem, type, id, data,
6666
+ i = 0,
6667
+ internalKey = jQuery.expando,
6668
+ cache = jQuery.cache,
6669
+ deleteExpando = jQuery.support.deleteExpando,
6670
+ special = jQuery.event.special;
6671
+
6672
+ for ( ; (elem = elems[i]) != null; i++ ) {
6673
+
6674
+ if ( acceptData || jQuery.acceptData( elem ) ) {
6675
+
6676
+ id = elem[ internalKey ];
6677
+ data = id && cache[ id ];
6678
+
6679
+ if ( data ) {
6680
+ if ( data.events ) {
6681
+ for ( type in data.events ) {
6682
+ if ( special[ type ] ) {
6683
+ jQuery.event.remove( elem, type );
6684
+
6685
+ // This is a shortcut to avoid jQuery.event.remove's overhead
6686
+ } else {
6687
+ jQuery.removeEvent( elem, type, data.handle );
6688
+ }
6689
+ }
6690
+ }
6691
+
6692
+ // Remove cache only if it was not already removed by jQuery.event.remove
6693
+ if ( cache[ id ] ) {
6694
+
6695
+ delete cache[ id ];
6696
+
6697
+ // IE does not allow us to delete expando properties from nodes,
6698
+ // nor does it have a removeAttribute function on Document nodes;
6699
+ // we must handle all of these cases
6700
+ if ( deleteExpando ) {
6701
+ delete elem[ internalKey ];
6702
+
6703
+ } else if ( typeof elem.removeAttribute !== core_strundefined ) {
6704
+ elem.removeAttribute( internalKey );
6705
+
6706
+ } else {
6707
+ elem[ internalKey ] = null;
6708
+ }
6709
+
6710
+ core_deletedIds.push( id );
6711
+ }
6712
+ }
6713
+ }
6714
+ }
6715
+ },
6716
+
6717
+ _evalUrl: function( url ) {
6718
+ return jQuery.ajax({
6719
+ url: url,
6720
+ type: "GET",
6721
+ dataType: "script",
6722
+ async: false,
6723
+ global: false,
6724
+ "throws": true
6725
+ });
6726
+ }
6727
+ });
6728
+ jQuery.fn.extend({
6729
+ wrapAll: function( html ) {
6730
+ if ( jQuery.isFunction( html ) ) {
6731
+ return this.each(function(i) {
6732
+ jQuery(this).wrapAll( html.call(this, i) );
6733
+ });
6734
+ }
6735
+
6736
+ if ( this[0] ) {
6737
+ // The elements to wrap the target around
6738
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
6739
+
6740
+ if ( this[0].parentNode ) {
6741
+ wrap.insertBefore( this[0] );
6742
+ }
6743
+
6744
+ wrap.map(function() {
6745
+ var elem = this;
6746
+
6747
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
6748
+ elem = elem.firstChild;
6749
+ }
6750
+
6751
+ return elem;
6752
+ }).append( this );
6753
+ }
6754
+
6755
+ return this;
6756
+ },
6757
+
6758
+ wrapInner: function( html ) {
6759
+ if ( jQuery.isFunction( html ) ) {
6760
+ return this.each(function(i) {
6761
+ jQuery(this).wrapInner( html.call(this, i) );
6762
+ });
6763
+ }
6764
+
6765
+ return this.each(function() {
6766
+ var self = jQuery( this ),
6767
+ contents = self.contents();
6768
+
6769
+ if ( contents.length ) {
6770
+ contents.wrapAll( html );
6771
+
6772
+ } else {
6773
+ self.append( html );
6774
+ }
6775
+ });
6776
+ },
6777
+
6778
+ wrap: function( html ) {
6779
+ var isFunction = jQuery.isFunction( html );
6780
+
6781
+ return this.each(function(i) {
6782
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
6783
+ });
6784
+ },
6785
+
6786
+ unwrap: function() {
6787
+ return this.parent().each(function() {
6788
+ if ( !jQuery.nodeName( this, "body" ) ) {
6789
+ jQuery( this ).replaceWith( this.childNodes );
6790
+ }
6791
+ }).end();
6792
+ }
6793
+ });
6794
+ var iframe, getStyles, curCSS,
6795
+ ralpha = /alpha\([^)]*\)/i,
6796
+ ropacity = /opacity\s*=\s*([^)]*)/,
6797
+ rposition = /^(top|right|bottom|left)$/,
6798
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
6799
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6800
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6801
+ rmargin = /^margin/,
6802
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
6803
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
6804
+ rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
6805
+ elemdisplay = { BODY: "block" },
6806
+
6807
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6808
+ cssNormalTransform = {
6809
+ letterSpacing: 0,
6810
+ fontWeight: 400
6811
+ },
6812
+
6813
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
6814
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
6815
+
6816
+ // return a css property mapped to a potentially vendor prefixed property
6817
+ function vendorPropName( style, name ) {
6818
+
6819
+ // shortcut for names that are not vendor prefixed
6820
+ if ( name in style ) {
6821
+ return name;
6822
+ }
6823
+
6824
+ // check for vendor prefixed names
6825
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
6826
+ origName = name,
6827
+ i = cssPrefixes.length;
6828
+
6829
+ while ( i-- ) {
6830
+ name = cssPrefixes[ i ] + capName;
6831
+ if ( name in style ) {
6832
+ return name;
6833
+ }
6834
+ }
6835
+
6836
+ return origName;
6837
+ }
6838
+
6839
+ function isHidden( elem, el ) {
6840
+ // isHidden might be called from jQuery#filter function;
6841
+ // in that case, element will be second argument
6842
+ elem = el || elem;
6843
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
6844
+ }
6845
+
6846
+ function showHide( elements, show ) {
6847
+ var display, elem, hidden,
6848
+ values = [],
6849
+ index = 0,
6850
+ length = elements.length;
6851
+
6852
+ for ( ; index < length; index++ ) {
6853
+ elem = elements[ index ];
6854
+ if ( !elem.style ) {
6855
+ continue;
6856
+ }
6857
+
6858
+ values[ index ] = jQuery._data( elem, "olddisplay" );
6859
+ display = elem.style.display;
6860
+ if ( show ) {
6861
+ // Reset the inline display of this element to learn if it is
6862
+ // being hidden by cascaded rules or not
6863
+ if ( !values[ index ] && display === "none" ) {
6864
+ elem.style.display = "";
6865
+ }
6866
+
6867
+ // Set elements which have been overridden with display: none
6868
+ // in a stylesheet to whatever the default browser style is
6869
+ // for such an element
6870
+ if ( elem.style.display === "" && isHidden( elem ) ) {
6871
+ values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
6872
+ }
6873
+ } else {
6874
+
6875
+ if ( !values[ index ] ) {
6876
+ hidden = isHidden( elem );
6877
+
6878
+ if ( display && display !== "none" || !hidden ) {
6879
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
6880
+ }
6881
+ }
6882
+ }
6883
+ }
6884
+
6885
+ // Set the display of most of the elements in a second loop
6886
+ // to avoid the constant reflow
6887
+ for ( index = 0; index < length; index++ ) {
6888
+ elem = elements[ index ];
6889
+ if ( !elem.style ) {
6890
+ continue;
6891
+ }
6892
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6893
+ elem.style.display = show ? values[ index ] || "" : "none";
6894
+ }
6895
+ }
6896
+
6897
+ return elements;
6898
+ }
6899
+
6900
+ jQuery.fn.extend({
6901
+ css: function( name, value ) {
6902
+ return jQuery.access( this, function( elem, name, value ) {
6903
+ var len, styles,
6904
+ map = {},
6905
+ i = 0;
6906
+
6907
+ if ( jQuery.isArray( name ) ) {
6908
+ styles = getStyles( elem );
6909
+ len = name.length;
6910
+
6911
+ for ( ; i < len; i++ ) {
6912
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6913
+ }
6914
+
6915
+ return map;
6916
+ }
6917
+
6918
+ return value !== undefined ?
6919
+ jQuery.style( elem, name, value ) :
6920
+ jQuery.css( elem, name );
6921
+ }, name, value, arguments.length > 1 );
6922
+ },
6923
+ show: function() {
6924
+ return showHide( this, true );
6925
+ },
6926
+ hide: function() {
6927
+ return showHide( this );
6928
+ },
6929
+ toggle: function( state ) {
6930
+ if ( typeof state === "boolean" ) {
6931
+ return state ? this.show() : this.hide();
6932
+ }
6933
+
6934
+ return this.each(function() {
6935
+ if ( isHidden( this ) ) {
6936
+ jQuery( this ).show();
6937
+ } else {
6938
+ jQuery( this ).hide();
6939
+ }
6940
+ });
6941
+ }
6942
+ });
6943
+
6944
+ jQuery.extend({
6945
+ // Add in style property hooks for overriding the default
6946
+ // behavior of getting and setting a style property
6947
+ cssHooks: {
6948
+ opacity: {
6949
+ get: function( elem, computed ) {
6950
+ if ( computed ) {
6951
+ // We should always get a number back from opacity
6952
+ var ret = curCSS( elem, "opacity" );
6953
+ return ret === "" ? "1" : ret;
6954
+ }
6955
+ }
6956
+ }
6957
+ },
6958
+
6959
+ // Don't automatically add "px" to these possibly-unitless properties
6960
+ cssNumber: {
6961
+ "columnCount": true,
6962
+ "fillOpacity": true,
6963
+ "fontWeight": true,
6964
+ "lineHeight": true,
6965
+ "opacity": true,
6966
+ "order": true,
6967
+ "orphans": true,
6968
+ "widows": true,
6969
+ "zIndex": true,
6970
+ "zoom": true
6971
+ },
6972
+
6973
+ // Add in properties whose names you wish to fix before
6974
+ // setting or getting the value
6975
+ cssProps: {
6976
+ // normalize float css property
6977
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
6978
+ },
6979
+
6980
+ // Get and set the style property on a DOM Node
6981
+ style: function( elem, name, value, extra ) {
6982
+ // Don't set styles on text and comment nodes
6983
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6984
+ return;
6985
+ }
6986
+
6987
+ // Make sure that we're working with the right name
6988
+ var ret, type, hooks,
6989
+ origName = jQuery.camelCase( name ),
6990
+ style = elem.style;
6991
+
6992
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
6993
+
6994
+ // gets hook for the prefixed version
6995
+ // followed by the unprefixed version
6996
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6997
+
6998
+ // Check if we're setting a value
6999
+ if ( value !== undefined ) {
7000
+ type = typeof value;
7001
+
7002
+ // convert relative number strings (+= or -=) to relative numbers. #7345
7003
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
7004
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
7005
+ // Fixes bug #9237
7006
+ type = "number";
7007
+ }
7008
+
7009
+ // Make sure that NaN and null values aren't set. See: #7116
7010
+ if ( value == null || type === "number" && isNaN( value ) ) {
7011
+ return;
7012
+ }
7013
+
7014
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
7015
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
7016
+ value += "px";
7017
+ }
7018
+
7019
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
7020
+ // but it would mean to define eight (for every problematic property) identical functions
7021
+ if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
7022
+ style[ name ] = "inherit";
7023
+ }
7024
+
7025
+ // If a hook was provided, use that value, otherwise just set the specified value
7026
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
7027
+
7028
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
7029
+ // Fixes bug #5509
7030
+ try {
7031
+ style[ name ] = value;
7032
+ } catch(e) {}
7033
+ }
7034
+
7035
+ } else {
7036
+ // If a hook was provided get the non-computed value from there
7037
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
7038
+ return ret;
7039
+ }
7040
+
7041
+ // Otherwise just get the value from the style object
7042
+ return style[ name ];
7043
+ }
7044
+ },
7045
+
7046
+ css: function( elem, name, extra, styles ) {
7047
+ var num, val, hooks,
7048
+ origName = jQuery.camelCase( name );
7049
+
7050
+ // Make sure that we're working with the right name
7051
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
7052
+
7053
+ // gets hook for the prefixed version
7054
+ // followed by the unprefixed version
7055
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
7056
+
7057
+ // If a hook was provided get the computed value from there
7058
+ if ( hooks && "get" in hooks ) {
7059
+ val = hooks.get( elem, true, extra );
7060
+ }
7061
+
7062
+ // Otherwise, if a way to get the computed value exists, use that
7063
+ if ( val === undefined ) {
7064
+ val = curCSS( elem, name, styles );
7065
+ }
7066
+
7067
+ //convert "normal" to computed value
7068
+ if ( val === "normal" && name in cssNormalTransform ) {
7069
+ val = cssNormalTransform[ name ];
7070
+ }
7071
+
7072
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
7073
+ if ( extra === "" || extra ) {
7074
+ num = parseFloat( val );
7075
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
7076
+ }
7077
+ return val;
7078
+ }
7079
+ });
7080
+
7081
+ // NOTE: we've included the "window" in window.getComputedStyle
7082
+ // because jsdom on node.js will break without it.
7083
+ if ( window.getComputedStyle ) {
7084
+ getStyles = function( elem ) {
7085
+ return window.getComputedStyle( elem, null );
7086
+ };
7087
+
7088
+ curCSS = function( elem, name, _computed ) {
7089
+ var width, minWidth, maxWidth,
7090
+ computed = _computed || getStyles( elem ),
7091
+
7092
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
7093
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
7094
+ style = elem.style;
7095
+
7096
+ if ( computed ) {
7097
+
7098
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
7099
+ ret = jQuery.style( elem, name );
7100
+ }
7101
+
7102
+ // A tribute to the "awesome hack by Dean Edwards"
7103
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
7104
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
7105
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
7106
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
7107
+
7108
+ // Remember the original values
7109
+ width = style.width;
7110
+ minWidth = style.minWidth;
7111
+ maxWidth = style.maxWidth;
7112
+
7113
+ // Put in the new values to get a computed value out
7114
+ style.minWidth = style.maxWidth = style.width = ret;
7115
+ ret = computed.width;
7116
+
7117
+ // Revert the changed values
7118
+ style.width = width;
7119
+ style.minWidth = minWidth;
7120
+ style.maxWidth = maxWidth;
7121
+ }
7122
+ }
7123
+
7124
+ return ret;
7125
+ };
7126
+ } else if ( document.documentElement.currentStyle ) {
7127
+ getStyles = function( elem ) {
7128
+ return elem.currentStyle;
7129
+ };
7130
+
7131
+ curCSS = function( elem, name, _computed ) {
7132
+ var left, rs, rsLeft,
7133
+ computed = _computed || getStyles( elem ),
7134
+ ret = computed ? computed[ name ] : undefined,
7135
+ style = elem.style;
7136
+
7137
+ // Avoid setting ret to empty string here
7138
+ // so we don't default to auto
7139
+ if ( ret == null && style && style[ name ] ) {
7140
+ ret = style[ name ];
7141
+ }
7142
+
7143
+ // From the awesome hack by Dean Edwards
7144
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
7145
+
7146
+ // If we're not dealing with a regular pixel number
7147
+ // but a number that has a weird ending, we need to convert it to pixels
7148
+ // but not position css attributes, as those are proportional to the parent element instead
7149
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
7150
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
7151
+
7152
+ // Remember the original values
7153
+ left = style.left;
7154
+ rs = elem.runtimeStyle;
7155
+ rsLeft = rs && rs.left;
7156
+
7157
+ // Put in the new values to get a computed value out
7158
+ if ( rsLeft ) {
7159
+ rs.left = elem.currentStyle.left;
7160
+ }
7161
+ style.left = name === "fontSize" ? "1em" : ret;
7162
+ ret = style.pixelLeft + "px";
7163
+
7164
+ // Revert the changed values
7165
+ style.left = left;
7166
+ if ( rsLeft ) {
7167
+ rs.left = rsLeft;
7168
+ }
7169
+ }
7170
+
7171
+ return ret === "" ? "auto" : ret;
7172
+ };
7173
+ }
7174
+
7175
+ function setPositiveNumber( elem, value, subtract ) {
7176
+ var matches = rnumsplit.exec( value );
7177
+ return matches ?
7178
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
7179
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
7180
+ value;
7181
+ }
7182
+
7183
+ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
7184
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
7185
+ // If we already have the right measurement, avoid augmentation
7186
+ 4 :
7187
+ // Otherwise initialize for horizontal or vertical properties
7188
+ name === "width" ? 1 : 0,
7189
+
7190
+ val = 0;
7191
+
7192
+ for ( ; i < 4; i += 2 ) {
7193
+ // both box models exclude margin, so add it if we want it
7194
+ if ( extra === "margin" ) {
7195
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
7196
+ }
7197
+
7198
+ if ( isBorderBox ) {
7199
+ // border-box includes padding, so remove it if we want content
7200
+ if ( extra === "content" ) {
7201
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7202
+ }
7203
+
7204
+ // at this point, extra isn't border nor margin, so remove border
7205
+ if ( extra !== "margin" ) {
7206
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7207
+ }
7208
+ } else {
7209
+ // at this point, extra isn't content, so add padding
7210
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7211
+
7212
+ // at this point, extra isn't content nor padding, so add border
7213
+ if ( extra !== "padding" ) {
7214
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7215
+ }
7216
+ }
7217
+ }
7218
+
7219
+ return val;
7220
+ }
7221
+
7222
+ function getWidthOrHeight( elem, name, extra ) {
7223
+
7224
+ // Start with offset property, which is equivalent to the border-box value
7225
+ var valueIsBorderBox = true,
7226
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
7227
+ styles = getStyles( elem ),
7228
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
7229
+
7230
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
7231
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
7232
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
7233
+ if ( val <= 0 || val == null ) {
7234
+ // Fall back to computed then uncomputed css if necessary
7235
+ val = curCSS( elem, name, styles );
7236
+ if ( val < 0 || val == null ) {
7237
+ val = elem.style[ name ];
7238
+ }
7239
+
7240
+ // Computed unit is not pixels. Stop here and return.
7241
+ if ( rnumnonpx.test(val) ) {
7242
+ return val;
7243
+ }
7244
+
7245
+ // we need the check for style in case a browser which returns unreliable values
7246
+ // for getComputedStyle silently falls back to the reliable elem.style
7247
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
7248
+
7249
+ // Normalize "", auto, and prepare for extra
7250
+ val = parseFloat( val ) || 0;
7251
+ }
7252
+
7253
+ // use the active box-sizing model to add/subtract irrelevant styles
7254
+ return ( val +
7255
+ augmentWidthOrHeight(
7256
+ elem,
7257
+ name,
7258
+ extra || ( isBorderBox ? "border" : "content" ),
7259
+ valueIsBorderBox,
7260
+ styles
7261
+ )
7262
+ ) + "px";
7263
+ }
7264
+
7265
+ // Try to determine the default display value of an element
7266
+ function css_defaultDisplay( nodeName ) {
7267
+ var doc = document,
7268
+ display = elemdisplay[ nodeName ];
7269
+
7270
+ if ( !display ) {
7271
+ display = actualDisplay( nodeName, doc );
7272
+
7273
+ // If the simple way fails, read from inside an iframe
7274
+ if ( display === "none" || !display ) {
7275
+ // Use the already-created iframe if possible
7276
+ iframe = ( iframe ||
7277
+ jQuery("<iframe frameborder='0' width='0' height='0'/>")
7278
+ .css( "cssText", "display:block !important" )
7279
+ ).appendTo( doc.documentElement );
7280
+
7281
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
7282
+ doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
7283
+ doc.write("<!doctype html><html><body>");
7284
+ doc.close();
7285
+
7286
+ display = actualDisplay( nodeName, doc );
7287
+ iframe.detach();
7288
+ }
7289
+
7290
+ // Store the correct default display
7291
+ elemdisplay[ nodeName ] = display;
7292
+ }
7293
+
7294
+ return display;
7295
+ }
7296
+
7297
+ // Called ONLY from within css_defaultDisplay
7298
+ function actualDisplay( name, doc ) {
7299
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
7300
+ display = jQuery.css( elem[0], "display" );
7301
+ elem.remove();
7302
+ return display;
7303
+ }
7304
+
7305
+ jQuery.each([ "height", "width" ], function( i, name ) {
7306
+ jQuery.cssHooks[ name ] = {
7307
+ get: function( elem, computed, extra ) {
7308
+ if ( computed ) {
7309
+ // certain elements can have dimension info if we invisibly show them
7310
+ // however, it must have a current display style that would benefit from this
7311
+ return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
7312
+ jQuery.swap( elem, cssShow, function() {
7313
+ return getWidthOrHeight( elem, name, extra );
7314
+ }) :
7315
+ getWidthOrHeight( elem, name, extra );
7316
+ }
7317
+ },
7318
+
7319
+ set: function( elem, value, extra ) {
7320
+ var styles = extra && getStyles( elem );
7321
+ return setPositiveNumber( elem, value, extra ?
7322
+ augmentWidthOrHeight(
7323
+ elem,
7324
+ name,
7325
+ extra,
7326
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
7327
+ styles
7328
+ ) : 0
7329
+ );
7330
+ }
7331
+ };
7332
+ });
7333
+
7334
+ if ( !jQuery.support.opacity ) {
7335
+ jQuery.cssHooks.opacity = {
7336
+ get: function( elem, computed ) {
7337
+ // IE uses filters for opacity
7338
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
7339
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
7340
+ computed ? "1" : "";
7341
+ },
7342
+
7343
+ set: function( elem, value ) {
7344
+ var style = elem.style,
7345
+ currentStyle = elem.currentStyle,
7346
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
7347
+ filter = currentStyle && currentStyle.filter || style.filter || "";
7348
+
7349
+ // IE has trouble with opacity if it does not have layout
7350
+ // Force it by setting the zoom level
7351
+ style.zoom = 1;
7352
+
7353
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
7354
+ // if value === "", then remove inline opacity #12685
7355
+ if ( ( value >= 1 || value === "" ) &&
7356
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
7357
+ style.removeAttribute ) {
7358
+
7359
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
7360
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
7361
+ // style.removeAttribute is IE Only, but so apparently is this code path...
7362
+ style.removeAttribute( "filter" );
7363
+
7364
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
7365
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
7366
+ return;
7367
+ }
7368
+ }
7369
+
7370
+ // otherwise, set new filter values
7371
+ style.filter = ralpha.test( filter ) ?
7372
+ filter.replace( ralpha, opacity ) :
7373
+ filter + " " + opacity;
7374
+ }
7375
+ };
7376
+ }
7377
+
7378
+ // These hooks cannot be added until DOM ready because the support test
7379
+ // for it is not run until after DOM ready
7380
+ jQuery(function() {
7381
+ if ( !jQuery.support.reliableMarginRight ) {
7382
+ jQuery.cssHooks.marginRight = {
7383
+ get: function( elem, computed ) {
7384
+ if ( computed ) {
7385
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
7386
+ // Work around by temporarily setting element display to inline-block
7387
+ return jQuery.swap( elem, { "display": "inline-block" },
7388
+ curCSS, [ elem, "marginRight" ] );
7389
+ }
7390
+ }
7391
+ };
7392
+ }
7393
+
7394
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
7395
+ // getComputedStyle returns percent when specified for top/left/bottom/right
7396
+ // rather than make the css module depend on the offset module, we just check for it here
7397
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
7398
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
7399
+ jQuery.cssHooks[ prop ] = {
7400
+ get: function( elem, computed ) {
7401
+ if ( computed ) {
7402
+ computed = curCSS( elem, prop );
7403
+ // if curCSS returns percentage, fallback to offset
7404
+ return rnumnonpx.test( computed ) ?
7405
+ jQuery( elem ).position()[ prop ] + "px" :
7406
+ computed;
7407
+ }
7408
+ }
7409
+ };
7410
+ });
7411
+ }
7412
+
7413
+ });
7414
+
7415
+ if ( jQuery.expr && jQuery.expr.filters ) {
7416
+ jQuery.expr.filters.hidden = function( elem ) {
7417
+ // Support: Opera <= 12.12
7418
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
7419
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
7420
+ (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
7421
+ };
7422
+
7423
+ jQuery.expr.filters.visible = function( elem ) {
7424
+ return !jQuery.expr.filters.hidden( elem );
7425
+ };
7426
+ }
7427
+
7428
+ // These hooks are used by animate to expand properties
7429
+ jQuery.each({
7430
+ margin: "",
7431
+ padding: "",
7432
+ border: "Width"
7433
+ }, function( prefix, suffix ) {
7434
+ jQuery.cssHooks[ prefix + suffix ] = {
7435
+ expand: function( value ) {
7436
+ var i = 0,
7437
+ expanded = {},
7438
+
7439
+ // assumes a single number if not a string
7440
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
7441
+
7442
+ for ( ; i < 4; i++ ) {
7443
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
7444
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
7445
+ }
7446
+
7447
+ return expanded;
7448
+ }
7449
+ };
7450
+
7451
+ if ( !rmargin.test( prefix ) ) {
7452
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
7453
+ }
7454
+ });
7455
+ var r20 = /%20/g,
7456
+ rbracket = /\[\]$/,
7457
+ rCRLF = /\r?\n/g,
7458
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
7459
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
7460
+
7461
+ jQuery.fn.extend({
7462
+ serialize: function() {
7463
+ return jQuery.param( this.serializeArray() );
7464
+ },
7465
+ serializeArray: function() {
7466
+ return this.map(function(){
7467
+ // Can add propHook for "elements" to filter or add form elements
7468
+ var elements = jQuery.prop( this, "elements" );
7469
+ return elements ? jQuery.makeArray( elements ) : this;
7470
+ })
7471
+ .filter(function(){
7472
+ var type = this.type;
7473
+ // Use .is(":disabled") so that fieldset[disabled] works
7474
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
7475
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
7476
+ ( this.checked || !manipulation_rcheckableType.test( type ) );
7477
+ })
7478
+ .map(function( i, elem ){
7479
+ var val = jQuery( this ).val();
7480
+
7481
+ return val == null ?
7482
+ null :
7483
+ jQuery.isArray( val ) ?
7484
+ jQuery.map( val, function( val ){
7485
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7486
+ }) :
7487
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7488
+ }).get();
7489
+ }
7490
+ });
7491
+
7492
+ //Serialize an array of form elements or a set of
7493
+ //key/values into a query string
7494
+ jQuery.param = function( a, traditional ) {
7495
+ var prefix,
7496
+ s = [],
7497
+ add = function( key, value ) {
7498
+ // If value is a function, invoke it and return its value
7499
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
7500
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
7501
+ };
7502
+
7503
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
7504
+ if ( traditional === undefined ) {
7505
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
7506
+ }
7507
+
7508
+ // If an array was passed in, assume that it is an array of form elements.
7509
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
7510
+ // Serialize the form elements
7511
+ jQuery.each( a, function() {
7512
+ add( this.name, this.value );
7513
+ });
7514
+
7515
+ } else {
7516
+ // If traditional, encode the "old" way (the way 1.3.2 or older
7517
+ // did it), otherwise encode params recursively.
7518
+ for ( prefix in a ) {
7519
+ buildParams( prefix, a[ prefix ], traditional, add );
7520
+ }
7521
+ }
7522
+
7523
+ // Return the resulting serialization
7524
+ return s.join( "&" ).replace( r20, "+" );
7525
+ };
7526
+
7527
+ function buildParams( prefix, obj, traditional, add ) {
7528
+ var name;
7529
+
7530
+ if ( jQuery.isArray( obj ) ) {
7531
+ // Serialize array item.
7532
+ jQuery.each( obj, function( i, v ) {
7533
+ if ( traditional || rbracket.test( prefix ) ) {
7534
+ // Treat each array item as a scalar.
7535
+ add( prefix, v );
7536
+
7537
+ } else {
7538
+ // Item is non-scalar (array or object), encode its numeric index.
7539
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
7540
+ }
7541
+ });
7542
+
7543
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
7544
+ // Serialize object item.
7545
+ for ( name in obj ) {
7546
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
7547
+ }
7548
+
7549
+ } else {
7550
+ // Serialize scalar item.
7551
+ add( prefix, obj );
7552
+ }
7553
+ }
7554
+ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
7555
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
7556
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
7557
+
7558
+ // Handle event binding
7559
+ jQuery.fn[ name ] = function( data, fn ) {
7560
+ return arguments.length > 0 ?
7561
+ this.on( name, null, data, fn ) :
7562
+ this.trigger( name );
7563
+ };
7564
+ });
7565
+
7566
+ jQuery.fn.extend({
7567
+ hover: function( fnOver, fnOut ) {
7568
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
7569
+ },
7570
+
7571
+ bind: function( types, data, fn ) {
7572
+ return this.on( types, null, data, fn );
7573
+ },
7574
+ unbind: function( types, fn ) {
7575
+ return this.off( types, null, fn );
7576
+ },
7577
+
7578
+ delegate: function( selector, types, data, fn ) {
7579
+ return this.on( types, selector, data, fn );
7580
+ },
7581
+ undelegate: function( selector, types, fn ) {
7582
+ // ( namespace ) or ( selector, types [, fn] )
7583
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
7584
+ }
7585
+ });
7586
+ var
7587
+ // Document location
7588
+ ajaxLocParts,
7589
+ ajaxLocation,
7590
+ ajax_nonce = jQuery.now(),
7591
+
7592
+ ajax_rquery = /\?/,
7593
+ rhash = /#.*$/,
7594
+ rts = /([?&])_=[^&]*/,
7595
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
7596
+ // #7653, #8125, #8152: local protocol detection
7597
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
7598
+ rnoContent = /^(?:GET|HEAD)$/,
7599
+ rprotocol = /^\/\//,
7600
+ rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
7601
+
7602
+ // Keep a copy of the old load method
7603
+ _load = jQuery.fn.load,
7604
+
7605
+ /* Prefilters
7606
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7607
+ * 2) These are called:
7608
+ * - BEFORE asking for a transport
7609
+ * - AFTER param serialization (s.data is a string if s.processData is true)
7610
+ * 3) key is the dataType
7611
+ * 4) the catchall symbol "*" can be used
7612
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7613
+ */
7614
+ prefilters = {},
7615
+
7616
+ /* Transports bindings
7617
+ * 1) key is the dataType
7618
+ * 2) the catchall symbol "*" can be used
7619
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
7620
+ */
7621
+ transports = {},
7622
+
7623
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7624
+ allTypes = "*/".concat("*");
7625
+
7626
+ // #8138, IE may throw an exception when accessing
7627
+ // a field from window.location if document.domain has been set
7628
+ try {
7629
+ ajaxLocation = location.href;
7630
+ } catch( e ) {
7631
+ // Use the href attribute of an A element
7632
+ // since IE will modify it given document.location
7633
+ ajaxLocation = document.createElement( "a" );
7634
+ ajaxLocation.href = "";
7635
+ ajaxLocation = ajaxLocation.href;
7636
+ }
7637
+
7638
+ // Segment location into parts
7639
+ ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7640
+
7641
+ // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7642
+ function addToPrefiltersOrTransports( structure ) {
7643
+
7644
+ // dataTypeExpression is optional and defaults to "*"
7645
+ return function( dataTypeExpression, func ) {
7646
+
7647
+ if ( typeof dataTypeExpression !== "string" ) {
7648
+ func = dataTypeExpression;
7649
+ dataTypeExpression = "*";
7650
+ }
7651
+
7652
+ var dataType,
7653
+ i = 0,
7654
+ dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
7655
+
7656
+ if ( jQuery.isFunction( func ) ) {
7657
+ // For each dataType in the dataTypeExpression
7658
+ while ( (dataType = dataTypes[i++]) ) {
7659
+ // Prepend if requested
7660
+ if ( dataType[0] === "+" ) {
7661
+ dataType = dataType.slice( 1 ) || "*";
7662
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
7663
+
7664
+ // Otherwise append
7665
+ } else {
7666
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
7667
+ }
7668
+ }
7669
+ }
7670
+ };
7671
+ }
7672
+
7673
+ // Base inspection function for prefilters and transports
7674
+ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
7675
+
7676
+ var inspected = {},
7677
+ seekingTransport = ( structure === transports );
7678
+
7679
+ function inspect( dataType ) {
7680
+ var selected;
7681
+ inspected[ dataType ] = true;
7682
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
7683
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
7684
+ if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
7685
+ options.dataTypes.unshift( dataTypeOrTransport );
7686
+ inspect( dataTypeOrTransport );
7687
+ return false;
7688
+ } else if ( seekingTransport ) {
7689
+ return !( selected = dataTypeOrTransport );
7690
+ }
7691
+ });
7692
+ return selected;
7693
+ }
7694
+
7695
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
7696
+ }
7697
+
7698
+ // A special extend for ajax options
7699
+ // that takes "flat" options (not to be deep extended)
7700
+ // Fixes #9887
7701
+ function ajaxExtend( target, src ) {
7702
+ var deep, key,
7703
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
7704
+
7705
+ for ( key in src ) {
7706
+ if ( src[ key ] !== undefined ) {
7707
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
7708
+ }
7709
+ }
7710
+ if ( deep ) {
7711
+ jQuery.extend( true, target, deep );
7712
+ }
7713
+
7714
+ return target;
7715
+ }
7716
+
7717
+ jQuery.fn.load = function( url, params, callback ) {
7718
+ if ( typeof url !== "string" && _load ) {
7719
+ return _load.apply( this, arguments );
7720
+ }
7721
+
7722
+ var selector, response, type,
7723
+ self = this,
7724
+ off = url.indexOf(" ");
7725
+
7726
+ if ( off >= 0 ) {
7727
+ selector = url.slice( off, url.length );
7728
+ url = url.slice( 0, off );
7729
+ }
7730
+
7731
+ // If it's a function
7732
+ if ( jQuery.isFunction( params ) ) {
7733
+
7734
+ // We assume that it's the callback
7735
+ callback = params;
7736
+ params = undefined;
7737
+
7738
+ // Otherwise, build a param string
7739
+ } else if ( params && typeof params === "object" ) {
7740
+ type = "POST";
7741
+ }
7742
+
7743
+ // If we have elements to modify, make the request
7744
+ if ( self.length > 0 ) {
7745
+ jQuery.ajax({
7746
+ url: url,
7747
+
7748
+ // if "type" variable is undefined, then "GET" method will be used
7749
+ type: type,
7750
+ dataType: "html",
7751
+ data: params
7752
+ }).done(function( responseText ) {
7753
+
7754
+ // Save response for use in complete callback
7755
+ response = arguments;
7756
+
7757
+ self.html( selector ?
7758
+
7759
+ // If a selector was specified, locate the right elements in a dummy div
7760
+ // Exclude scripts to avoid IE 'Permission Denied' errors
7761
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
7762
+
7763
+ // Otherwise use the full result
7764
+ responseText );
7765
+
7766
+ }).complete( callback && function( jqXHR, status ) {
7767
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
7768
+ });
7769
+ }
7770
+
7771
+ return this;
7772
+ };
7773
+
7774
+ // Attach a bunch of functions for handling common AJAX events
7775
+ jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
7776
+ jQuery.fn[ type ] = function( fn ){
7777
+ return this.on( type, fn );
7778
+ };
7779
+ });
7780
+
7781
+ jQuery.extend({
7782
+
7783
+ // Counter for holding the number of active queries
7784
+ active: 0,
7785
+
7786
+ // Last-Modified header cache for next request
7787
+ lastModified: {},
7788
+ etag: {},
7789
+
7790
+ ajaxSettings: {
7791
+ url: ajaxLocation,
7792
+ type: "GET",
7793
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7794
+ global: true,
7795
+ processData: true,
7796
+ async: true,
7797
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
7798
+ /*
7799
+ timeout: 0,
7800
+ data: null,
7801
+ dataType: null,
7802
+ username: null,
7803
+ password: null,
7804
+ cache: null,
7805
+ throws: false,
7806
+ traditional: false,
7807
+ headers: {},
7808
+ */
7809
+
7810
+ accepts: {
7811
+ "*": allTypes,
7812
+ text: "text/plain",
7813
+ html: "text/html",
7814
+ xml: "application/xml, text/xml",
7815
+ json: "application/json, text/javascript"
7816
+ },
7817
+
7818
+ contents: {
7819
+ xml: /xml/,
7820
+ html: /html/,
7821
+ json: /json/
7822
+ },
7823
+
7824
+ responseFields: {
7825
+ xml: "responseXML",
7826
+ text: "responseText",
7827
+ json: "responseJSON"
7828
+ },
7829
+
7830
+ // Data converters
7831
+ // Keys separate source (or catchall "*") and destination types with a single space
7832
+ converters: {
7833
+
7834
+ // Convert anything to text
7835
+ "* text": String,
7836
+
7837
+ // Text to html (true = no transformation)
7838
+ "text html": true,
7839
+
7840
+ // Evaluate text as a json expression
7841
+ "text json": jQuery.parseJSON,
7842
+
7843
+ // Parse text as xml
7844
+ "text xml": jQuery.parseXML
7845
+ },
7846
+
7847
+ // For options that shouldn't be deep extended:
7848
+ // you can add your own custom options here if
7849
+ // and when you create one that shouldn't be
7850
+ // deep extended (see ajaxExtend)
7851
+ flatOptions: {
7852
+ url: true,
7853
+ context: true
7854
+ }
7855
+ },
7856
+
7857
+ // Creates a full fledged settings object into target
7858
+ // with both ajaxSettings and settings fields.
7859
+ // If target is omitted, writes into ajaxSettings.
7860
+ ajaxSetup: function( target, settings ) {
7861
+ return settings ?
7862
+
7863
+ // Building a settings object
7864
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7865
+
7866
+ // Extending ajaxSettings
7867
+ ajaxExtend( jQuery.ajaxSettings, target );
7868
+ },
7869
+
7870
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7871
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
7872
+
7873
+ // Main method
7874
+ ajax: function( url, options ) {
7875
+
7876
+ // If url is an object, simulate pre-1.5 signature
7877
+ if ( typeof url === "object" ) {
7878
+ options = url;
7879
+ url = undefined;
7880
+ }
7881
+
7882
+ // Force options to be an object
7883
+ options = options || {};
7884
+
7885
+ var // Cross-domain detection vars
7886
+ parts,
7887
+ // Loop variable
7888
+ i,
7889
+ // URL without anti-cache param
7890
+ cacheURL,
7891
+ // Response headers as string
7892
+ responseHeadersString,
7893
+ // timeout handle
7894
+ timeoutTimer,
7895
+
7896
+ // To know if global events are to be dispatched
7897
+ fireGlobals,
7898
+
7899
+ transport,
7900
+ // Response headers
7901
+ responseHeaders,
7902
+ // Create the final options object
7903
+ s = jQuery.ajaxSetup( {}, options ),
7904
+ // Callbacks context
7905
+ callbackContext = s.context || s,
7906
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
7907
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7908
+ jQuery( callbackContext ) :
7909
+ jQuery.event,
7910
+ // Deferreds
7911
+ deferred = jQuery.Deferred(),
7912
+ completeDeferred = jQuery.Callbacks("once memory"),
7913
+ // Status-dependent callbacks
7914
+ statusCode = s.statusCode || {},
7915
+ // Headers (they are sent all at once)
7916
+ requestHeaders = {},
7917
+ requestHeadersNames = {},
7918
+ // The jqXHR state
7919
+ state = 0,
7920
+ // Default abort message
7921
+ strAbort = "canceled",
7922
+ // Fake xhr
7923
+ jqXHR = {
7924
+ readyState: 0,
7925
+
7926
+ // Builds headers hashtable if needed
7927
+ getResponseHeader: function( key ) {
7928
+ var match;
7929
+ if ( state === 2 ) {
7930
+ if ( !responseHeaders ) {
7931
+ responseHeaders = {};
7932
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
7933
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7934
+ }
7935
+ }
7936
+ match = responseHeaders[ key.toLowerCase() ];
7937
+ }
7938
+ return match == null ? null : match;
7939
+ },
7940
+
7941
+ // Raw string
7942
+ getAllResponseHeaders: function() {
7943
+ return state === 2 ? responseHeadersString : null;
7944
+ },
7945
+
7946
+ // Caches the header
7947
+ setRequestHeader: function( name, value ) {
7948
+ var lname = name.toLowerCase();
7949
+ if ( !state ) {
7950
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7951
+ requestHeaders[ name ] = value;
7952
+ }
7953
+ return this;
7954
+ },
7955
+
7956
+ // Overrides response content-type header
7957
+ overrideMimeType: function( type ) {
7958
+ if ( !state ) {
7959
+ s.mimeType = type;
7960
+ }
7961
+ return this;
7962
+ },
7963
+
7964
+ // Status-dependent callbacks
7965
+ statusCode: function( map ) {
7966
+ var code;
7967
+ if ( map ) {
7968
+ if ( state < 2 ) {
7969
+ for ( code in map ) {
7970
+ // Lazy-add the new callback in a way that preserves old ones
7971
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7972
+ }
7973
+ } else {
7974
+ // Execute the appropriate callbacks
7975
+ jqXHR.always( map[ jqXHR.status ] );
7976
+ }
7977
+ }
7978
+ return this;
7979
+ },
7980
+
7981
+ // Cancel the request
7982
+ abort: function( statusText ) {
7983
+ var finalText = statusText || strAbort;
7984
+ if ( transport ) {
7985
+ transport.abort( finalText );
7986
+ }
7987
+ done( 0, finalText );
7988
+ return this;
7989
+ }
7990
+ };
7991
+
7992
+ // Attach deferreds
7993
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
7994
+ jqXHR.success = jqXHR.done;
7995
+ jqXHR.error = jqXHR.fail;
7996
+
7997
+ // Remove hash character (#7531: and string promotion)
7998
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
7999
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
8000
+ // We also use the url parameter if available
8001
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
8002
+
8003
+ // Alias method option to type as per ticket #12004
8004
+ s.type = options.method || options.type || s.method || s.type;
8005
+
8006
+ // Extract dataTypes list
8007
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
8008
+
8009
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
8010
+ if ( s.crossDomain == null ) {
8011
+ parts = rurl.exec( s.url.toLowerCase() );
8012
+ s.crossDomain = !!( parts &&
8013
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
8014
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
8015
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
8016
+ );
8017
+ }
8018
+
8019
+ // Convert data if not already a string
8020
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
8021
+ s.data = jQuery.param( s.data, s.traditional );
8022
+ }
8023
+
8024
+ // Apply prefilters
8025
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
8026
+
8027
+ // If request was aborted inside a prefilter, stop there
8028
+ if ( state === 2 ) {
8029
+ return jqXHR;
8030
+ }
8031
+
8032
+ // We can fire global events as of now if asked to
8033
+ fireGlobals = s.global;
8034
+
8035
+ // Watch for a new set of requests
8036
+ if ( fireGlobals && jQuery.active++ === 0 ) {
8037
+ jQuery.event.trigger("ajaxStart");
8038
+ }
8039
+
8040
+ // Uppercase the type
8041
+ s.type = s.type.toUpperCase();
8042
+
8043
+ // Determine if request has content
8044
+ s.hasContent = !rnoContent.test( s.type );
8045
+
8046
+ // Save the URL in case we're toying with the If-Modified-Since
8047
+ // and/or If-None-Match header later on
8048
+ cacheURL = s.url;
8049
+
8050
+ // More options handling for requests with no content
8051
+ if ( !s.hasContent ) {
8052
+
8053
+ // If data is available, append data to url
8054
+ if ( s.data ) {
8055
+ cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
8056
+ // #9682: remove data so that it's not used in an eventual retry
8057
+ delete s.data;
8058
+ }
8059
+
8060
+ // Add anti-cache in url if needed
8061
+ if ( s.cache === false ) {
8062
+ s.url = rts.test( cacheURL ) ?
8063
+
8064
+ // If there is already a '_' parameter, set its value
8065
+ cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
8066
+
8067
+ // Otherwise add one to the end
8068
+ cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
8069
+ }
8070
+ }
8071
+
8072
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8073
+ if ( s.ifModified ) {
8074
+ if ( jQuery.lastModified[ cacheURL ] ) {
8075
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
8076
+ }
8077
+ if ( jQuery.etag[ cacheURL ] ) {
8078
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
8079
+ }
8080
+ }
8081
+
8082
+ // Set the correct header, if data is being sent
8083
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
8084
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
8085
+ }
8086
+
8087
+ // Set the Accepts header for the server, depending on the dataType
8088
+ jqXHR.setRequestHeader(
8089
+ "Accept",
8090
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
8091
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
8092
+ s.accepts[ "*" ]
8093
+ );
8094
+
8095
+ // Check for headers option
8096
+ for ( i in s.headers ) {
8097
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
8098
+ }
8099
+
8100
+ // Allow custom headers/mimetypes and early abort
8101
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
8102
+ // Abort if not done already and return
8103
+ return jqXHR.abort();
8104
+ }
8105
+
8106
+ // aborting is no longer a cancellation
8107
+ strAbort = "abort";
8108
+
8109
+ // Install callbacks on deferreds
8110
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
8111
+ jqXHR[ i ]( s[ i ] );
8112
+ }
8113
+
8114
+ // Get transport
8115
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
8116
+
8117
+ // If no transport, we auto-abort
8118
+ if ( !transport ) {
8119
+ done( -1, "No Transport" );
8120
+ } else {
8121
+ jqXHR.readyState = 1;
8122
+
8123
+ // Send global event
8124
+ if ( fireGlobals ) {
8125
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
8126
+ }
8127
+ // Timeout
8128
+ if ( s.async && s.timeout > 0 ) {
8129
+ timeoutTimer = setTimeout(function() {
8130
+ jqXHR.abort("timeout");
8131
+ }, s.timeout );
8132
+ }
8133
+
8134
+ try {
8135
+ state = 1;
8136
+ transport.send( requestHeaders, done );
8137
+ } catch ( e ) {
8138
+ // Propagate exception as error if not done
8139
+ if ( state < 2 ) {
8140
+ done( -1, e );
8141
+ // Simply rethrow otherwise
8142
+ } else {
8143
+ throw e;
8144
+ }
8145
+ }
8146
+ }
8147
+
8148
+ // Callback for when everything is done
8149
+ function done( status, nativeStatusText, responses, headers ) {
8150
+ var isSuccess, success, error, response, modified,
8151
+ statusText = nativeStatusText;
8152
+
8153
+ // Called once
8154
+ if ( state === 2 ) {
8155
+ return;
8156
+ }
8157
+
8158
+ // State is "done" now
8159
+ state = 2;
8160
+
8161
+ // Clear timeout if it exists
8162
+ if ( timeoutTimer ) {
8163
+ clearTimeout( timeoutTimer );
8164
+ }
8165
+
8166
+ // Dereference transport for early garbage collection
8167
+ // (no matter how long the jqXHR object will be used)
8168
+ transport = undefined;
8169
+
8170
+ // Cache response headers
8171
+ responseHeadersString = headers || "";
8172
+
8173
+ // Set readyState
8174
+ jqXHR.readyState = status > 0 ? 4 : 0;
8175
+
8176
+ // Determine if successful
8177
+ isSuccess = status >= 200 && status < 300 || status === 304;
8178
+
8179
+ // Get response data
8180
+ if ( responses ) {
8181
+ response = ajaxHandleResponses( s, jqXHR, responses );
8182
+ }
8183
+
8184
+ // Convert no matter what (that way responseXXX fields are always set)
8185
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
8186
+
8187
+ // If successful, handle type chaining
8188
+ if ( isSuccess ) {
8189
+
8190
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8191
+ if ( s.ifModified ) {
8192
+ modified = jqXHR.getResponseHeader("Last-Modified");
8193
+ if ( modified ) {
8194
+ jQuery.lastModified[ cacheURL ] = modified;
8195
+ }
8196
+ modified = jqXHR.getResponseHeader("etag");
8197
+ if ( modified ) {
8198
+ jQuery.etag[ cacheURL ] = modified;
8199
+ }
8200
+ }
8201
+
8202
+ // if no content
8203
+ if ( status === 204 || s.type === "HEAD" ) {
8204
+ statusText = "nocontent";
8205
+
8206
+ // if not modified
8207
+ } else if ( status === 304 ) {
8208
+ statusText = "notmodified";
8209
+
8210
+ // If we have data, let's convert it
8211
+ } else {
8212
+ statusText = response.state;
8213
+ success = response.data;
8214
+ error = response.error;
8215
+ isSuccess = !error;
8216
+ }
8217
+ } else {
8218
+ // We extract error from statusText
8219
+ // then normalize statusText and status for non-aborts
8220
+ error = statusText;
8221
+ if ( status || !statusText ) {
8222
+ statusText = "error";
8223
+ if ( status < 0 ) {
8224
+ status = 0;
8225
+ }
8226
+ }
8227
+ }
8228
+
8229
+ // Set data for the fake xhr object
8230
+ jqXHR.status = status;
8231
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
8232
+
8233
+ // Success/Error
8234
+ if ( isSuccess ) {
8235
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8236
+ } else {
8237
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8238
+ }
8239
+
8240
+ // Status-dependent callbacks
8241
+ jqXHR.statusCode( statusCode );
8242
+ statusCode = undefined;
8243
+
8244
+ if ( fireGlobals ) {
8245
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
8246
+ [ jqXHR, s, isSuccess ? success : error ] );
8247
+ }
8248
+
8249
+ // Complete
8250
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8251
+
8252
+ if ( fireGlobals ) {
8253
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8254
+ // Handle the global AJAX counter
8255
+ if ( !( --jQuery.active ) ) {
8256
+ jQuery.event.trigger("ajaxStop");
8257
+ }
8258
+ }
8259
+ }
8260
+
8261
+ return jqXHR;
8262
+ },
8263
+
8264
+ getJSON: function( url, data, callback ) {
8265
+ return jQuery.get( url, data, callback, "json" );
8266
+ },
8267
+
8268
+ getScript: function( url, callback ) {
8269
+ return jQuery.get( url, undefined, callback, "script" );
8270
+ }
8271
+ });
8272
+
8273
+ jQuery.each( [ "get", "post" ], function( i, method ) {
8274
+ jQuery[ method ] = function( url, data, callback, type ) {
8275
+ // shift arguments if data argument was omitted
8276
+ if ( jQuery.isFunction( data ) ) {
8277
+ type = type || callback;
8278
+ callback = data;
8279
+ data = undefined;
8280
+ }
8281
+
8282
+ return jQuery.ajax({
8283
+ url: url,
8284
+ type: method,
8285
+ dataType: type,
8286
+ data: data,
8287
+ success: callback
8288
+ });
8289
+ };
8290
+ });
8291
+
8292
+ /* Handles responses to an ajax request:
8293
+ * - finds the right dataType (mediates between content-type and expected dataType)
8294
+ * - returns the corresponding response
8295
+ */
8296
+ function ajaxHandleResponses( s, jqXHR, responses ) {
8297
+ var firstDataType, ct, finalDataType, type,
8298
+ contents = s.contents,
8299
+ dataTypes = s.dataTypes;
8300
+
8301
+ // Remove auto dataType and get content-type in the process
8302
+ while( dataTypes[ 0 ] === "*" ) {
8303
+ dataTypes.shift();
8304
+ if ( ct === undefined ) {
8305
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
8306
+ }
8307
+ }
8308
+
8309
+ // Check if we're dealing with a known content-type
8310
+ if ( ct ) {
8311
+ for ( type in contents ) {
8312
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
8313
+ dataTypes.unshift( type );
8314
+ break;
8315
+ }
8316
+ }
8317
+ }
8318
+
8319
+ // Check to see if we have a response for the expected dataType
8320
+ if ( dataTypes[ 0 ] in responses ) {
8321
+ finalDataType = dataTypes[ 0 ];
8322
+ } else {
8323
+ // Try convertible dataTypes
8324
+ for ( type in responses ) {
8325
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
8326
+ finalDataType = type;
8327
+ break;
8328
+ }
8329
+ if ( !firstDataType ) {
8330
+ firstDataType = type;
8331
+ }
8332
+ }
8333
+ // Or just use first one
8334
+ finalDataType = finalDataType || firstDataType;
8335
+ }
8336
+
8337
+ // If we found a dataType
8338
+ // We add the dataType to the list if needed
8339
+ // and return the corresponding response
8340
+ if ( finalDataType ) {
8341
+ if ( finalDataType !== dataTypes[ 0 ] ) {
8342
+ dataTypes.unshift( finalDataType );
8343
+ }
8344
+ return responses[ finalDataType ];
8345
+ }
8346
+ }
8347
+
8348
+ /* Chain conversions given the request and the original response
8349
+ * Also sets the responseXXX fields on the jqXHR instance
8350
+ */
8351
+ function ajaxConvert( s, response, jqXHR, isSuccess ) {
8352
+ var conv2, current, conv, tmp, prev,
8353
+ converters = {},
8354
+ // Work with a copy of dataTypes in case we need to modify it for conversion
8355
+ dataTypes = s.dataTypes.slice();
8356
+
8357
+ // Create converters map with lowercased keys
8358
+ if ( dataTypes[ 1 ] ) {
8359
+ for ( conv in s.converters ) {
8360
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
8361
+ }
8362
+ }
8363
+
8364
+ current = dataTypes.shift();
8365
+
8366
+ // Convert to each sequential dataType
8367
+ while ( current ) {
8368
+
8369
+ if ( s.responseFields[ current ] ) {
8370
+ jqXHR[ s.responseFields[ current ] ] = response;
8371
+ }
8372
+
8373
+ // Apply the dataFilter if provided
8374
+ if ( !prev && isSuccess && s.dataFilter ) {
8375
+ response = s.dataFilter( response, s.dataType );
8376
+ }
8377
+
8378
+ prev = current;
8379
+ current = dataTypes.shift();
8380
+
8381
+ if ( current ) {
8382
+
8383
+ // There's only work to do if current dataType is non-auto
8384
+ if ( current === "*" ) {
8385
+
8386
+ current = prev;
8387
+
8388
+ // Convert response if prev dataType is non-auto and differs from current
8389
+ } else if ( prev !== "*" && prev !== current ) {
8390
+
8391
+ // Seek a direct converter
8392
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
8393
+
8394
+ // If none found, seek a pair
8395
+ if ( !conv ) {
8396
+ for ( conv2 in converters ) {
8397
+
8398
+ // If conv2 outputs current
8399
+ tmp = conv2.split( " " );
8400
+ if ( tmp[ 1 ] === current ) {
8401
+
8402
+ // If prev can be converted to accepted input
8403
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
8404
+ converters[ "* " + tmp[ 0 ] ];
8405
+ if ( conv ) {
8406
+ // Condense equivalence converters
8407
+ if ( conv === true ) {
8408
+ conv = converters[ conv2 ];
8409
+
8410
+ // Otherwise, insert the intermediate dataType
8411
+ } else if ( converters[ conv2 ] !== true ) {
8412
+ current = tmp[ 0 ];
8413
+ dataTypes.unshift( tmp[ 1 ] );
8414
+ }
8415
+ break;
8416
+ }
8417
+ }
8418
+ }
8419
+ }
8420
+
8421
+ // Apply converter (if not an equivalence)
8422
+ if ( conv !== true ) {
8423
+
8424
+ // Unless errors are allowed to bubble, catch and return them
8425
+ if ( conv && s[ "throws" ] ) {
8426
+ response = conv( response );
8427
+ } else {
8428
+ try {
8429
+ response = conv( response );
8430
+ } catch ( e ) {
8431
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
8432
+ }
8433
+ }
8434
+ }
8435
+ }
8436
+ }
8437
+ }
8438
+
8439
+ return { state: "success", data: response };
8440
+ }
8441
+ // Install script dataType
8442
+ jQuery.ajaxSetup({
8443
+ accepts: {
8444
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8445
+ },
8446
+ contents: {
8447
+ script: /(?:java|ecma)script/
8448
+ },
8449
+ converters: {
8450
+ "text script": function( text ) {
8451
+ jQuery.globalEval( text );
8452
+ return text;
8453
+ }
8454
+ }
8455
+ });
8456
+
8457
+ // Handle cache's special case and global
8458
+ jQuery.ajaxPrefilter( "script", function( s ) {
8459
+ if ( s.cache === undefined ) {
8460
+ s.cache = false;
8461
+ }
8462
+ if ( s.crossDomain ) {
8463
+ s.type = "GET";
8464
+ s.global = false;
8465
+ }
8466
+ });
8467
+
8468
+ // Bind script tag hack transport
8469
+ jQuery.ajaxTransport( "script", function(s) {
8470
+
8471
+ // This transport only deals with cross domain requests
8472
+ if ( s.crossDomain ) {
8473
+
8474
+ var script,
8475
+ head = document.head || jQuery("head")[0] || document.documentElement;
8476
+
8477
+ return {
8478
+
8479
+ send: function( _, callback ) {
8480
+
8481
+ script = document.createElement("script");
8482
+
8483
+ script.async = true;
8484
+
8485
+ if ( s.scriptCharset ) {
8486
+ script.charset = s.scriptCharset;
8487
+ }
8488
+
8489
+ script.src = s.url;
8490
+
8491
+ // Attach handlers for all browsers
8492
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
8493
+
8494
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
8495
+
8496
+ // Handle memory leak in IE
8497
+ script.onload = script.onreadystatechange = null;
8498
+
8499
+ // Remove the script
8500
+ if ( script.parentNode ) {
8501
+ script.parentNode.removeChild( script );
8502
+ }
8503
+
8504
+ // Dereference the script
8505
+ script = null;
8506
+
8507
+ // Callback if not abort
8508
+ if ( !isAbort ) {
8509
+ callback( 200, "success" );
8510
+ }
8511
+ }
8512
+ };
8513
+
8514
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
8515
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
8516
+ head.insertBefore( script, head.firstChild );
8517
+ },
8518
+
8519
+ abort: function() {
8520
+ if ( script ) {
8521
+ script.onload( undefined, true );
8522
+ }
8523
+ }
8524
+ };
8525
+ }
8526
+ });
8527
+ var oldCallbacks = [],
8528
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
8529
+
8530
+ // Default jsonp settings
8531
+ jQuery.ajaxSetup({
8532
+ jsonp: "callback",
8533
+ jsonpCallback: function() {
8534
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
8535
+ this[ callback ] = true;
8536
+ return callback;
8537
+ }
8538
+ });
8539
+
8540
+ // Detect, normalize options and install callbacks for jsonp requests
8541
+ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8542
+
8543
+ var callbackName, overwritten, responseContainer,
8544
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
8545
+ "url" :
8546
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
8547
+ );
8548
+
8549
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
8550
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
8551
+
8552
+ // Get callback name, remembering preexisting value associated with it
8553
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
8554
+ s.jsonpCallback() :
8555
+ s.jsonpCallback;
8556
+
8557
+ // Insert callback into url or form data
8558
+ if ( jsonProp ) {
8559
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
8560
+ } else if ( s.jsonp !== false ) {
8561
+ s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
8562
+ }
8563
+
8564
+ // Use data converter to retrieve json after script execution
8565
+ s.converters["script json"] = function() {
8566
+ if ( !responseContainer ) {
8567
+ jQuery.error( callbackName + " was not called" );
8568
+ }
8569
+ return responseContainer[ 0 ];
8570
+ };
8571
+
8572
+ // force json dataType
8573
+ s.dataTypes[ 0 ] = "json";
8574
+
8575
+ // Install callback
8576
+ overwritten = window[ callbackName ];
8577
+ window[ callbackName ] = function() {
8578
+ responseContainer = arguments;
8579
+ };
8580
+
8581
+ // Clean-up function (fires after converters)
8582
+ jqXHR.always(function() {
8583
+ // Restore preexisting value
8584
+ window[ callbackName ] = overwritten;
8585
+
8586
+ // Save back as free
8587
+ if ( s[ callbackName ] ) {
8588
+ // make sure that re-using the options doesn't screw things around
8589
+ s.jsonpCallback = originalSettings.jsonpCallback;
8590
+
8591
+ // save the callback name for future use
8592
+ oldCallbacks.push( callbackName );
8593
+ }
8594
+
8595
+ // Call if it was a function and we have a response
8596
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
8597
+ overwritten( responseContainer[ 0 ] );
8598
+ }
8599
+
8600
+ responseContainer = overwritten = undefined;
8601
+ });
8602
+
8603
+ // Delegate to script
8604
+ return "script";
8605
+ }
8606
+ });
8607
+ var xhrCallbacks, xhrSupported,
8608
+ xhrId = 0,
8609
+ // #5280: Internet Explorer will keep connections alive if we don't abort on unload
8610
+ xhrOnUnloadAbort = window.ActiveXObject && function() {
8611
+ // Abort all pending requests
8612
+ var key;
8613
+ for ( key in xhrCallbacks ) {
8614
+ xhrCallbacks[ key ]( undefined, true );
8615
+ }
8616
+ };
8617
+
8618
+ // Functions to create xhrs
8619
+ function createStandardXHR() {
8620
+ try {
8621
+ return new window.XMLHttpRequest();
8622
+ } catch( e ) {}
8623
+ }
8624
+
8625
+ function createActiveXHR() {
8626
+ try {
8627
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
8628
+ } catch( e ) {}
8629
+ }
8630
+
8631
+ // Create the request object
8632
+ // (This is still attached to ajaxSettings for backward compatibility)
8633
+ jQuery.ajaxSettings.xhr = window.ActiveXObject ?
8634
+ /* Microsoft failed to properly
8635
+ * implement the XMLHttpRequest in IE7 (can't request local files),
8636
+ * so we use the ActiveXObject when it is available
8637
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
8638
+ * we need a fallback.
8639
+ */
8640
+ function() {
8641
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
8642
+ } :
8643
+ // For all other browsers, use the standard XMLHttpRequest object
8644
+ createStandardXHR;
8645
+
8646
+ // Determine support properties
8647
+ xhrSupported = jQuery.ajaxSettings.xhr();
8648
+ jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
8649
+ xhrSupported = jQuery.support.ajax = !!xhrSupported;
8650
+
8651
+ // Create transport if the browser can provide an xhr
8652
+ if ( xhrSupported ) {
8653
+
8654
+ jQuery.ajaxTransport(function( s ) {
8655
+ // Cross domain only allowed if supported through XMLHttpRequest
8656
+ if ( !s.crossDomain || jQuery.support.cors ) {
8657
+
8658
+ var callback;
8659
+
8660
+ return {
8661
+ send: function( headers, complete ) {
8662
+
8663
+ // Get a new xhr
8664
+ var handle, i,
8665
+ xhr = s.xhr();
8666
+
8667
+ // Open the socket
8668
+ // Passing null username, generates a login popup on Opera (#2865)
8669
+ if ( s.username ) {
8670
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
8671
+ } else {
8672
+ xhr.open( s.type, s.url, s.async );
8673
+ }
8674
+
8675
+ // Apply custom fields if provided
8676
+ if ( s.xhrFields ) {
8677
+ for ( i in s.xhrFields ) {
8678
+ xhr[ i ] = s.xhrFields[ i ];
8679
+ }
8680
+ }
8681
+
8682
+ // Override mime type if needed
8683
+ if ( s.mimeType && xhr.overrideMimeType ) {
8684
+ xhr.overrideMimeType( s.mimeType );
8685
+ }
8686
+
8687
+ // X-Requested-With header
8688
+ // For cross-domain requests, seeing as conditions for a preflight are
8689
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
8690
+ // (it can always be set on a per-request basis or even using ajaxSetup)
8691
+ // For same-domain requests, won't change header if already provided.
8692
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
8693
+ headers["X-Requested-With"] = "XMLHttpRequest";
8694
+ }
8695
+
8696
+ // Need an extra try/catch for cross domain requests in Firefox 3
8697
+ try {
8698
+ for ( i in headers ) {
8699
+ xhr.setRequestHeader( i, headers[ i ] );
8700
+ }
8701
+ } catch( err ) {}
8702
+
8703
+ // Do send the request
8704
+ // This may raise an exception which is actually
8705
+ // handled in jQuery.ajax (so no try/catch here)
8706
+ xhr.send( ( s.hasContent && s.data ) || null );
8707
+
8708
+ // Listener
8709
+ callback = function( _, isAbort ) {
8710
+ var status, responseHeaders, statusText, responses;
8711
+
8712
+ // Firefox throws exceptions when accessing properties
8713
+ // of an xhr when a network error occurred
8714
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
8715
+ try {
8716
+
8717
+ // Was never called and is aborted or complete
8718
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
8719
+
8720
+ // Only called once
8721
+ callback = undefined;
8722
+
8723
+ // Do not keep as active anymore
8724
+ if ( handle ) {
8725
+ xhr.onreadystatechange = jQuery.noop;
8726
+ if ( xhrOnUnloadAbort ) {
8727
+ delete xhrCallbacks[ handle ];
8728
+ }
8729
+ }
8730
+
8731
+ // If it's an abort
8732
+ if ( isAbort ) {
8733
+ // Abort it manually if needed
8734
+ if ( xhr.readyState !== 4 ) {
8735
+ xhr.abort();
8736
+ }
8737
+ } else {
8738
+ responses = {};
8739
+ status = xhr.status;
8740
+ responseHeaders = xhr.getAllResponseHeaders();
8741
+
8742
+ // When requesting binary data, IE6-9 will throw an exception
8743
+ // on any attempt to access responseText (#11426)
8744
+ if ( typeof xhr.responseText === "string" ) {
8745
+ responses.text = xhr.responseText;
8746
+ }
8747
+
8748
+ // Firefox throws an exception when accessing
8749
+ // statusText for faulty cross-domain requests
8750
+ try {
8751
+ statusText = xhr.statusText;
8752
+ } catch( e ) {
8753
+ // We normalize with Webkit giving an empty statusText
8754
+ statusText = "";
8755
+ }
8756
+
8757
+ // Filter status for non standard behaviors
8758
+
8759
+ // If the request is local and we have data: assume a success
8760
+ // (success with no data won't get notified, that's the best we
8761
+ // can do given current implementations)
8762
+ if ( !status && s.isLocal && !s.crossDomain ) {
8763
+ status = responses.text ? 200 : 404;
8764
+ // IE - #1450: sometimes returns 1223 when it should be 204
8765
+ } else if ( status === 1223 ) {
8766
+ status = 204;
8767
+ }
8768
+ }
8769
+ }
8770
+ } catch( firefoxAccessException ) {
8771
+ if ( !isAbort ) {
8772
+ complete( -1, firefoxAccessException );
8773
+ }
8774
+ }
8775
+
8776
+ // Call complete if needed
8777
+ if ( responses ) {
8778
+ complete( status, statusText, responses, responseHeaders );
8779
+ }
8780
+ };
8781
+
8782
+ if ( !s.async ) {
8783
+ // if we're in sync mode we fire the callback
8784
+ callback();
8785
+ } else if ( xhr.readyState === 4 ) {
8786
+ // (IE6 & IE7) if it's in cache and has been
8787
+ // retrieved directly we need to fire the callback
8788
+ setTimeout( callback );
8789
+ } else {
8790
+ handle = ++xhrId;
8791
+ if ( xhrOnUnloadAbort ) {
8792
+ // Create the active xhrs callbacks list if needed
8793
+ // and attach the unload handler
8794
+ if ( !xhrCallbacks ) {
8795
+ xhrCallbacks = {};
8796
+ jQuery( window ).unload( xhrOnUnloadAbort );
8797
+ }
8798
+ // Add to list of active xhrs callbacks
8799
+ xhrCallbacks[ handle ] = callback;
8800
+ }
8801
+ xhr.onreadystatechange = callback;
8802
+ }
8803
+ },
8804
+
8805
+ abort: function() {
8806
+ if ( callback ) {
8807
+ callback( undefined, true );
8808
+ }
8809
+ }
8810
+ };
8811
+ }
8812
+ });
8813
+ }
8814
+ var fxNow, timerId,
8815
+ rfxtypes = /^(?:toggle|show|hide)$/,
8816
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
8817
+ rrun = /queueHooks$/,
8818
+ animationPrefilters = [ defaultPrefilter ],
8819
+ tweeners = {
8820
+ "*": [function( prop, value ) {
8821
+ var tween = this.createTween( prop, value ),
8822
+ target = tween.cur(),
8823
+ parts = rfxnum.exec( value ),
8824
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
8825
+
8826
+ // Starting value computation is required for potential unit mismatches
8827
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
8828
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
8829
+ scale = 1,
8830
+ maxIterations = 20;
8831
+
8832
+ if ( start && start[ 3 ] !== unit ) {
8833
+ // Trust units reported by jQuery.css
8834
+ unit = unit || start[ 3 ];
8835
+
8836
+ // Make sure we update the tween properties later on
8837
+ parts = parts || [];
8838
+
8839
+ // Iteratively approximate from a nonzero starting point
8840
+ start = +target || 1;
8841
+
8842
+ do {
8843
+ // If previous iteration zeroed out, double until we get *something*
8844
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
8845
+ scale = scale || ".5";
8846
+
8847
+ // Adjust and apply
8848
+ start = start / scale;
8849
+ jQuery.style( tween.elem, prop, start + unit );
8850
+
8851
+ // Update scale, tolerating zero or NaN from tween.cur()
8852
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
8853
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
8854
+ }
8855
+
8856
+ // Update tween properties
8857
+ if ( parts ) {
8858
+ start = tween.start = +start || +target || 0;
8859
+ tween.unit = unit;
8860
+ // If a +=/-= token was provided, we're doing a relative animation
8861
+ tween.end = parts[ 1 ] ?
8862
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
8863
+ +parts[ 2 ];
8864
+ }
8865
+
8866
+ return tween;
8867
+ }]
8868
+ };
8869
+
8870
+ // Animations created synchronously will run synchronously
8871
+ function createFxNow() {
8872
+ setTimeout(function() {
8873
+ fxNow = undefined;
8874
+ });
8875
+ return ( fxNow = jQuery.now() );
8876
+ }
8877
+
8878
+ function createTween( value, prop, animation ) {
8879
+ var tween,
8880
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
8881
+ index = 0,
8882
+ length = collection.length;
8883
+ for ( ; index < length; index++ ) {
8884
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
8885
+
8886
+ // we're done with this property
8887
+ return tween;
8888
+ }
8889
+ }
8890
+ }
8891
+
8892
+ function Animation( elem, properties, options ) {
8893
+ var result,
8894
+ stopped,
8895
+ index = 0,
8896
+ length = animationPrefilters.length,
8897
+ deferred = jQuery.Deferred().always( function() {
8898
+ // don't match elem in the :animated selector
8899
+ delete tick.elem;
8900
+ }),
8901
+ tick = function() {
8902
+ if ( stopped ) {
8903
+ return false;
8904
+ }
8905
+ var currentTime = fxNow || createFxNow(),
8906
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
8907
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
8908
+ temp = remaining / animation.duration || 0,
8909
+ percent = 1 - temp,
8910
+ index = 0,
8911
+ length = animation.tweens.length;
8912
+
8913
+ for ( ; index < length ; index++ ) {
8914
+ animation.tweens[ index ].run( percent );
8915
+ }
8916
+
8917
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
8918
+
8919
+ if ( percent < 1 && length ) {
8920
+ return remaining;
8921
+ } else {
8922
+ deferred.resolveWith( elem, [ animation ] );
8923
+ return false;
8924
+ }
8925
+ },
8926
+ animation = deferred.promise({
8927
+ elem: elem,
8928
+ props: jQuery.extend( {}, properties ),
8929
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
8930
+ originalProperties: properties,
8931
+ originalOptions: options,
8932
+ startTime: fxNow || createFxNow(),
8933
+ duration: options.duration,
8934
+ tweens: [],
8935
+ createTween: function( prop, end ) {
8936
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
8937
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
8938
+ animation.tweens.push( tween );
8939
+ return tween;
8940
+ },
8941
+ stop: function( gotoEnd ) {
8942
+ var index = 0,
8943
+ // if we are going to the end, we want to run all the tweens
8944
+ // otherwise we skip this part
8945
+ length = gotoEnd ? animation.tweens.length : 0;
8946
+ if ( stopped ) {
8947
+ return this;
8948
+ }
8949
+ stopped = true;
8950
+ for ( ; index < length ; index++ ) {
8951
+ animation.tweens[ index ].run( 1 );
8952
+ }
8953
+
8954
+ // resolve when we played the last frame
8955
+ // otherwise, reject
8956
+ if ( gotoEnd ) {
8957
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
8958
+ } else {
8959
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
8960
+ }
8961
+ return this;
8962
+ }
8963
+ }),
8964
+ props = animation.props;
8965
+
8966
+ propFilter( props, animation.opts.specialEasing );
8967
+
8968
+ for ( ; index < length ; index++ ) {
8969
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
8970
+ if ( result ) {
8971
+ return result;
8972
+ }
8973
+ }
8974
+
8975
+ jQuery.map( props, createTween, animation );
8976
+
8977
+ if ( jQuery.isFunction( animation.opts.start ) ) {
8978
+ animation.opts.start.call( elem, animation );
8979
+ }
8980
+
8981
+ jQuery.fx.timer(
8982
+ jQuery.extend( tick, {
8983
+ elem: elem,
8984
+ anim: animation,
8985
+ queue: animation.opts.queue
8986
+ })
8987
+ );
8988
+
8989
+ // attach callbacks from options
8990
+ return animation.progress( animation.opts.progress )
8991
+ .done( animation.opts.done, animation.opts.complete )
8992
+ .fail( animation.opts.fail )
8993
+ .always( animation.opts.always );
8994
+ }
8995
+
8996
+ function propFilter( props, specialEasing ) {
8997
+ var index, name, easing, value, hooks;
8998
+
8999
+ // camelCase, specialEasing and expand cssHook pass
9000
+ for ( index in props ) {
9001
+ name = jQuery.camelCase( index );
9002
+ easing = specialEasing[ name ];
9003
+ value = props[ index ];
9004
+ if ( jQuery.isArray( value ) ) {
9005
+ easing = value[ 1 ];
9006
+ value = props[ index ] = value[ 0 ];
9007
+ }
9008
+
9009
+ if ( index !== name ) {
9010
+ props[ name ] = value;
9011
+ delete props[ index ];
9012
+ }
9013
+
9014
+ hooks = jQuery.cssHooks[ name ];
9015
+ if ( hooks && "expand" in hooks ) {
9016
+ value = hooks.expand( value );
9017
+ delete props[ name ];
9018
+
9019
+ // not quite $.extend, this wont overwrite keys already present.
9020
+ // also - reusing 'index' from above because we have the correct "name"
9021
+ for ( index in value ) {
9022
+ if ( !( index in props ) ) {
9023
+ props[ index ] = value[ index ];
9024
+ specialEasing[ index ] = easing;
9025
+ }
9026
+ }
9027
+ } else {
9028
+ specialEasing[ name ] = easing;
9029
+ }
9030
+ }
9031
+ }
9032
+
9033
+ jQuery.Animation = jQuery.extend( Animation, {
9034
+
9035
+ tweener: function( props, callback ) {
9036
+ if ( jQuery.isFunction( props ) ) {
9037
+ callback = props;
9038
+ props = [ "*" ];
9039
+ } else {
9040
+ props = props.split(" ");
9041
+ }
9042
+
9043
+ var prop,
9044
+ index = 0,
9045
+ length = props.length;
9046
+
9047
+ for ( ; index < length ; index++ ) {
9048
+ prop = props[ index ];
9049
+ tweeners[ prop ] = tweeners[ prop ] || [];
9050
+ tweeners[ prop ].unshift( callback );
9051
+ }
9052
+ },
9053
+
9054
+ prefilter: function( callback, prepend ) {
9055
+ if ( prepend ) {
9056
+ animationPrefilters.unshift( callback );
9057
+ } else {
9058
+ animationPrefilters.push( callback );
9059
+ }
9060
+ }
9061
+ });
9062
+
9063
+ function defaultPrefilter( elem, props, opts ) {
9064
+ /* jshint validthis: true */
9065
+ var prop, value, toggle, tween, hooks, oldfire,
9066
+ anim = this,
9067
+ orig = {},
9068
+ style = elem.style,
9069
+ hidden = elem.nodeType && isHidden( elem ),
9070
+ dataShow = jQuery._data( elem, "fxshow" );
9071
+
9072
+ // handle queue: false promises
9073
+ if ( !opts.queue ) {
9074
+ hooks = jQuery._queueHooks( elem, "fx" );
9075
+ if ( hooks.unqueued == null ) {
9076
+ hooks.unqueued = 0;
9077
+ oldfire = hooks.empty.fire;
9078
+ hooks.empty.fire = function() {
9079
+ if ( !hooks.unqueued ) {
9080
+ oldfire();
9081
+ }
9082
+ };
9083
+ }
9084
+ hooks.unqueued++;
9085
+
9086
+ anim.always(function() {
9087
+ // doing this makes sure that the complete handler will be called
9088
+ // before this completes
9089
+ anim.always(function() {
9090
+ hooks.unqueued--;
9091
+ if ( !jQuery.queue( elem, "fx" ).length ) {
9092
+ hooks.empty.fire();
9093
+ }
9094
+ });
9095
+ });
9096
+ }
9097
+
9098
+ // height/width overflow pass
9099
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
9100
+ // Make sure that nothing sneaks out
9101
+ // Record all 3 overflow attributes because IE does not
9102
+ // change the overflow attribute when overflowX and
9103
+ // overflowY are set to the same value
9104
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
9105
+
9106
+ // Set display property to inline-block for height/width
9107
+ // animations on inline elements that are having width/height animated
9108
+ if ( jQuery.css( elem, "display" ) === "inline" &&
9109
+ jQuery.css( elem, "float" ) === "none" ) {
9110
+
9111
+ // inline-level elements accept inline-block;
9112
+ // block-level elements need to be inline with layout
9113
+ if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
9114
+ style.display = "inline-block";
9115
+
9116
+ } else {
9117
+ style.zoom = 1;
9118
+ }
9119
+ }
9120
+ }
9121
+
9122
+ if ( opts.overflow ) {
9123
+ style.overflow = "hidden";
9124
+ if ( !jQuery.support.shrinkWrapBlocks ) {
9125
+ anim.always(function() {
9126
+ style.overflow = opts.overflow[ 0 ];
9127
+ style.overflowX = opts.overflow[ 1 ];
9128
+ style.overflowY = opts.overflow[ 2 ];
9129
+ });
9130
+ }
9131
+ }
9132
+
9133
+
9134
+ // show/hide pass
9135
+ for ( prop in props ) {
9136
+ value = props[ prop ];
9137
+ if ( rfxtypes.exec( value ) ) {
9138
+ delete props[ prop ];
9139
+ toggle = toggle || value === "toggle";
9140
+ if ( value === ( hidden ? "hide" : "show" ) ) {
9141
+ continue;
9142
+ }
9143
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
9144
+ }
9145
+ }
9146
+
9147
+ if ( !jQuery.isEmptyObject( orig ) ) {
9148
+ if ( dataShow ) {
9149
+ if ( "hidden" in dataShow ) {
9150
+ hidden = dataShow.hidden;
9151
+ }
9152
+ } else {
9153
+ dataShow = jQuery._data( elem, "fxshow", {} );
9154
+ }
9155
+
9156
+ // store state if its toggle - enables .stop().toggle() to "reverse"
9157
+ if ( toggle ) {
9158
+ dataShow.hidden = !hidden;
9159
+ }
9160
+ if ( hidden ) {
9161
+ jQuery( elem ).show();
9162
+ } else {
9163
+ anim.done(function() {
9164
+ jQuery( elem ).hide();
9165
+ });
9166
+ }
9167
+ anim.done(function() {
9168
+ var prop;
9169
+ jQuery._removeData( elem, "fxshow" );
9170
+ for ( prop in orig ) {
9171
+ jQuery.style( elem, prop, orig[ prop ] );
9172
+ }
9173
+ });
9174
+ for ( prop in orig ) {
9175
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
9176
+
9177
+ if ( !( prop in dataShow ) ) {
9178
+ dataShow[ prop ] = tween.start;
9179
+ if ( hidden ) {
9180
+ tween.end = tween.start;
9181
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
9182
+ }
9183
+ }
9184
+ }
9185
+ }
9186
+ }
9187
+
9188
+ function Tween( elem, options, prop, end, easing ) {
9189
+ return new Tween.prototype.init( elem, options, prop, end, easing );
9190
+ }
9191
+ jQuery.Tween = Tween;
9192
+
9193
+ Tween.prototype = {
9194
+ constructor: Tween,
9195
+ init: function( elem, options, prop, end, easing, unit ) {
9196
+ this.elem = elem;
9197
+ this.prop = prop;
9198
+ this.easing = easing || "swing";
9199
+ this.options = options;
9200
+ this.start = this.now = this.cur();
9201
+ this.end = end;
9202
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
9203
+ },
9204
+ cur: function() {
9205
+ var hooks = Tween.propHooks[ this.prop ];
9206
+
9207
+ return hooks && hooks.get ?
9208
+ hooks.get( this ) :
9209
+ Tween.propHooks._default.get( this );
9210
+ },
9211
+ run: function( percent ) {
9212
+ var eased,
9213
+ hooks = Tween.propHooks[ this.prop ];
9214
+
9215
+ if ( this.options.duration ) {
9216
+ this.pos = eased = jQuery.easing[ this.easing ](
9217
+ percent, this.options.duration * percent, 0, 1, this.options.duration
9218
+ );
9219
+ } else {
9220
+ this.pos = eased = percent;
9221
+ }
9222
+ this.now = ( this.end - this.start ) * eased + this.start;
9223
+
9224
+ if ( this.options.step ) {
9225
+ this.options.step.call( this.elem, this.now, this );
9226
+ }
9227
+
9228
+ if ( hooks && hooks.set ) {
9229
+ hooks.set( this );
9230
+ } else {
9231
+ Tween.propHooks._default.set( this );
9232
+ }
9233
+ return this;
9234
+ }
9235
+ };
9236
+
9237
+ Tween.prototype.init.prototype = Tween.prototype;
9238
+
9239
+ Tween.propHooks = {
9240
+ _default: {
9241
+ get: function( tween ) {
9242
+ var result;
9243
+
9244
+ if ( tween.elem[ tween.prop ] != null &&
9245
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
9246
+ return tween.elem[ tween.prop ];
9247
+ }
9248
+
9249
+ // passing an empty string as a 3rd parameter to .css will automatically
9250
+ // attempt a parseFloat and fallback to a string if the parse fails
9251
+ // so, simple values such as "10px" are parsed to Float.
9252
+ // complex values such as "rotate(1rad)" are returned as is.
9253
+ result = jQuery.css( tween.elem, tween.prop, "" );
9254
+ // Empty strings, null, undefined and "auto" are converted to 0.
9255
+ return !result || result === "auto" ? 0 : result;
9256
+ },
9257
+ set: function( tween ) {
9258
+ // use step hook for back compat - use cssHook if its there - use .style if its
9259
+ // available and use plain properties where available
9260
+ if ( jQuery.fx.step[ tween.prop ] ) {
9261
+ jQuery.fx.step[ tween.prop ]( tween );
9262
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
9263
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
9264
+ } else {
9265
+ tween.elem[ tween.prop ] = tween.now;
9266
+ }
9267
+ }
9268
+ }
9269
+ };
9270
+
9271
+ // Support: IE <=9
9272
+ // Panic based approach to setting things on disconnected nodes
9273
+
9274
+ Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
9275
+ set: function( tween ) {
9276
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
9277
+ tween.elem[ tween.prop ] = tween.now;
9278
+ }
9279
+ }
9280
+ };
9281
+
9282
+ jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
9283
+ var cssFn = jQuery.fn[ name ];
9284
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
9285
+ return speed == null || typeof speed === "boolean" ?
9286
+ cssFn.apply( this, arguments ) :
9287
+ this.animate( genFx( name, true ), speed, easing, callback );
9288
+ };
9289
+ });
9290
+
9291
+ jQuery.fn.extend({
9292
+ fadeTo: function( speed, to, easing, callback ) {
9293
+
9294
+ // show any hidden elements after setting opacity to 0
9295
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
9296
+
9297
+ // animate to the value specified
9298
+ .end().animate({ opacity: to }, speed, easing, callback );
9299
+ },
9300
+ animate: function( prop, speed, easing, callback ) {
9301
+ var empty = jQuery.isEmptyObject( prop ),
9302
+ optall = jQuery.speed( speed, easing, callback ),
9303
+ doAnimation = function() {
9304
+ // Operate on a copy of prop so per-property easing won't be lost
9305
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
9306
+
9307
+ // Empty animations, or finishing resolves immediately
9308
+ if ( empty || jQuery._data( this, "finish" ) ) {
9309
+ anim.stop( true );
9310
+ }
9311
+ };
9312
+ doAnimation.finish = doAnimation;
9313
+
9314
+ return empty || optall.queue === false ?
9315
+ this.each( doAnimation ) :
9316
+ this.queue( optall.queue, doAnimation );
9317
+ },
9318
+ stop: function( type, clearQueue, gotoEnd ) {
9319
+ var stopQueue = function( hooks ) {
9320
+ var stop = hooks.stop;
9321
+ delete hooks.stop;
9322
+ stop( gotoEnd );
9323
+ };
9324
+
9325
+ if ( typeof type !== "string" ) {
9326
+ gotoEnd = clearQueue;
9327
+ clearQueue = type;
9328
+ type = undefined;
9329
+ }
9330
+ if ( clearQueue && type !== false ) {
9331
+ this.queue( type || "fx", [] );
9332
+ }
9333
+
9334
+ return this.each(function() {
9335
+ var dequeue = true,
9336
+ index = type != null && type + "queueHooks",
9337
+ timers = jQuery.timers,
9338
+ data = jQuery._data( this );
9339
+
9340
+ if ( index ) {
9341
+ if ( data[ index ] && data[ index ].stop ) {
9342
+ stopQueue( data[ index ] );
9343
+ }
9344
+ } else {
9345
+ for ( index in data ) {
9346
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
9347
+ stopQueue( data[ index ] );
9348
+ }
9349
+ }
9350
+ }
9351
+
9352
+ for ( index = timers.length; index--; ) {
9353
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
9354
+ timers[ index ].anim.stop( gotoEnd );
9355
+ dequeue = false;
9356
+ timers.splice( index, 1 );
9357
+ }
9358
+ }
9359
+
9360
+ // start the next in the queue if the last step wasn't forced
9361
+ // timers currently will call their complete callbacks, which will dequeue
9362
+ // but only if they were gotoEnd
9363
+ if ( dequeue || !gotoEnd ) {
9364
+ jQuery.dequeue( this, type );
9365
+ }
9366
+ });
9367
+ },
9368
+ finish: function( type ) {
9369
+ if ( type !== false ) {
9370
+ type = type || "fx";
9371
+ }
9372
+ return this.each(function() {
9373
+ var index,
9374
+ data = jQuery._data( this ),
9375
+ queue = data[ type + "queue" ],
9376
+ hooks = data[ type + "queueHooks" ],
9377
+ timers = jQuery.timers,
9378
+ length = queue ? queue.length : 0;
9379
+
9380
+ // enable finishing flag on private data
9381
+ data.finish = true;
9382
+
9383
+ // empty the queue first
9384
+ jQuery.queue( this, type, [] );
9385
+
9386
+ if ( hooks && hooks.stop ) {
9387
+ hooks.stop.call( this, true );
9388
+ }
9389
+
9390
+ // look for any active animations, and finish them
9391
+ for ( index = timers.length; index--; ) {
9392
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
9393
+ timers[ index ].anim.stop( true );
9394
+ timers.splice( index, 1 );
9395
+ }
9396
+ }
9397
+
9398
+ // look for any animations in the old queue and finish them
9399
+ for ( index = 0; index < length; index++ ) {
9400
+ if ( queue[ index ] && queue[ index ].finish ) {
9401
+ queue[ index ].finish.call( this );
9402
+ }
9403
+ }
9404
+
9405
+ // turn off finishing flag
9406
+ delete data.finish;
9407
+ });
9408
+ }
9409
+ });
9410
+
9411
+ // Generate parameters to create a standard animation
9412
+ function genFx( type, includeWidth ) {
9413
+ var which,
9414
+ attrs = { height: type },
9415
+ i = 0;
9416
+
9417
+ // if we include width, step value is 1 to do all cssExpand values,
9418
+ // if we don't include width, step value is 2 to skip over Left and Right
9419
+ includeWidth = includeWidth? 1 : 0;
9420
+ for( ; i < 4 ; i += 2 - includeWidth ) {
9421
+ which = cssExpand[ i ];
9422
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
9423
+ }
9424
+
9425
+ if ( includeWidth ) {
9426
+ attrs.opacity = attrs.width = type;
9427
+ }
9428
+
9429
+ return attrs;
9430
+ }
9431
+
9432
+ // Generate shortcuts for custom animations
9433
+ jQuery.each({
9434
+ slideDown: genFx("show"),
9435
+ slideUp: genFx("hide"),
9436
+ slideToggle: genFx("toggle"),
9437
+ fadeIn: { opacity: "show" },
9438
+ fadeOut: { opacity: "hide" },
9439
+ fadeToggle: { opacity: "toggle" }
9440
+ }, function( name, props ) {
9441
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
9442
+ return this.animate( props, speed, easing, callback );
9443
+ };
9444
+ });
9445
+
9446
+ jQuery.speed = function( speed, easing, fn ) {
9447
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
9448
+ complete: fn || !fn && easing ||
9449
+ jQuery.isFunction( speed ) && speed,
9450
+ duration: speed,
9451
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
9452
+ };
9453
+
9454
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
9455
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
9456
+
9457
+ // normalize opt.queue - true/undefined/null -> "fx"
9458
+ if ( opt.queue == null || opt.queue === true ) {
9459
+ opt.queue = "fx";
9460
+ }
9461
+
9462
+ // Queueing
9463
+ opt.old = opt.complete;
9464
+
9465
+ opt.complete = function() {
9466
+ if ( jQuery.isFunction( opt.old ) ) {
9467
+ opt.old.call( this );
9468
+ }
9469
+
9470
+ if ( opt.queue ) {
9471
+ jQuery.dequeue( this, opt.queue );
9472
+ }
9473
+ };
9474
+
9475
+ return opt;
9476
+ };
9477
+
9478
+ jQuery.easing = {
9479
+ linear: function( p ) {
9480
+ return p;
9481
+ },
9482
+ swing: function( p ) {
9483
+ return 0.5 - Math.cos( p*Math.PI ) / 2;
9484
+ }
9485
+ };
9486
+
9487
+ jQuery.timers = [];
9488
+ jQuery.fx = Tween.prototype.init;
9489
+ jQuery.fx.tick = function() {
9490
+ var timer,
9491
+ timers = jQuery.timers,
9492
+ i = 0;
9493
+
9494
+ fxNow = jQuery.now();
9495
+
9496
+ for ( ; i < timers.length; i++ ) {
9497
+ timer = timers[ i ];
9498
+ // Checks the timer has not already been removed
9499
+ if ( !timer() && timers[ i ] === timer ) {
9500
+ timers.splice( i--, 1 );
9501
+ }
9502
+ }
9503
+
9504
+ if ( !timers.length ) {
9505
+ jQuery.fx.stop();
9506
+ }
9507
+ fxNow = undefined;
9508
+ };
9509
+
9510
+ jQuery.fx.timer = function( timer ) {
9511
+ if ( timer() && jQuery.timers.push( timer ) ) {
9512
+ jQuery.fx.start();
9513
+ }
9514
+ };
9515
+
9516
+ jQuery.fx.interval = 13;
9517
+
9518
+ jQuery.fx.start = function() {
9519
+ if ( !timerId ) {
9520
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
9521
+ }
9522
+ };
9523
+
9524
+ jQuery.fx.stop = function() {
9525
+ clearInterval( timerId );
9526
+ timerId = null;
9527
+ };
9528
+
9529
+ jQuery.fx.speeds = {
9530
+ slow: 600,
9531
+ fast: 200,
9532
+ // Default speed
9533
+ _default: 400
9534
+ };
9535
+
9536
+ // Back Compat <1.8 extension point
9537
+ jQuery.fx.step = {};
9538
+
9539
+ if ( jQuery.expr && jQuery.expr.filters ) {
9540
+ jQuery.expr.filters.animated = function( elem ) {
9541
+ return jQuery.grep(jQuery.timers, function( fn ) {
9542
+ return elem === fn.elem;
9543
+ }).length;
9544
+ };
9545
+ }
9546
+ jQuery.fn.offset = function( options ) {
9547
+ if ( arguments.length ) {
9548
+ return options === undefined ?
9549
+ this :
9550
+ this.each(function( i ) {
9551
+ jQuery.offset.setOffset( this, options, i );
9552
+ });
9553
+ }
9554
+
9555
+ var docElem, win,
9556
+ box = { top: 0, left: 0 },
9557
+ elem = this[ 0 ],
9558
+ doc = elem && elem.ownerDocument;
9559
+
9560
+ if ( !doc ) {
9561
+ return;
9562
+ }
9563
+
9564
+ docElem = doc.documentElement;
9565
+
9566
+ // Make sure it's not a disconnected DOM node
9567
+ if ( !jQuery.contains( docElem, elem ) ) {
9568
+ return box;
9569
+ }
9570
+
9571
+ // If we don't have gBCR, just use 0,0 rather than error
9572
+ // BlackBerry 5, iOS 3 (original iPhone)
9573
+ if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
9574
+ box = elem.getBoundingClientRect();
9575
+ }
9576
+ win = getWindow( doc );
9577
+ return {
9578
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
9579
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
9580
+ };
9581
+ };
9582
+
9583
+ jQuery.offset = {
9584
+
9585
+ setOffset: function( elem, options, i ) {
9586
+ var position = jQuery.css( elem, "position" );
9587
+
9588
+ // set position first, in-case top/left are set even on static elem
9589
+ if ( position === "static" ) {
9590
+ elem.style.position = "relative";
9591
+ }
9592
+
9593
+ var curElem = jQuery( elem ),
9594
+ curOffset = curElem.offset(),
9595
+ curCSSTop = jQuery.css( elem, "top" ),
9596
+ curCSSLeft = jQuery.css( elem, "left" ),
9597
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
9598
+ props = {}, curPosition = {}, curTop, curLeft;
9599
+
9600
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
9601
+ if ( calculatePosition ) {
9602
+ curPosition = curElem.position();
9603
+ curTop = curPosition.top;
9604
+ curLeft = curPosition.left;
9605
+ } else {
9606
+ curTop = parseFloat( curCSSTop ) || 0;
9607
+ curLeft = parseFloat( curCSSLeft ) || 0;
9608
+ }
9609
+
9610
+ if ( jQuery.isFunction( options ) ) {
9611
+ options = options.call( elem, i, curOffset );
9612
+ }
9613
+
9614
+ if ( options.top != null ) {
9615
+ props.top = ( options.top - curOffset.top ) + curTop;
9616
+ }
9617
+ if ( options.left != null ) {
9618
+ props.left = ( options.left - curOffset.left ) + curLeft;
9619
+ }
9620
+
9621
+ if ( "using" in options ) {
9622
+ options.using.call( elem, props );
9623
+ } else {
9624
+ curElem.css( props );
9625
+ }
9626
+ }
9627
+ };
9628
+
9629
+
9630
+ jQuery.fn.extend({
9631
+
9632
+ position: function() {
9633
+ if ( !this[ 0 ] ) {
9634
+ return;
9635
+ }
9636
+
9637
+ var offsetParent, offset,
9638
+ parentOffset = { top: 0, left: 0 },
9639
+ elem = this[ 0 ];
9640
+
9641
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
9642
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
9643
+ // we assume that getBoundingClientRect is available when computed position is fixed
9644
+ offset = elem.getBoundingClientRect();
9645
+ } else {
9646
+ // Get *real* offsetParent
9647
+ offsetParent = this.offsetParent();
9648
+
9649
+ // Get correct offsets
9650
+ offset = this.offset();
9651
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
9652
+ parentOffset = offsetParent.offset();
9653
+ }
9654
+
9655
+ // Add offsetParent borders
9656
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
9657
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
9658
+ }
9659
+
9660
+ // Subtract parent offsets and element margins
9661
+ // note: when an element has margin: auto the offsetLeft and marginLeft
9662
+ // are the same in Safari causing offset.left to incorrectly be 0
9663
+ return {
9664
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
9665
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
9666
+ };
9667
+ },
9668
+
9669
+ offsetParent: function() {
9670
+ return this.map(function() {
9671
+ var offsetParent = this.offsetParent || docElem;
9672
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
9673
+ offsetParent = offsetParent.offsetParent;
9674
+ }
9675
+ return offsetParent || docElem;
9676
+ });
9677
+ }
9678
+ });
9679
+
9680
+
9681
+ // Create scrollLeft and scrollTop methods
9682
+ jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
9683
+ var top = /Y/.test( prop );
9684
+
9685
+ jQuery.fn[ method ] = function( val ) {
9686
+ return jQuery.access( this, function( elem, method, val ) {
9687
+ var win = getWindow( elem );
9688
+
9689
+ if ( val === undefined ) {
9690
+ return win ? (prop in win) ? win[ prop ] :
9691
+ win.document.documentElement[ method ] :
9692
+ elem[ method ];
9693
+ }
9694
+
9695
+ if ( win ) {
9696
+ win.scrollTo(
9697
+ !top ? val : jQuery( win ).scrollLeft(),
9698
+ top ? val : jQuery( win ).scrollTop()
9699
+ );
9700
+
9701
+ } else {
9702
+ elem[ method ] = val;
9703
+ }
9704
+ }, method, val, arguments.length, null );
9705
+ };
9706
+ });
9707
+
9708
+ function getWindow( elem ) {
9709
+ return jQuery.isWindow( elem ) ?
9710
+ elem :
9711
+ elem.nodeType === 9 ?
9712
+ elem.defaultView || elem.parentWindow :
9713
+ false;
9714
+ }
9715
+ // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
9716
+ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
9717
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
9718
+ // margin is only for outerHeight, outerWidth
9719
+ jQuery.fn[ funcName ] = function( margin, value ) {
9720
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
9721
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
9722
+
9723
+ return jQuery.access( this, function( elem, type, value ) {
9724
+ var doc;
9725
+
9726
+ if ( jQuery.isWindow( elem ) ) {
9727
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
9728
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
9729
+ // https://github.com/jquery/jquery/pull/764
9730
+ return elem.document.documentElement[ "client" + name ];
9731
+ }
9732
+
9733
+ // Get document width or height
9734
+ if ( elem.nodeType === 9 ) {
9735
+ doc = elem.documentElement;
9736
+
9737
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
9738
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
9739
+ return Math.max(
9740
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
9741
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
9742
+ doc[ "client" + name ]
9743
+ );
9744
+ }
9745
+
9746
+ return value === undefined ?
9747
+ // Get width or height on the element, requesting but not forcing parseFloat
9748
+ jQuery.css( elem, type, extra ) :
9749
+
9750
+ // Set width or height on the element
9751
+ jQuery.style( elem, type, value, extra );
9752
+ }, type, chainable ? margin : undefined, chainable, null );
9753
+ };
9754
+ });
9755
+ });
9756
+ // Limit scope pollution from any deprecated API
9757
+ // (function() {
9758
+
9759
+ // The number of elements contained in the matched element set
9760
+ jQuery.fn.size = function() {
9761
+ return this.length;
9762
+ };
9763
+
9764
+ jQuery.fn.andSelf = jQuery.fn.addBack;
9765
+
9766
+ // })();
9767
+ if ( typeof module === "object" && module && typeof module.exports === "object" ) {
9768
+ // Expose jQuery as module.exports in loaders that implement the Node
9769
+ // module pattern (including browserify). Do not create the global, since
9770
+ // the user will be storing it themselves locally, and globals are frowned
9771
+ // upon in the Node module world.
9772
+ module.exports = jQuery;
9773
+ } else {
9774
+ // Otherwise expose jQuery to the global object as usual
9775
+ window.jQuery = window.$ = jQuery;
9776
+
9777
+ // Register as a named AMD module, since jQuery can be concatenated with other
9778
+ // files that may use define, but not via a proper concatenation script that
9779
+ // understands anonymous AMD modules. A named AMD is safest and most robust
9780
+ // way to register. Lowercase jquery is used because AMD module names are
9781
+ // derived from file names, and jQuery is normally delivered in a lowercase
9782
+ // file name. Do this after creating the global so that if an AMD module wants
9783
+ // to call noConflict to hide this version of jQuery, it will work.
9784
+ if ( typeof define === "function" && define.amd ) {
9785
+ define( "jquery", [], function () { return jQuery; } );
9786
+ }
9787
+ }
9788
+
9789
+ })( window );
9790
+ jQuery.noConflict();
9791
+
skin/adminhtml/default/default/affinityengine/main.css ADDED
@@ -0,0 +1,1887 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .aeheader {
2
+ background-color: #374352;
3
+ height: 50px;
4
+ width: 100%;
5
+ }
6
+
7
+ .aelogo {
8
+ background: url(img/logo.png) no-repeat;
9
+ width: 249px;
10
+ height: 80px;
11
+ margin-left: 10px;
12
+ position: absolute;
13
+ cursor: pointer;
14
+ }
15
+
16
+ .items-menu {
17
+ float: right;
18
+ right: 5px;
19
+ top: 85px;
20
+ width: 176px;
21
+ position: absolute;
22
+ z-index: 9999;
23
+ line-height: 30px;
24
+ background: #595959;
25
+ font-size: 14px;
26
+ text-align: center;
27
+ }
28
+
29
+ .radio-style-dark {
30
+ margin-right: 0px !important;
31
+ background-color: #595959 !important;
32
+ }
33
+
34
+ .radio-style-dark label {
35
+ background-color: #6d6d6d !important;
36
+ }
37
+
38
+ .items-menu ul {
39
+ color: #fff;
40
+ list-style: none;
41
+ margin: 0;
42
+ padding: 0;
43
+ }
44
+
45
+ .items-menu ul li {
46
+ color: #fff;
47
+ }
48
+
49
+ .items-icon-top-menu {
50
+ background: url(../img/top-menu.png) no-repeat;
51
+ height: 18px;
52
+ width: 37px;
53
+ position: absolute;
54
+ top: -18px;
55
+ right: 13px;
56
+ }
57
+
58
+ .items-icon-menu {
59
+ background: url(../img/menu.png) no-repeat;
60
+ height: 40px;
61
+ width: 56px;
62
+ float: right;
63
+ margin-top: 20px;
64
+ cursor: pointer;
65
+ }
66
+
67
+ .items-right {
68
+ float: right;
69
+ }
70
+
71
+ .items-left {
72
+ float: left;
73
+ }
74
+
75
+ .items-hide {
76
+ display: none;
77
+ }
78
+
79
+ .items-wrapper {
80
+ width: 925px;
81
+ margin: 0 auto;
82
+ border: 1px solid #bdc3c7;
83
+ position: relative;
84
+ }
85
+
86
+ .ae-cgv {
87
+ color: #585A69 !important;
88
+ margin-bottom: 20px;
89
+ margin-top: 10px;
90
+ font-size: 13px;
91
+ }
92
+
93
+ .items-auth-zone {
94
+ font-size: 17px;
95
+ color: #585A69;
96
+ }
97
+
98
+ .items-auth-zone p {
99
+ margin: 0.5em 0 !important;
100
+ }
101
+
102
+ .items-auth-register {
103
+ margin-top: 25px;
104
+ }
105
+
106
+ .items-auth-zone h3 {
107
+ color: #79478b;
108
+ }
109
+
110
+ .items-auth-presentation {
111
+ width: 50%;
112
+ height: 500px;
113
+ background: #f2f2f2;
114
+ }
115
+
116
+ .items-auth-presentation-block {
117
+ height: 170px;
118
+ }
119
+
120
+ .items-auth-presentation-block-middle {
121
+ margin-top: 10px;
122
+ }
123
+
124
+ .items-auth-presentation img {
125
+ width: 20%;
126
+ float: left;
127
+ margin-top: 20px;
128
+ }
129
+
130
+ .items-auth-presentation ul {
131
+ list-style: initial;
132
+ float: right;
133
+ width: 235px;
134
+ text-align: justify;
135
+ margin-right: 40px;
136
+ }
137
+
138
+ .items-auth-presentation h3 {
139
+ padding: 0;
140
+ margin-top: 0;
141
+ margin-bottom: 10px;
142
+ }
143
+
144
+ .items-auth-presentation-content {
145
+ margin-top: 25px;
146
+ text-align: center;
147
+ }
148
+
149
+ .items-red-button {
150
+ border-image-source: initial;
151
+ border-image-slice: initial;
152
+ border-image-width: initial;
153
+ border-image-outset: initial;
154
+ border-image-repeat: initial;
155
+ display: inline;
156
+ cursor: pointer;
157
+ background-color: rgb(229, 77, 66) !important;
158
+ color: rgb(255, 255, 255);
159
+ }
160
+
161
+ .items-auth-container {
162
+ width: 50%;
163
+ height: 500px;
164
+ margin: 0;
165
+ text-align: center;
166
+ padding: 0;
167
+ }
168
+
169
+ .items-auth-container a {
170
+ color: #585A69 !important;
171
+ font-weight: bold;
172
+ }
173
+
174
+
175
+ .items-auth-container select {
176
+ max-width: 160px;
177
+ }
178
+
179
+ .items-auth-switch {
180
+ color: #604a7b !important;
181
+ background-color: white;
182
+ font-family: Arial, Helvetica, sans-serif;
183
+ font-weight: 700;
184
+ text-decoration: underline;
185
+ border: 1px transparent solid !important;
186
+ margin-bottom: 10px !important;
187
+ border-radius: 0;
188
+ display: inline-block;
189
+ text-align: center;
190
+ padding-right: 10px !important;
191
+ padding-top: 5px !important;
192
+ padding-bottom: 5px !important;
193
+ cursor: pointer !important;
194
+ padding-left: 10px !important;
195
+ position: relative;
196
+ }
197
+
198
+ .items-button {
199
+ color: white !important;
200
+ -webkit-border-radius: 7px !important;
201
+ -moz-border-radius: 7px !important;
202
+ border-radius: 7px !important;
203
+ min-width: 220px !important;
204
+ border: 1px transparent solid !important;
205
+ margin-bottom: 10px !important;
206
+ display: inline-block !important;
207
+ text-align: center !important;
208
+ font-size: 20px !important;
209
+ cursor: pointer !important;
210
+ padding: 10px !important;
211
+ }
212
+
213
+ .items-green {
214
+ background-color: #82c836;
215
+ }
216
+
217
+ .items-purple {
218
+ background-color: #774e92;
219
+ }
220
+
221
+ .items-grey {
222
+ background-color: #d9d9d9;
223
+ border: 1px solid #989898;
224
+ color: #989898;
225
+ }
226
+
227
+ .items-login-container {
228
+ display: none;
229
+ margin-top: 15% !important;
230
+ width: 210px;
231
+ margin: 0 auto;
232
+ background: #fff;
233
+ border: 1px solid #bdc3c7;
234
+ border-bottom-width: 6px;
235
+ padding: 10px 39px 19px;
236
+ -webkit-border-radius: 5px;
237
+ -moz-border-radius: 8px;
238
+ border-radius: 0px;
239
+ -moz-box-shadow: 0 0 6px #999;
240
+ text-align: center;
241
+ }
242
+
243
+ .items-login-container h3 {
244
+ color: #604a7b;
245
+ }
246
+
247
+ .items-register-container h3 {
248
+ color: #604a7b;
249
+ }
250
+
251
+ .ae-cgv a {
252
+ color: #268CCD !important;
253
+ text-decoration: underline !important;
254
+ }
255
+
256
+ .items-login-container input {
257
+ height: 25px;
258
+ margin-top: 10px;
259
+ }
260
+
261
+ .items-register-container {
262
+ width: 210px;
263
+ margin: 45px auto;
264
+ text-align: center;
265
+ display: block;
266
+ }
267
+
268
+ .items-register-container input[type=text],
269
+ .items-register-container input[type=password],
270
+ .items-register-container select {
271
+ height: 25px;
272
+ width: 210px;
273
+ -webkit-border-radius: 7px;
274
+ -moz-border-radius: 7px;
275
+ font-size: 17px;
276
+ border-radius: 7px;
277
+ margin-top: 12px;
278
+ margin-bottom: 12px;
279
+ }
280
+
281
+ .items-register-container input[type="text"], .items-register-container input[type="password"], .items-register-container input[type="file"], .items-register-container textarea {
282
+ border: 1px solid #ccc;
283
+ background-color: #fff;
284
+ }
285
+
286
+ .items-header {
287
+ background: #774e92;
288
+ height: 80px;
289
+ width: 875px;
290
+ color: white;
291
+ font-size: 1.8em;
292
+ line-height: 50px;
293
+ padding: 0 25px;
294
+ }
295
+
296
+ .items-tabs {
297
+ height: 30px;
298
+ width: 100%;
299
+ background: #ecf0f1;
300
+ border-bottom: 1px solid #bdc3c7;
301
+ border-top: 1px solid #bdc3c7;
302
+ }
303
+
304
+ .items-tab {
305
+ display: inline-block;
306
+ float: left;
307
+ height: 30px;
308
+ width: 120px;
309
+ line-height: 30px;
310
+ text-align: center;
311
+ border: 1px solid #bdc3c7;
312
+ border-top: 0;
313
+ border-left: 0;
314
+ color: #7f8c8d;
315
+ padding: 0 20px;
316
+ background: #ecf0f1;
317
+ cursor: pointer;
318
+ }
319
+
320
+ .items-support {
321
+ background: #d9534f;
322
+ float: right;
323
+ color: white;
324
+ }
325
+
326
+ .items-first-tab {
327
+ border-left: 0 solid;
328
+ }
329
+
330
+ .items-tab.active {
331
+ border-bottom: 0 solid;
332
+ height: 31px;
333
+ background: white;
334
+ }
335
+
336
+ .items-explain {
337
+ background: #604a7b !important;
338
+ color: white !important;
339
+ padding: 50px 30px;
340
+ height: 230px !important;
341
+ font-size: 1.1em;
342
+ width: 875px !important;
343
+ }
344
+
345
+ .items-explain-description {
346
+ display: inline-block;
347
+ float: left;
348
+ width: 52%;
349
+ text-align: justify;
350
+ height: 100%;
351
+ line-height: 19px;
352
+ }
353
+
354
+ .items-checked {
355
+ background: url(../img/checked.png) no-repeat;
356
+ font-size: 1.2em;
357
+ padding-left: 30%;
358
+ margin-bottom: 20px;
359
+ text-align: left;
360
+ }
361
+
362
+ .items-loading {
363
+ background: url(../img/loading.gif) no-repeat;
364
+ font-size: 1.2em;
365
+ padding-left: 30%;
366
+ margin-bottom: 20px;
367
+ text-align: left;
368
+ }
369
+
370
+ .items-explain-description p {
371
+ color: white;
372
+ margin-top: 0px;
373
+ margin-bottom: 0px;
374
+ }
375
+
376
+ .items-explain-image img {
377
+ position: absolute;
378
+ top: 20px;
379
+ right: 100px;
380
+ }
381
+
382
+ .items-video {
383
+ text-align: center;
384
+ margin-top: 25px;
385
+ margin-bottom: 25px;
386
+ }
387
+
388
+ .items-video a {
389
+ color: white;
390
+ text-decoration: underline;
391
+ }
392
+
393
+ .items-video-installation {
394
+ display: none;
395
+ }
396
+
397
+ .items-video-installation-text {
398
+ display: none;
399
+ }
400
+
401
+ .items-content {
402
+
403
+ }
404
+
405
+ .items-title {
406
+ margin: 20px 30px;
407
+ padding: 10px 10px;
408
+ font-size: 1.5em;
409
+ font-weight: bold;
410
+ color: #604a7b;
411
+ border-bottom: 1px solid #7f8c8d;
412
+ }
413
+
414
+ /*
415
+ .items-box {
416
+ position: relative;
417
+ background: #ecf0f1;
418
+ border: 1px solid #bdc3c7;
419
+ border-bottom-width: 6px;
420
+ border-radius: 2px;
421
+ margin: 10px 0 20px 15px;
422
+ height: 300px;
423
+ width: 280px;
424
+ display: inline-block;
425
+ float: left;
426
+ }
427
+ */
428
+
429
+ .items-boxes {
430
+ display: block;
431
+ margin-left: 15px;
432
+ height: 350px;
433
+ }
434
+
435
+ .items-stat .items-box-title {
436
+ height: 54px;
437
+ }
438
+
439
+ .items-stat-message {
440
+ color: #1f497d;
441
+ font-size: 1.9em;
442
+ line-height: 2em;
443
+ font-weight: bold;
444
+ }
445
+
446
+ .items-box-title {
447
+ padding: 20px 10px 10px 10px;
448
+ font-size: 1.5em;
449
+ color: #604a7b;
450
+ text-align: center;
451
+ }
452
+
453
+ .items-box-content {
454
+ padding: 10px;
455
+ text-align: center;
456
+ }
457
+
458
+ .items-box-content input {
459
+ width: 225px;
460
+ padding: 5px;
461
+ margin: 5px 5px 25px 5px;
462
+ border: 1px solid #7f8c8d;
463
+ border-radius: 5px;
464
+ font-size: 2em;
465
+ color: #1f497d;
466
+ text-align: center;
467
+ }
468
+
469
+ #content-config .items-box-content input[type=csheckbox] {
470
+ display:none;
471
+ }
472
+
473
+ #content-config .items-box-content label {
474
+ color: #585a69;
475
+ text-shadow: 0 1px 0#fff;
476
+ text-align: center;
477
+ width: 100%;
478
+ line-height: 2.5;
479
+ }
480
+
481
+ #content-config .items-box-content input[type=checkbox] + label:before {
482
+ content: "";
483
+ display: inline-block;
484
+ width: 15px;
485
+ height: 15px;
486
+ vertical-align:middle;
487
+ margin-right: 8px;
488
+ background-color: #aaa;
489
+ box-shadow: inset 0px 2px 2px rgba(0, 0, 0, .3);
490
+ border-radius: 4px;
491
+ }
492
+
493
+ #content-config .items-box-content input[type=checkbox]:checked + label:before {
494
+ content:"\2714";
495
+ color:white;
496
+ background-color: #666;
497
+ text-align:center;
498
+ line-height:15px;
499
+ text-shadow:0px 0px 3px #eee;
500
+ }
501
+
502
+ #content-config .items-box {
503
+ height: 220px !important;
504
+ margin-left: 23px;
505
+ }
506
+
507
+ .items-box-description {
508
+ text-align: justify;
509
+ color: #758384;
510
+ font-size: 0.95em;
511
+ padding: 10px;
512
+ margin-bottom: 15px;
513
+ background: white;
514
+ border-radius: 3px;
515
+ border: 1px solid #bdc3c7;
516
+ }
517
+
518
+ .items-button-submit {
519
+ color: white !important;
520
+ background-color: #604a7b;
521
+ font-family: Arial, Helvetica, sans-serif;
522
+ font-weight: 700;
523
+ font-size: 14px !important;
524
+ min-width: 105px;
525
+ min-height: 32px;
526
+ height: 32px;
527
+ border: 1px transparent solid !important;
528
+ margin-bottom: 10px !important;
529
+ margin-left: 10px !important;
530
+ margin-right: 10px !important;
531
+ border-radius: 0;
532
+ display: inline-block;
533
+ text-align: center;
534
+ cursor: pointer;
535
+ padding: 4px 10px !important;
536
+ position: relative;
537
+ outline: none;
538
+ margin-right: 25px;
539
+ }
540
+
541
+ .items-sync-diff {
542
+ width: 80px !important;
543
+ }
544
+
545
+ .items-box-description.notactivate {
546
+ color: white;
547
+ background: #d9534f;
548
+ }
549
+
550
+ .items-third-stat {
551
+ color: #758384;
552
+ font-size: 1.35em;
553
+ }
554
+
555
+ .items-second-stat {
556
+ color: #1f497d;
557
+ font-size: 1.35em;
558
+ }
559
+
560
+ .items-main-stat {
561
+ color: #1f497d;
562
+ font-size: 1.9em;
563
+ line-height: 2em;
564
+ font-weight: bold;
565
+ }
566
+
567
+ #slider {
568
+ margin: 0 15px;
569
+ background: #604a7b;
570
+ }
571
+
572
+ #input-number {
573
+ width: 75px;
574
+ padding: 5px;
575
+ margin: 5px 5px 25px 5px;
576
+ border: 1px solid #7f8c8d;
577
+ border-radius: 5px;
578
+ font-size: 2em;
579
+ color: #1f497d;
580
+ text-align: center;
581
+ }
582
+
583
+ .items-button-plus {
584
+ background: #26A65B;
585
+ margin: 0 auto;
586
+ cursor: pointer;
587
+ border: none;
588
+ padding: 0px 13px;
589
+ width: 69px;
590
+ height: 30px;
591
+ color: white;
592
+ border-radius: 3px;
593
+ }
594
+
595
+ .items-box-footer {
596
+ position: absolute;
597
+ bottom: 15px;
598
+ left: 0;
599
+ width: 100%;
600
+ }
601
+
602
+ .items-detail {
603
+ color: #7f8c8d;
604
+ text-decoration: underline;
605
+ text-align: center;
606
+ cursor: pointer;
607
+ }
608
+
609
+ .items-line {
610
+ width: 835px !important;
611
+ }
612
+
613
+ .items-line .items-line-item {
614
+ width: 300px;
615
+ height: 220px;
616
+ display: inline-block;
617
+ float: left;
618
+ position: relative;
619
+ margin-right: 10px;
620
+ }
621
+
622
+ .items-line .items-box-footer {
623
+ bottom: -70px;
624
+ }
625
+
626
+ .items-box label {
627
+ float: none !important;
628
+ }
629
+
630
+ .items-list {
631
+ background: white;
632
+ border: 1px solid #7f8c8d;
633
+ border-radius: 2px;
634
+ margin: 0 10px 0 35px;
635
+ padding: 5px;
636
+ height: 200px;
637
+ overflow: auto;
638
+ }
639
+
640
+ .items-item {
641
+ border: 1px solid #7f8c8d;
642
+ border-radius: 3px;
643
+ padding: 5px 0;
644
+ width: 150px;
645
+ background: #ecf0f1;
646
+ margin: 10px auto;
647
+ }
648
+
649
+ .items-item.whitelist {
650
+ background: #27ae60;
651
+ border: none;
652
+ color: white;
653
+ }
654
+
655
+ .items-item.blacklist {
656
+ background: #d9534f;
657
+ border: none;
658
+ color: white;
659
+ }
660
+
661
+ .clear {
662
+ clear: both;
663
+ }
664
+
665
+ .grow {
666
+ -webkit-transition-duration: 0.5s;
667
+ transition-duration: 0.5s;
668
+ -webkit-transition-property: transform;
669
+ transition-property: transform;
670
+ -webkit-transform: translateZ(0);
671
+ transform: translateZ(0);
672
+ box-shadow: 0 0 1px rgba(0, 0, 0, 0);
673
+ }
674
+
675
+ .grow:hover, .grow:focus, .grow:active {
676
+ -webkit-transform: scale(1.2);
677
+ transform: scale(1.2);
678
+ }
679
+
680
+ .onoffswitch {
681
+ margin: 30px auto;
682
+ position: relative; width: 115px;
683
+ -webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
684
+ }
685
+
686
+ .onoffswitch-checkbox {
687
+ display: none;
688
+ }
689
+
690
+ .onoffswitch-label {
691
+ display: block;
692
+ overflow: hidden;
693
+ cursor: pointer;
694
+ border: 2px solid #999999;
695
+ border-radius: 20px;
696
+ text-align: left !important;
697
+ width: auto !important;
698
+ float: none !important;
699
+ padding: 0 !important;
700
+ }
701
+
702
+ .onoffswitch-inner {
703
+ display: block; width: 200%; margin-left: -100%;
704
+ -moz-transition: margin 0.3s ease-in 0s; -webkit-transition: margin 0.3s ease-in 0s;
705
+ -o-transition: margin 0.3s ease-in 0s; transition: margin 0.3s ease-in 0s;
706
+ }
707
+
708
+ .onoffswitch-inner:before, .onoffswitch-inner:after {
709
+ display: block; float: left; width: 50%; height: 40px; padding: 0; line-height: 40px;
710
+ font-size: 25px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
711
+ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
712
+ }
713
+
714
+ .onoffswitch-inner:before {
715
+ content: "ON";
716
+ padding-left: 12px;
717
+ background-color: #83c937;
718
+ color: #FFFFFF;
719
+ }
720
+
721
+ .onoffswitch-inner:after {
722
+ content: "OFF";
723
+ padding-right: 12px;
724
+ background-color: #FFFFFF; color: #999999;
725
+ text-align: right;
726
+ }
727
+
728
+ .onoffswitch-switch {
729
+ display: block; width: 30px; margin: 5px;
730
+ background: #FFFFFF;
731
+ border: 2px solid #999999; border-radius: 20px;
732
+ position: absolute; top: 0; bottom: 0; right: 71px;
733
+ -moz-transition: all 0.3s ease-in 0s; -webkit-transition: all 0.3s ease-in 0s;
734
+ -o-transition: all 0.3s ease-in 0s; transition: all 0.3s ease-in 0s;
735
+ }
736
+
737
+ .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
738
+ margin-left: 0;
739
+ }
740
+
741
+ .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
742
+ right: 0px;
743
+ }
744
+
745
+ .ae-log {
746
+ font-weight: bold;
747
+ max-height: 200px;
748
+ width: 85%;
749
+ margin-left: 44px;
750
+ text-align: justify;
751
+ margin-bottom: 0px;
752
+ margin-top: 15px;
753
+ padding: 5px 25px 5px 25px;
754
+ -webkit-border-radius: 10px;
755
+ -moz-border-radius: 10px;
756
+ border-radius: 10px;
757
+ }
758
+
759
+ .ae-log.ae-info {
760
+ background-color: #fcf8e3;
761
+ border-color: #faebcc;
762
+ color: #8a6d3b;
763
+ }
764
+
765
+ .items-alert {
766
+ background-color: #f2dede;
767
+ border-color: #ebccd1;
768
+ color: #a94442;
769
+ width: 95%;
770
+ margin-left: 15px;
771
+ margin-top: 10px;
772
+ padding: 10px 10px 10px 10px;
773
+ line-height: 1.3;
774
+ border: 1px solid #CA706E;
775
+ }
776
+
777
+ .items-success {
778
+ color: #3c763d;
779
+ background-color: #dff0d8;
780
+ width: 95%;
781
+ margin-left: 15px;
782
+ margin-top: 10px;
783
+ padding: 10px 10px 10px 10px;
784
+ line-height: 1.3;
785
+ border: 1px solid #d6e9c6;
786
+ }
787
+
788
+ .ae-log.ae-alert {
789
+ background-color: #f2dede;
790
+ border-color: #ebccd1;
791
+ color: #a94442;
792
+ }
793
+
794
+ .zone-config {
795
+ min-height: 235px;
796
+ display: block;
797
+ }
798
+
799
+ .zone-config a {
800
+ color: #268CCD !important;
801
+ font-weight: bold;
802
+ }
803
+
804
+ .zone {
805
+ position: relative;
806
+ border: 2px solid #E0E0E0;
807
+ border-radius: 2px;
808
+ width: 93%;
809
+ -webkit-border-radius: 15px;
810
+ -moz-border-radius: 15px;
811
+ border-radius: 15px;
812
+ margin: 10px 15px 15px 15px;
813
+ padding: 15px;
814
+ display: inline-block;
815
+ float: left;
816
+ }
817
+
818
+ .zone-tabs {
819
+ margin: 5px 15px 0 15px;
820
+ }
821
+
822
+ .zone-tab {
823
+ display: inline-block;
824
+ float: left;
825
+ width: 85px;
826
+ background: #ecf0f1;
827
+ border: 1px solid #bdc3c7;
828
+ border-bottom-width: 6px;
829
+ border-radius: 2px;
830
+ margin-right: 10px;
831
+ padding: 5px 15px;
832
+ cursor: pointer;
833
+ }
834
+
835
+ .zone-tab-selected {
836
+ color: #604a7b;
837
+ font-weight: bold;
838
+ border: 1px solid rgb(96, 74, 123);
839
+ border-bottom-width: 6px;
840
+ }
841
+
842
+ .zone-tab i {
843
+ font-size: 0.85em
844
+ }
845
+
846
+ .zone-tab .lightfire {
847
+ color: #D91E18;
848
+ font-size: 0.85em;
849
+ float: right;
850
+ line-height: 1em;
851
+ margin-top: 2px;
852
+ }
853
+
854
+ .zone-tab .lightfire.on {
855
+ color: #00B16A;
856
+ }
857
+
858
+ .zone .one,
859
+ .zone .two {
860
+ display: inline-block;
861
+ width: 100%;
862
+ float: left;
863
+ margin-bottom: 10px;
864
+ margin-top: 10px;
865
+ }
866
+
867
+ .items-wrapper a {
868
+ color: #fff;
869
+ text-decoration: none;
870
+ }
871
+
872
+ .items-wrapper select {
873
+ margin: 10px 0 !important;
874
+ vertical-align: initial !important;
875
+ height: 33px;
876
+ width: 215px;
877
+ background-color: white;
878
+ }
879
+
880
+ .zone .one .position-options > label,
881
+ .zone .two .position-options > label {
882
+ display: inline-block;
883
+ float: left;
884
+ line-height: 36px;
885
+ margin: 5px 5px 5px 25px;
886
+ width: 46px;
887
+ font-weight: initial !important;
888
+ }
889
+
890
+ .zone .one .position-options > select,
891
+ .zone .two .position-options > select {
892
+ display: inline-block;
893
+ float: left;
894
+ margin: 5px 0;
895
+ }
896
+
897
+ .toolboxarea .title,
898
+ .zone .title {
899
+ color: #774e92;
900
+ font-weight: bold;
901
+ height: 50px;
902
+ font-size: 1.4em;
903
+ }
904
+
905
+ .items-theme-selector {
906
+ width: 90%;
907
+ position: relative;
908
+ margin-left: 15px;
909
+ background: #ecf0f1;
910
+ border: 1px solid #bdc3c7;
911
+ height: 40px;
912
+ border-bottom-width: 6px;
913
+ border-radius: 2px;
914
+ padding: 15px;
915
+ }
916
+
917
+ .items-theme-selector-content {
918
+ width: 70%;
919
+ float: left;
920
+ font-size: 15px;
921
+ line-height: 2;
922
+ width: 830px;
923
+ }
924
+
925
+ .items-theme-selector-content .items-button-submit {
926
+ margin-top: 9px;
927
+ margin-left: -2px !important;
928
+ }
929
+
930
+ .items-theme-selector-content select {
931
+ width: 130px;
932
+ margin-top: 7px !important;
933
+ }
934
+
935
+ .items-new-theme-input {
936
+ background: white;
937
+ border-radius: 10px;
938
+ border: 2px solid #999999;
939
+ padding: 5px;
940
+ max-width: 150px;
941
+ height: 20px;
942
+ }
943
+
944
+ .items-register-theme {
945
+ float: right;
946
+ display: none;
947
+ margin-top: 7px;
948
+ }
949
+
950
+ .zone .onoffswitch {
951
+ margin: 7px 0;
952
+ float: left;
953
+ display: inline-block;
954
+ position: relative; width: 60px;
955
+ -webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
956
+ }
957
+
958
+ .zone .onoffswitch-checkbox {
959
+ display: none;
960
+ }
961
+
962
+ .zone .onoffswitch-label {
963
+ display: block; overflow: hidden; cursor: pointer;
964
+ border: 1px solid #999999; border-radius: 10px;
965
+ }
966
+
967
+ .zone .onoffswitch-inner {
968
+ display: block; width: 200%; margin-left: -100%;
969
+ -moz-transition: margin 0.3s ease-in 0s; -webkit-transition: margin 0.3s ease-in 0s;
970
+ -o-transition: margin 0.3s ease-in 0s; transition: margin 0.3s ease-in 0s;
971
+ }
972
+
973
+ .zone .onoffswitch-inner:before, .zone .onoffswitch-inner:after {
974
+ display: block; float: left; width: 50%; height: 30px; padding: 0; line-height: 30px;
975
+ font-size: 11px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
976
+ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
977
+ }
978
+
979
+ .zone .onoffswitch-inner:before {
980
+ content: "ON";
981
+ padding-left: 5px;
982
+ background-color: #83c937;
983
+ color: #FFFFFF;
984
+ }
985
+
986
+ .zone .onoffswitch-inner:after {
987
+ content: "OFF";
988
+ padding-right: 5px;
989
+ background-color: #FFFFFF; color: #999999;
990
+ text-align: right;
991
+ }
992
+
993
+ .zone .onoffswitch-switch {
994
+ display: block; width: 15px; margin: 7.5px;
995
+ background: #FFFFFF;
996
+ border: 2px solid #999999; border-radius: 20px;
997
+ position: absolute; top: 0; bottom: 0; right: 26px;
998
+ -moz-transition: all 0.3s ease-in 0s; -webkit-transition: all 0.3s ease-in 0s;
999
+ -o-transition: all 0.3s ease-in 0s; transition: all 0.3s ease-in 0s;
1000
+ }
1001
+
1002
+ .zone .onoffswitch-checkbox:checked + .zone .onoffswitch-label .zone .onoffswitch-inner {
1003
+ margin-left: 0;
1004
+ }
1005
+
1006
+ .zone .onoffswitch-checkbox:checked + .zone .onoffswitch-label .zone .onoffswitch-switch {
1007
+ right: 0px;
1008
+ }
1009
+
1010
+ .preview {
1011
+ margin: 15px;
1012
+ }
1013
+
1014
+ .preview > div {
1015
+ display: inline-block;
1016
+ float: left;
1017
+ vertical-align: top;
1018
+ min-height: 415px;
1019
+ }
1020
+
1021
+ .preview .toolbox {
1022
+ width: 30%;
1023
+ position: relative;
1024
+ background: #ecf0f1;
1025
+ border: 1px solid #bdc3c7;
1026
+ border-bottom-width: 6px;
1027
+ border-radius: 2px;
1028
+ padding: 15px;
1029
+ }
1030
+
1031
+ .preview .toolbox .items-conf {
1032
+ height: 60px;
1033
+ }
1034
+
1035
+ .preview .toolbox button {
1036
+ padding: 10px 15px;
1037
+ height: 35px;
1038
+ width: 150px;
1039
+ background: none;
1040
+ border-radius: 4px;
1041
+ cursor: pointer;
1042
+ color: white;
1043
+ background: #604a7b;
1044
+ text-align: left;
1045
+ position: relative;
1046
+ border: none;
1047
+ }
1048
+
1049
+ .preview .toolbox button .arrow {
1050
+ float: right;
1051
+ font-weight: bold;
1052
+ font-size: 1.2em;
1053
+ }
1054
+
1055
+ .preview .preview-area {
1056
+ width: 60%;
1057
+ padding: 25px;
1058
+ padding-top: 0px;
1059
+ }
1060
+
1061
+ .preview .preview-area .reco {
1062
+ width: 100%;
1063
+ height: 450px;
1064
+ margin-top: -25px;
1065
+ background: #ecf0f1;
1066
+ }
1067
+
1068
+ .preview .preview-area .product {
1069
+ display: inline-block;
1070
+ float: left;
1071
+ vertical-align: middle;
1072
+ margin: 15px;
1073
+ padding: 15px 20px;
1074
+ background: white;
1075
+ border: 1px solid #95a5a6;
1076
+ border-bottom-width: 2px;
1077
+ border-radius: 2px;
1078
+ height: 350px;
1079
+ width: 37%;
1080
+ }
1081
+
1082
+ .product .title {
1083
+ margin: 15px 0;
1084
+ font-size: 1.5em;
1085
+ font-weight: bold;
1086
+ }
1087
+
1088
+ .product img {
1089
+ display: block;
1090
+ margin: 0 auto;
1091
+ }
1092
+
1093
+ .product .price {
1094
+ text-align: center;
1095
+ margin: 10px 0;
1096
+ }
1097
+
1098
+ .preview .onoffswitch {
1099
+ margin: 0 10px;
1100
+ display: inline-block;
1101
+ position: relative; width: 40px;
1102
+ -webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
1103
+ }
1104
+
1105
+ .preview .onoffswitch-checkbox {
1106
+ display: none;
1107
+ }
1108
+
1109
+ .preview .onoffswitch-label {
1110
+ display: block; overflow: hidden; cursor: pointer;
1111
+ border: 2px solid #999999; border-radius: 5px;
1112
+ }
1113
+
1114
+ .preview .onoffswitch-inner {
1115
+ display: block; width: 200%; margin-left: -100%;
1116
+ -moz-transition: margin 0.3s ease-in 0s; -webkit-transition: margin 0.3s ease-in 0s;
1117
+ -o-transition: margin 0.3s ease-in 0s; transition: margin 0.3s ease-in 0s;
1118
+ }
1119
+
1120
+ .preview .onoffswitch-inner:before, .preview .onoffswitch-inner:after {
1121
+ display: block; float: left; width: 50%; height: 10px; padding: 0; line-height: 10px;
1122
+ font-size: 10px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
1123
+ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
1124
+ }
1125
+
1126
+ .preview .onoffswitch-inner:before {
1127
+ content: "";
1128
+ padding-left: 5px;
1129
+ background-color: #604A7B; color: #FFFFFF;
1130
+ }
1131
+
1132
+ .preview .onoffswitch-inner:after {
1133
+ content: "";
1134
+ padding-right: 5px;
1135
+ background-color: #EEEEEE; color: #FFFFFF;
1136
+ text-align: right;
1137
+ }
1138
+
1139
+ .preview .onoffswitch-switch {
1140
+ display: block; width: 25px; margin: -7.5px;
1141
+ background: #FFFFFF;
1142
+ border: 2px solid #999999; border-radius: 5px;
1143
+ position: absolute; top: 0; bottom: 0; right: 26px;
1144
+ -moz-transition: all 0.3s ease-in 0s; -webkit-transition: all 0.3s ease-in 0s;
1145
+ -o-transition: all 0.3s ease-in 0s; transition: all 0.3s ease-in 0s;
1146
+ }
1147
+
1148
+ .preview .onoffswitch-checkbox:checked + .preview .onoffswitch-label .preview .onoffswitch-inner {
1149
+ margin-left: 0;
1150
+ }
1151
+
1152
+ .preview .onoffswitch-checkbox:checked + .preview .onoffswitch-label .preview .onoffswitch-switch {
1153
+ right: 0px;
1154
+ }
1155
+
1156
+ .back,
1157
+ .visit {
1158
+ color: #8b959c;
1159
+ font-size: 0.6em;
1160
+ float: right;
1161
+ cursor: pointer;
1162
+ font-weight: normal;
1163
+ line-height: 32px;
1164
+ vertical-align: bottom;
1165
+ margin-right: 15px;
1166
+ }
1167
+
1168
+ .back {
1169
+ font-size: 1.8em;
1170
+ }
1171
+
1172
+ .toolboxarea label {
1173
+ padding: 0 !important;
1174
+ float: none !important;
1175
+ text-align: left !important;
1176
+ }
1177
+
1178
+ .preview-area input {
1179
+ margin-top: 50px;
1180
+ margin-right: 0px !important;
1181
+ }
1182
+
1183
+ .items-config-title {
1184
+ width: 100%;
1185
+ height: 50px;
1186
+ color: #8b959c;
1187
+ line-height: 2;
1188
+ font-weight: bold;
1189
+ font-size: 1.4em;
1190
+ }
1191
+
1192
+ .items-config-title .items-button-submit {
1193
+ margin-left: 0px !important;
1194
+ margin-right: 0px !important;
1195
+ }
1196
+
1197
+ .preview-area h4 {
1198
+ margin-top: 0px;
1199
+ }
1200
+
1201
+ .ae-number-reco-label {
1202
+ width: 175px !important;
1203
+ margin-left: 10px !important;
1204
+ }
1205
+
1206
+ .ae-number-reco-input {
1207
+ margin: 10px 0 !important;
1208
+ vertical-align: initial !important;
1209
+ width: 55px;
1210
+ height: 25px;
1211
+ text-align: center;
1212
+ background-color: white;
1213
+ }
1214
+
1215
+ .ae-type-recommendation-select {
1216
+ max-width: 265px !important;
1217
+ }
1218
+
1219
+ .items-reco-all-filtered {
1220
+ display: none;
1221
+ margin: 10px 0px 10px 0px;
1222
+ }
1223
+
1224
+ .items-reco-all-filtered select {
1225
+ max-width: 145px !important;
1226
+ }
1227
+
1228
+ .categoryIds {
1229
+ display: none;
1230
+ padding-top: 10px;
1231
+ font-weight: bold;
1232
+ }
1233
+
1234
+ .attributeIds {
1235
+ display: none;
1236
+ padding-top: 10px;
1237
+ font-weight: bold;
1238
+ }
1239
+
1240
+ .featureIds {
1241
+ display: none;
1242
+ padding-top: 10px;
1243
+ font-weight: bold;
1244
+ }
1245
+
1246
+ .items-display {
1247
+ display: block;
1248
+ }
1249
+
1250
+ .items-css-text-area {
1251
+ width: 93%;
1252
+ margin-left: 3% !important;
1253
+ margin-bottom: 25px !important;
1254
+ min-height: 420px;
1255
+ }
1256
+
1257
+ .items-hr {
1258
+ width: 100%;
1259
+ margin: 0 auto;
1260
+ border-bottom: 1px solid grey;
1261
+ height: 1px;
1262
+ }
1263
+
1264
+ .items-selectors-label {
1265
+ width: 100px !important;
1266
+ margin-left: 0px !important;
1267
+ }
1268
+
1269
+ .items-selectors-input {
1270
+ display: inline-block;
1271
+ margin: 10px 0 !important;
1272
+ vertical-align: initial !important;
1273
+ height: 25px;
1274
+ width: 200px;
1275
+ }
1276
+
1277
+ .items-wrapper .position {
1278
+ font-size: 15px;
1279
+ margin-bottom: 20px;
1280
+ }
1281
+
1282
+
1283
+ .items-selectors-position {
1284
+ width: 70px !important;
1285
+ margin-left: 0px !important;
1286
+ }
1287
+
1288
+ .items-selectors-select {
1289
+ display: inline-block;
1290
+ float: left;
1291
+ margin: 10px 0;
1292
+ border-radius: 6px;
1293
+ height: 25px;
1294
+ }
1295
+
1296
+ .items-tab.items-support.active {
1297
+ background: #d9534f !important;
1298
+ }
1299
+
1300
+ .items-support-description {
1301
+ background: #ecf0f1;
1302
+ border: 1px solid #bdc3c7;
1303
+ min-height: 125px;
1304
+ text-align: justify;
1305
+ margin: 0 auto;
1306
+ display: block;
1307
+ margin-left: 25px;
1308
+ margin-right: 25px;
1309
+ color: #323232;
1310
+ margin-top: 30px;
1311
+ margin-bottom: 60px;
1312
+ padding: 20px 20px 20px 20px;
1313
+ }
1314
+
1315
+ .items-support-description ul {
1316
+ list-style: initial;
1317
+ margin-left: 35px;
1318
+ line-height: 25px;
1319
+ }
1320
+
1321
+ .items-manager-button {
1322
+ color: transparent !important;
1323
+ }
1324
+
1325
+ .ae-info-auth {
1326
+ font-weight: bold;
1327
+ background-color: #fcf8e3;
1328
+ border-color: #faebcc;
1329
+ color: #8a6d3b;
1330
+ padding-left: 35px;
1331
+ width: 93%;
1332
+ line-height: 2.5;
1333
+ border-bottom: 6px solid#faebcc;
1334
+ line-height: 20px;
1335
+ margin-bottom: 10px;
1336
+ margin-left: 15px;
1337
+ -moz-border-radius: 10px;
1338
+ list-style: initial;
1339
+ border-radius: 5px;
1340
+ }
1341
+
1342
+ .ae-info-auth ul {
1343
+ list-style: initial;
1344
+ list-style-type: square;
1345
+ }
1346
+
1347
+ .ae-email-color {
1348
+ color: #268CCD;
1349
+ }
1350
+
1351
+ #items-wiki {
1352
+ width: 89%;
1353
+ margin: 0 auto;
1354
+ text-align: justify;
1355
+ background: #ecf0f1;
1356
+ border: 1px solid #bdc3c7;
1357
+ border-bottom-width: 6px;
1358
+ min-height: 142px;
1359
+ text-align: justify;
1360
+ margin: 0 auto;
1361
+ display: block;
1362
+ margin-left: 25px;
1363
+ margin-right: 25px;
1364
+ color: #323232;
1365
+ margin-top: 30px;
1366
+ margin-bottom: 60px;
1367
+ padding: 0px 25px 25px 25px;
1368
+ }
1369
+
1370
+ .items-theme-zone-activation {
1371
+ color: red;
1372
+ font-weight: bold;
1373
+ }
1374
+
1375
+ .items-theme-cancel {
1376
+ background: #d9534f;
1377
+ color: white;
1378
+ margin-left: 225px !important;
1379
+ }
1380
+
1381
+ .phpinfo {
1382
+ width: 92%;
1383
+ margin: 0 auto;
1384
+ background: #ecf0f1;
1385
+ border: 1px solid #bdc3c7;
1386
+ border-bottom-width: 6px;
1387
+ margin-bottom: 10px;
1388
+ }
1389
+
1390
+ .preview-title-zone {
1391
+ background: #ecf0f1;
1392
+ border: 1px solid #bdc3c7;
1393
+ text-align: center;
1394
+ font-size: 9px;
1395
+ color: #8b959c;
1396
+ border-bottom-width: 6px;
1397
+ margin-bottom: 20px;
1398
+ }
1399
+
1400
+ #items-overlay {
1401
+ visibility: hidden;
1402
+ position: fixed;
1403
+ top: 0;
1404
+ left: 0;
1405
+ z-index: 4000;
1406
+ width: 100%;
1407
+ height: 100%;
1408
+ background: #000;
1409
+ background: -webkit-radial-gradient(50% 20%,ellipse farthest-corner,rgba(0,0,0,0.6),#000);
1410
+ background: -moz-radial-gradient(50% 20%,ellipse farthest-corner,rgba(0,0,0,0.6),#000);
1411
+ background: -o-radial-gradient(50% 20%,ellipse farthest-corner,rgba(0,0,0,0.6),#000);
1412
+ background: radial-gradient(50% 20%,ellipse farthest-corner,rgba(0,0,0,0.6),#000);
1413
+ opacity: .6;
1414
+ filter: alpha(opacity=60);
1415
+ -webkit-animation: popin-overlay-fadein .5s;
1416
+ animation: popin-overlay-fadein .5s;
1417
+ }
1418
+
1419
+ #items-overlay-content {
1420
+ visibility: hidden;
1421
+ position: fixed;
1422
+ top: 0;
1423
+ left: 40%;
1424
+ z-index: 4000;
1425
+ -webkit-animation: popin-overlay-fadein .5s;
1426
+ animation: popin-overlay-fadein .5s;
1427
+ width:300px;
1428
+ margin: 100px auto;
1429
+ margin-top: 15%;
1430
+ background-color: #fff;
1431
+ border:1px solid #000;
1432
+ padding:15px;
1433
+ text-align:center;
1434
+ background-color: white;
1435
+ }
1436
+
1437
+ .items-support-h3 {
1438
+ font-size: 16px;
1439
+ color: #604a7b;
1440
+ margin: 0;
1441
+ padding: 0;
1442
+ }
1443
+
1444
+ #items-wiki h1 {
1445
+ color: #604a7b;
1446
+ font-size: 33px;
1447
+ }
1448
+
1449
+ #items-wiki h2 {
1450
+ color: #604a7b;
1451
+ font-size: 25px;
1452
+ text-decoration: underline;
1453
+ }
1454
+
1455
+ #items-wiki strong {
1456
+ color: #604a7b;
1457
+ font-size: 16px;
1458
+ }
1459
+
1460
+ #items-wiki p {
1461
+ font-size: 14px;
1462
+ }
1463
+
1464
+ .items-notice {
1465
+ background-color: #d9edf7;
1466
+ border-color: #bce8f1;
1467
+ color: #31708f;
1468
+ max-height: 200px;
1469
+ width: 91.5%;
1470
+ margin-left: 15px;
1471
+ text-align: justify;
1472
+ margin-bottom: 15px;
1473
+ padding: 15px 25px 15px 25px;
1474
+ -webkit-border-radius: 10px;
1475
+ -moz-border-radius: 10px;
1476
+ border-radius: 10px;
1477
+ }
1478
+
1479
+ .items-set-notification-read {
1480
+ float: right;
1481
+ display: block;
1482
+ text-decoration: none;
1483
+ cursor: pointer;
1484
+ opacity: 0.5;
1485
+ font-size: 21px;
1486
+ font-weight: 700;
1487
+ line-height: 1;
1488
+ color: #000;
1489
+ text-shadow: 0 1px 0 #fff;
1490
+ padding: 0;
1491
+ cursor: pointer;
1492
+ background: 0 0;
1493
+ border: 0;
1494
+ -webkit-appearance: none;
1495
+ }
1496
+
1497
+ .items-set-notification-read:hover {
1498
+ opacity: 0.9;
1499
+ }
1500
+
1501
+ .position-options {
1502
+ float: left;
1503
+ }
1504
+
1505
+ #items-funnel-step-one, #items-funnel-step-two {
1506
+ height: 325px;
1507
+ text-align: center;
1508
+ }
1509
+
1510
+ #items-funnel-step-one h2 , #items-funnel-step-two h2 {
1511
+ color: #79478b;
1512
+ }
1513
+
1514
+ #items-funnel-step-one a, #items-funnel-step-two a {
1515
+ margin-top: 15px;
1516
+ margin-bottom: 15px;
1517
+ }
1518
+
1519
+ #items-funnel-step-one span, #items-funnel-step-two span {
1520
+ font-size: 12px;
1521
+ }
1522
+
1523
+ #items-funnel-step-two label {
1524
+ display: block;
1525
+ float: none;
1526
+ width: initial;
1527
+ padding: initial;
1528
+ text-align: center;
1529
+ color: white;
1530
+ margin-top: 35px;
1531
+ background-color: #ababab;
1532
+ font-weight: initial;
1533
+ margin-bottom: 45px;
1534
+ }
1535
+
1536
+ #items-funnel-step-two ul {
1537
+ list-style: none;
1538
+ display: block;
1539
+ }
1540
+
1541
+ #items-funnel-step-two ul li {
1542
+ float: left;
1543
+ display: block;
1544
+ margin-right: 55px;
1545
+ width: 120px;
1546
+ height: 90px;
1547
+ text-align: center;
1548
+ background-color: #d9d9d9;
1549
+ }
1550
+
1551
+ .items-radio-funnel-style-choice {
1552
+ height: 140px;
1553
+ padding-top: 20px;
1554
+ margin-bottom: 20px;
1555
+ width: 32%;
1556
+ margin: 0 auto;
1557
+ }
1558
+
1559
+ .items-radio-funnel-style-choice ul {
1560
+ padding: 0;
1561
+ }
1562
+
1563
+ .items-box {
1564
+ width: 169px;
1565
+ height: 152px;
1566
+ color: white;
1567
+ text-align: center;
1568
+ display: inline-block;
1569
+ float: left;
1570
+ padding: 0;
1571
+ margin-left: 8.5px;
1572
+ margin-bottom: 8.5px;
1573
+ }
1574
+
1575
+ .items-box p {
1576
+ padding-top: 48px;
1577
+ color: white;
1578
+ margin-top: 0px;
1579
+ }
1580
+
1581
+ .items-box-black {
1582
+ background: #595959;
1583
+ }
1584
+
1585
+ .items-box-purple {
1586
+ background: #8E6FA3;
1587
+ }
1588
+
1589
+ .items-box-large-font {
1590
+ font-size: 40px;
1591
+ }
1592
+
1593
+ .items-synchronize-container {
1594
+ width: 875px;
1595
+ padding: 15px;
1596
+ min-height: 50px;
1597
+ font-size: 14px;
1598
+ margin-top: 15px;
1599
+ margin-left: 10px;
1600
+ margin-bottom: 20px;
1601
+ color: #fff;
1602
+ }
1603
+
1604
+ .items-synchronize-container-button {
1605
+ border: 1px solid white;
1606
+ padding: 15px;
1607
+ margin-top: 0px;
1608
+ display: block;
1609
+ -webkit-border-radius: 10px;
1610
+ -moz-border-radius: 10px;
1611
+ border-radius: 10px;
1612
+ background-color: #92d050;
1613
+ }
1614
+
1615
+ .items-synchronize-container-text {
1616
+ font-size: 16px;
1617
+ padding-top: 16px;
1618
+ }
1619
+
1620
+ #items-activation {
1621
+ text-align: center;
1622
+ }
1623
+
1624
+ .items-activation-content {
1625
+ width: 650px;
1626
+ margin: 20px auto;
1627
+ padding: 15px;
1628
+ -webkit-border-radius: 20px;
1629
+ -moz-border-radius: 20px;
1630
+ border-radius: 20px;
1631
+ border: 2px solid #d9d9d9;
1632
+ }
1633
+
1634
+ #items-activation h2 {
1635
+ color: #774e92;
1636
+ }
1637
+
1638
+ .items-activation-content-settings {
1639
+ height: 35px;
1640
+ padding: 15px;
1641
+ color: #8B8B8B;
1642
+ }
1643
+
1644
+ .items-activation-content-settings .items-button {
1645
+ float: left;
1646
+ margin-right: 70px;
1647
+ margin-left: 20px;
1648
+ }
1649
+
1650
+ .items-activation-content-settings-text {
1651
+ margin-top: 5px;
1652
+ display: block;
1653
+ float: left;
1654
+ margin-left: 10px;
1655
+ }
1656
+
1657
+ .items-activation-content-settings-text-container {
1658
+ text-align: left;
1659
+ }
1660
+
1661
+ .items-config-container {
1662
+ background: #f2f2f2;
1663
+ height: 40px;
1664
+ margin-left: 35px;
1665
+ margin-top: 10px;
1666
+ width: 89%;
1667
+ padding: 15px;
1668
+ margin-top: 10px;
1669
+ }
1670
+
1671
+ .items-config-text {
1672
+ width: 65%;
1673
+ text-align: justify;
1674
+ float: left;
1675
+ margin-right: 40px;
1676
+ }
1677
+
1678
+ .items-general-activation {
1679
+ float: left;
1680
+ }
1681
+
1682
+ .items-general-activation-text {
1683
+ float: right;
1684
+ }
1685
+
1686
+ .items-tabs-support {
1687
+ height: 40px;
1688
+ border-bottom: 2px solid #774e92;
1689
+ width: 100%;
1690
+ }
1691
+
1692
+ .items-tabs-support ul {
1693
+ width: 100%;
1694
+ text-align: center;
1695
+ }
1696
+
1697
+ .items-tabs-support ul li {
1698
+ width: 180px;
1699
+ border-top: 2px solid #774e92;
1700
+ border-left: 2px solid #774e92;
1701
+ border-right: 2px solid #774e92;
1702
+ text-align: center;
1703
+ color: #774e92;
1704
+ display: inline-block;
1705
+ background: #ecf0f1;
1706
+ font-weight: bold;
1707
+ cursor: pointer;
1708
+ height: 40px;
1709
+ margin-right: 10px;
1710
+ border-top-left-radius: 10px;
1711
+ border-top-right-radius: 10px;
1712
+ }
1713
+
1714
+ .items-tabs-support ul li span {
1715
+ padding-top: 10px;
1716
+ display: block;
1717
+ }
1718
+
1719
+ .items-tab-active {
1720
+ background: white !important;
1721
+ }
1722
+
1723
+ .items-eye {
1724
+ font-size: 90px;
1725
+ color: #774e92;
1726
+ cursor: pointer;
1727
+ margin-right: 5%;
1728
+ }
1729
+
1730
+ .items-help-explaination {
1731
+ text-align: center;
1732
+ display: block;
1733
+ margin-top: 20px;
1734
+ margin-bottom: 20px;
1735
+ font-size: 17px;
1736
+ }
1737
+
1738
+ #items-desactivate table {
1739
+ margin: 0 auto;
1740
+ text-align: left;
1741
+ margin-bottom: 25px;
1742
+ }
1743
+
1744
+ #items-desactivate tr {
1745
+ height: 30px;
1746
+ }
1747
+
1748
+ .items-desactivate-button {
1749
+ margin: 0 auto;
1750
+ }
1751
+
1752
+ .items-desactivate-form {
1753
+ margin: 0 auto;
1754
+ text-align: center;
1755
+ display: block;
1756
+ width: 333px;
1757
+ }
1758
+
1759
+ .items-help-form {
1760
+ margin: 0 auto;
1761
+ display: block;
1762
+ width: 333px;
1763
+ text-align: center;
1764
+ }
1765
+
1766
+ .items-help-form table {
1767
+ margin: 0 auto;
1768
+ margin-bottom: 20px;
1769
+ text-align: left;
1770
+ }
1771
+
1772
+ .items-help-form span {
1773
+ width: 70px;
1774
+ display: block;
1775
+ float: left;
1776
+ }
1777
+
1778
+ .items-synchronize-message-container {
1779
+ display: none;
1780
+ }
1781
+
1782
+ .items-open-theme-list {
1783
+ cursor: pointer;
1784
+ }
1785
+
1786
+ .items-theme-list {
1787
+ min-height: 110px;
1788
+ width: 100%;
1789
+ padding-top: 20px;
1790
+ display: none;
1791
+ }
1792
+
1793
+ .items-theme-list ul {
1794
+ list-style: none;
1795
+ display: block;
1796
+ }
1797
+
1798
+ .items-theme-list ul li {
1799
+ float: left;
1800
+ display: block;
1801
+ background-color: #d9d9d9;
1802
+ margin-right: 20px;
1803
+ width: 120px;
1804
+ height: 90px;
1805
+ margin-bottom: 25px;
1806
+ text-align: center;
1807
+ }
1808
+
1809
+ .items-theme-list ul li label {
1810
+ display: block;
1811
+ float: none;
1812
+ width: initial;
1813
+ padding: initial;
1814
+ text-align: center;
1815
+ color: white;
1816
+ margin-top: 35px;
1817
+ background-color: #ababab;
1818
+ font-weight: initial;
1819
+ margin-bottom: 45px;
1820
+ }
1821
+
1822
+ .items-menu-help {
1823
+ min-width: 160px !important;
1824
+ height: 35px !important;
1825
+ border: 1px solid white;
1826
+ margin-right: 20px;
1827
+ margin-top: 10px;
1828
+ background: #947cb0;
1829
+ }
1830
+
1831
+ .items-menu-help a {
1832
+ margin-top: -7px;
1833
+ display: block;
1834
+ }
1835
+
1836
+ .items-table-activation-cell {
1837
+ width: 7%;
1838
+ text-align: center;
1839
+ }
1840
+
1841
+ .items-table-zone-title-cell {
1842
+ width: 27%;
1843
+ text-align: center;
1844
+ }
1845
+
1846
+ .items-table-recommendation-type-cell {
1847
+ width: 25%;
1848
+ text-align: center;
1849
+ }
1850
+
1851
+ .items-table-product-number-cell {
1852
+ width: 16%;
1853
+ text-align: center;
1854
+ }
1855
+
1856
+ .items-table-theme-cell {
1857
+ text-align: center;
1858
+ }
1859
+
1860
+ .items-open-theme-list {
1861
+ width: 170px !important;
1862
+ }
1863
+
1864
+ .aechecked {
1865
+ background: url(./img/checked.png) no-repeat;
1866
+ font-size: 1.2em;
1867
+ padding-left: 30px;
1868
+ margin: 20px auto;
1869
+ width: 25%;
1870
+ }
1871
+
1872
+ .aeunchecked {
1873
+ background: url(./img/unchecked.png) no-repeat;
1874
+ font-size: 1.2em;
1875
+ padding-left: 30px;
1876
+ margin: 20px auto;
1877
+ width: 25%;
1878
+ }
1879
+
1880
+ .items-synchronization {
1881
+ text-align: center;
1882
+ color: #774e92;
1883
+ }
1884
+
1885
+ .items-box-description {
1886
+ text-align: center;
1887
+ }
skin/frontend/base/default/css/affinityitems/affinityitems.css ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .ae-area ul {margin-bottom: 30px;}
2
+ .ae-area img {border: 1px solid #d6d4d4; float: left; margin-right: 10px; height: auto;}
3
+ .ae-area h4 {clear: both; background-color: #f6f6f6; border-top: 5px solid #333333; margin-bottom: -15px; padding: 10px;}
4
+ .ae-area h5 {margin-bottom: 5px; font-size: 11px; line-height: 13px; margin-right: 10px;}
5
+ .ae-area li {float: left; width: 20%; margin-bottom: 10px;}
6
+ .ae-area li p {font-size: 10px; line-height: 12px; margin-right: 10px;}
7
+ .ae_price_center {font-size: 14px; font-weight: bold;position: relative; top: 5px;}
8
+ .ae-area.ae-home img, .ae-area.ae-category img,.ae-area.ae-product img, .ae-area.ae-search img, .ae-area.ae-cart img {margin-bottom: 10px;}
9
+ .ae-area.ae-left li, .ae-area.ae-right li {width: 100%; border-bottom: 1px solid #d6d4d4; padding-bottom: 5px;}
10
+ .ae-area.ae-left .ae_price_center, .ae-area.ae-right .ae_price_center {float: right; top: 0;}
11
+ .ae-area.ae-left .ae_products_name_center, .ae-area.ae-right .ae_products_name_center {
12
+ word-wrap: break-word !important;
13
+ width: 90px;
14
+ display: block;
15
+ float: left;
16
+ margin-bottom: 5px;}
17
+ @media only screen and (max-width: 1024px) {
18
+ .cms-home .ae-area img,
19
+ .catalog-product-view .ae-area img,
20
+ .checkout-cart-index .ae-area img {width: 90%}
21
+ }
22
+
23
+ @media only screen and (max-width: 360px) {
24
+ .ae-area li {width: 50%; min-height: 250px;}
25
+ }
skin/frontend/base/default/js/affinityitems/affinityitems.js ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * 2014 Affinity-Engine
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * DISCLAIMER
7
+ *
8
+ * Do not edit or add to this file if you wish to upgrade AffinityItems to newer
9
+ * versions in the future. If you wish to customize AffinityItems for your
10
+ * needs please refer to http://www.affinity-engine.fr for more information.
11
+ *
12
+ * @author Affinity-Engine SARL <contact@affinity-engine.fr>
13
+ * @copyright 2014 Affinity-Engine SARL
14
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL Version 2 (GPLv2)
15
+ * International Registered Trademark & Property of Affinity Engine SARL
16
+ */
17
+
18
+ function createCookie(name, value, days) {
19
+ if (days) {
20
+ var date = new Date();
21
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
22
+ var expires = "; expires=" + date.toGMTString();
23
+ }
24
+ else
25
+ var expires = "";
26
+ document.cookie = name + "=" + value + expires + "; path=/";
27
+ }
28
+
29
+ function deleteCookie(name) {
30
+ document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/';
31
+ }
32
+
33
+ function readCookie(name) {
34
+ var nameEQ = name + "=";
35
+ var ca = document.cookie.split(';');
36
+ for (var i = 0; i < ca.length; i++) {
37
+ var c = ca[i];
38
+ while (c.charAt(0) == ' ')
39
+ c = c.substring(1, c.length);
40
+ if (c.indexOf(nameEQ) == 0)
41
+ return c.substring(nameEQ.length, c.length);
42
+ }
43
+ return null;
44
+ }
45
+
46
+ /*function postAction(action, object) {
47
+ var aegroup = readCookie('aegroup');
48
+ var aeguest = readCookie('aeguest');
49
+
50
+ if (!object.recoType) {
51
+ aejQuery.ajax({
52
+ type: 'POST',
53
+ url: base_url + 'affinityitems/action/ajax',
54
+ data: {recoType: object.recoType, productId: object.productId, action: action, guestId: aeguest, group: aegroup},
55
+ async: true,
56
+ dataType: 'json',
57
+ complete: function(e, t, n) {
58
+ }
59
+ });
60
+ } else {
61
+ aejQuery.ajax({
62
+ type: 'POST',
63
+ url: base_url + 'affinityitems/action/ajax',
64
+ data: {recoType: object.recoType, productId: object.productId, action: action, guestId: aeguest, group: aegroup},
65
+ async: true,
66
+ dataType: 'json',
67
+ complete: function(e, t, n) {
68
+ }
69
+ });
70
+ deleteCookie('aelastreco');
71
+ }
72
+ }*/
73
+
74
+ function postAction(action, object) {
75
+ var aegroup = readCookie('aegroup');
76
+ var aeguest = readCookie('aeguest');
77
+ if(!object.recoType) {
78
+ if(object.productId) {
79
+ aejQuery.ajax({
80
+ type: 'POST',
81
+ url: base_url + 'affinityitems/action/ajax',
82
+ data: {productId: object.productId, action: action, guestId: aeguest, group: aegroup},
83
+ async:true,
84
+ dataType: 'json',
85
+ complete: function(e,t,n) {}
86
+ });
87
+ } else if(object.categoryId) {
88
+ aejQuery.ajax({
89
+ type: 'POST',
90
+ url: base_url + 'affinityitems/action/ajax',
91
+ data: {categoryId: object.categoryId, action: action, guestId: aeguest, group: aegroup},
92
+ async:true,
93
+ dataType: 'json',
94
+ complete: function(e,t,n) {}
95
+ });
96
+ }
97
+ } else {
98
+ aejQuery.ajax({
99
+ type: 'POST',
100
+ url: base_url + 'affinityitems/action/ajax',
101
+ data: {recoType: object.recoType, productId: object.productId, action: action, guestId: aeguest, group: aegroup},
102
+ async:true,
103
+ dataType: 'json',
104
+ complete: function(e,t,n) {}
105
+ });
106
+ deleteCookie('aelastreco');
107
+ }
108
+ }
109
+
110
+ aejQuery(document).ready(function() {
111
+
112
+ var paetimestamp = readCookie('paetimestamp');
113
+ var caetimestamp = readCookie('caetimestamp');
114
+ var aelastreco = readCookie('aelastreco');
115
+ var aenow = new Date().getTime();
116
+
117
+ if (aejQuery('#product_page_product_id').val()) {
118
+ var aetimer = setInterval((function() {
119
+ clearInterval(aetimer);
120
+ postAction("read", {productId: aejQuery('#product_page_product_id').val()});
121
+ }), 4000);
122
+ createCookie('paetimestamp', (aenow + "." + aejQuery('#product_page_product_id').val()), 1);
123
+ }
124
+
125
+ if(paetimestamp){
126
+ paetimestamp = paetimestamp.split('.');
127
+ var diff = aenow - paetimestamp[0];
128
+ if(diff < 4000) {
129
+ postAction("rebound", {productId : paetimestamp[1]});
130
+ }
131
+ }
132
+
133
+ if (typeof categoryId !== 'undefined') {
134
+ var aetimer = setInterval((function() {
135
+ clearInterval(aetimer);
136
+ postAction("readCategory", {categoryId : categoryId});
137
+ }), 4000);
138
+ createCookie('caetimestamp', (aenow+"."+categoryId), 1);
139
+ }
140
+
141
+ if(caetimestamp) {
142
+ caetimestamp = caetimestamp.split('.');
143
+ var diff = aenow - caetimestamp[0];
144
+ if(diff < 4000) {
145
+ postAction("reboundCategory", {categoryId : caetimestamp[1]});
146
+ }
147
+ }
148
+
149
+ /*var aetimestamp = readCookie('aetimestamp');
150
+ var aelastreco = readCookie('aelastreco');
151
+ var aenow = new Date().getTime();
152
+
153
+ if (aejQuery('#product_page_product_id').val()) {
154
+ var aetimer = setInterval((function() {
155
+ clearInterval(aetimer);
156
+ postAction("read", {productId: aejQuery('#product_page_product_id').val()});
157
+ }), 4000);
158
+ createCookie('aetimestamp', (aenow + "." + aejQuery('#product_page_product_id').val()), 1);
159
+ }
160
+
161
+ if (aetimestamp) {
162
+ aetimestamp = aetimestamp.split('.');
163
+ var diff = aenow - aetimestamp[0];
164
+ if (diff < 4000) {
165
+ postAction("rebound", {productId: aetimestamp[1]});
166
+ }
167
+ }*/
168
+
169
+ if (aelastreco) {
170
+ aelastreco = aelastreco.split('.');
171
+ postAction("trackRecoClick", {recoType: aelastreco[1], productId: aelastreco[2]});
172
+ }
173
+
174
+
175
+ });
skin/frontend/base/default/js/affinityitems/jquery-noconflict.js ADDED
@@ -0,0 +1,9791 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery JavaScript Library v1.10.2
3
+ * http://jquery.com/
4
+ *
5
+ * Includes Sizzle.js
6
+ * http://sizzlejs.com/
7
+ *
8
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
9
+ * Released under the MIT license
10
+ * http://jquery.org/license
11
+ *
12
+ * Date: 2013-07-03T13:48Z
13
+ */
14
+ (function( window, undefined ) {
15
+
16
+ // Can't do this because several apps including ASP.NET trace
17
+ // the stack via arguments.caller.callee and Firefox dies if
18
+ // you try to trace through "use strict" call chains. (#13335)
19
+ // Support: Firefox 18+
20
+ //"use strict";
21
+ var
22
+ // The deferred used on DOM ready
23
+ readyList,
24
+
25
+ // A central reference to the root jQuery(document)
26
+ rootjQuery,
27
+
28
+ // Support: IE<10
29
+ // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
30
+ core_strundefined = typeof undefined,
31
+
32
+ // Use the correct document accordingly with window argument (sandbox)
33
+ location = window.location,
34
+ document = window.document,
35
+ docElem = document.documentElement,
36
+
37
+ // Map over jQuery in case of overwrite
38
+ _jQuery = window.jQuery,
39
+
40
+ // Map over the $ in case of overwrite
41
+ _$ = window.$,
42
+
43
+ // [[Class]] -> type pairs
44
+ class2type = {},
45
+
46
+ // List of deleted data cache ids, so we can reuse them
47
+ core_deletedIds = [],
48
+
49
+ core_version = "1.10.2",
50
+
51
+ // Save a reference to some core methods
52
+ core_concat = core_deletedIds.concat,
53
+ core_push = core_deletedIds.push,
54
+ core_slice = core_deletedIds.slice,
55
+ core_indexOf = core_deletedIds.indexOf,
56
+ core_toString = class2type.toString,
57
+ core_hasOwn = class2type.hasOwnProperty,
58
+ core_trim = core_version.trim,
59
+
60
+ // Define a local copy of jQuery
61
+ jQuery = function( selector, context ) {
62
+ // The jQuery object is actually just the init constructor 'enhanced'
63
+ return new jQuery.fn.init( selector, context, rootjQuery );
64
+ },
65
+
66
+ // Used for matching numbers
67
+ core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
68
+
69
+ // Used for splitting on whitespace
70
+ core_rnotwhite = /\S+/g,
71
+
72
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
73
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
74
+
75
+ // A simple way to check for HTML strings
76
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
77
+ // Strict HTML recognition (#11290: must start with <)
78
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
79
+
80
+ // Match a standalone tag
81
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
82
+
83
+ // JSON RegExp
84
+ rvalidchars = /^[\],:{}\s]*$/,
85
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
86
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
87
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
88
+
89
+ // Matches dashed string for camelizing
90
+ rmsPrefix = /^-ms-/,
91
+ rdashAlpha = /-([\da-z])/gi,
92
+
93
+ // Used by jQuery.camelCase as callback to replace()
94
+ fcamelCase = function( all, letter ) {
95
+ return letter.toUpperCase();
96
+ },
97
+
98
+ // The ready event handler
99
+ completed = function( event ) {
100
+
101
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
102
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
103
+ detach();
104
+ jQuery.ready();
105
+ }
106
+ },
107
+ // Clean-up method for dom ready events
108
+ detach = function() {
109
+ if ( document.addEventListener ) {
110
+ document.removeEventListener( "DOMContentLoaded", completed, false );
111
+ window.removeEventListener( "load", completed, false );
112
+
113
+ } else {
114
+ document.detachEvent( "onreadystatechange", completed );
115
+ window.detachEvent( "onload", completed );
116
+ }
117
+ };
118
+
119
+ jQuery.fn = jQuery.prototype = {
120
+ // The current version of jQuery being used
121
+ jquery: core_version,
122
+
123
+ constructor: jQuery,
124
+ init: function( selector, context, rootjQuery ) {
125
+ var match, elem;
126
+
127
+ // HANDLE: $(""), $(null), $(undefined), $(false)
128
+ if ( !selector ) {
129
+ return this;
130
+ }
131
+
132
+ // Handle HTML strings
133
+ if ( typeof selector === "string" ) {
134
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
135
+ // Assume that strings that start and end with <> are HTML and skip the regex check
136
+ match = [ null, selector, null ];
137
+
138
+ } else {
139
+ match = rquickExpr.exec( selector );
140
+ }
141
+
142
+ // Match html or make sure no context is specified for #id
143
+ if ( match && (match[1] || !context) ) {
144
+
145
+ // HANDLE: $(html) -> $(array)
146
+ if ( match[1] ) {
147
+ context = context instanceof jQuery ? context[0] : context;
148
+
149
+ // scripts is true for back-compat
150
+ jQuery.merge( this, jQuery.parseHTML(
151
+ match[1],
152
+ context && context.nodeType ? context.ownerDocument || context : document,
153
+ true
154
+ ) );
155
+
156
+ // HANDLE: $(html, props)
157
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
158
+ for ( match in context ) {
159
+ // Properties of context are called as methods if possible
160
+ if ( jQuery.isFunction( this[ match ] ) ) {
161
+ this[ match ]( context[ match ] );
162
+
163
+ // ...and otherwise set as attributes
164
+ } else {
165
+ this.attr( match, context[ match ] );
166
+ }
167
+ }
168
+ }
169
+
170
+ return this;
171
+
172
+ // HANDLE: $(#id)
173
+ } else {
174
+ elem = document.getElementById( match[2] );
175
+
176
+ // Check parentNode to catch when Blackberry 4.6 returns
177
+ // nodes that are no longer in the document #6963
178
+ if ( elem && elem.parentNode ) {
179
+ // Handle the case where IE and Opera return items
180
+ // by name instead of ID
181
+ if ( elem.id !== match[2] ) {
182
+ return rootjQuery.find( selector );
183
+ }
184
+
185
+ // Otherwise, we inject the element directly into the jQuery object
186
+ this.length = 1;
187
+ this[0] = elem;
188
+ }
189
+
190
+ this.context = document;
191
+ this.selector = selector;
192
+ return this;
193
+ }
194
+
195
+ // HANDLE: $(expr, $(...))
196
+ } else if ( !context || context.jquery ) {
197
+ return ( context || rootjQuery ).find( selector );
198
+
199
+ // HANDLE: $(expr, context)
200
+ // (which is just equivalent to: $(context).find(expr)
201
+ } else {
202
+ return this.constructor( context ).find( selector );
203
+ }
204
+
205
+ // HANDLE: $(DOMElement)
206
+ } else if ( selector.nodeType ) {
207
+ this.context = this[0] = selector;
208
+ this.length = 1;
209
+ return this;
210
+
211
+ // HANDLE: $(function)
212
+ // Shortcut for document ready
213
+ } else if ( jQuery.isFunction( selector ) ) {
214
+ return rootjQuery.ready( selector );
215
+ }
216
+
217
+ if ( selector.selector !== undefined ) {
218
+ this.selector = selector.selector;
219
+ this.context = selector.context;
220
+ }
221
+
222
+ return jQuery.makeArray( selector, this );
223
+ },
224
+
225
+ // Start with an empty selector
226
+ selector: "",
227
+
228
+ // The default length of a jQuery object is 0
229
+ length: 0,
230
+
231
+ toArray: function() {
232
+ return core_slice.call( this );
233
+ },
234
+
235
+ // Get the Nth element in the matched element set OR
236
+ // Get the whole matched element set as a clean array
237
+ get: function( num ) {
238
+ return num == null ?
239
+
240
+ // Return a 'clean' array
241
+ this.toArray() :
242
+
243
+ // Return just the object
244
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
245
+ },
246
+
247
+ // Take an array of elements and push it onto the stack
248
+ // (returning the new matched element set)
249
+ pushStack: function( elems ) {
250
+
251
+ // Build a new jQuery matched element set
252
+ var ret = jQuery.merge( this.constructor(), elems );
253
+
254
+ // Add the old object onto the stack (as a reference)
255
+ ret.prevObject = this;
256
+ ret.context = this.context;
257
+
258
+ // Return the newly-formed element set
259
+ return ret;
260
+ },
261
+
262
+ // Execute a callback for every element in the matched set.
263
+ // (You can seed the arguments with an array of args, but this is
264
+ // only used internally.)
265
+ each: function( callback, args ) {
266
+ return jQuery.each( this, callback, args );
267
+ },
268
+
269
+ ready: function( fn ) {
270
+ // Add the callback
271
+ jQuery.ready.promise().done( fn );
272
+
273
+ return this;
274
+ },
275
+
276
+ slice: function() {
277
+ return this.pushStack( core_slice.apply( this, arguments ) );
278
+ },
279
+
280
+ first: function() {
281
+ return this.eq( 0 );
282
+ },
283
+
284
+ last: function() {
285
+ return this.eq( -1 );
286
+ },
287
+
288
+ eq: function( i ) {
289
+ var len = this.length,
290
+ j = +i + ( i < 0 ? len : 0 );
291
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
292
+ },
293
+
294
+ map: function( callback ) {
295
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
296
+ return callback.call( elem, i, elem );
297
+ }));
298
+ },
299
+
300
+ end: function() {
301
+ return this.prevObject || this.constructor(null);
302
+ },
303
+
304
+ // For internal use only.
305
+ // Behaves like an Array's method, not like a jQuery method.
306
+ push: core_push,
307
+ sort: [].sort,
308
+ splice: [].splice
309
+ };
310
+
311
+ // Give the init function the jQuery prototype for later instantiation
312
+ jQuery.fn.init.prototype = jQuery.fn;
313
+
314
+ jQuery.extend = jQuery.fn.extend = function() {
315
+ var src, copyIsArray, copy, name, options, clone,
316
+ target = arguments[0] || {},
317
+ i = 1,
318
+ length = arguments.length,
319
+ deep = false;
320
+
321
+ // Handle a deep copy situation
322
+ if ( typeof target === "boolean" ) {
323
+ deep = target;
324
+ target = arguments[1] || {};
325
+ // skip the boolean and the target
326
+ i = 2;
327
+ }
328
+
329
+ // Handle case when target is a string or something (possible in deep copy)
330
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
331
+ target = {};
332
+ }
333
+
334
+ // extend jQuery itself if only one argument is passed
335
+ if ( length === i ) {
336
+ target = this;
337
+ --i;
338
+ }
339
+
340
+ for ( ; i < length; i++ ) {
341
+ // Only deal with non-null/undefined values
342
+ if ( (options = arguments[ i ]) != null ) {
343
+ // Extend the base object
344
+ for ( name in options ) {
345
+ src = target[ name ];
346
+ copy = options[ name ];
347
+
348
+ // Prevent never-ending loop
349
+ if ( target === copy ) {
350
+ continue;
351
+ }
352
+
353
+ // Recurse if we're merging plain objects or arrays
354
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
355
+ if ( copyIsArray ) {
356
+ copyIsArray = false;
357
+ clone = src && jQuery.isArray(src) ? src : [];
358
+
359
+ } else {
360
+ clone = src && jQuery.isPlainObject(src) ? src : {};
361
+ }
362
+
363
+ // Never move original objects, clone them
364
+ target[ name ] = jQuery.extend( deep, clone, copy );
365
+
366
+ // Don't bring in undefined values
367
+ } else if ( copy !== undefined ) {
368
+ target[ name ] = copy;
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ // Return the modified object
375
+ return target;
376
+ };
377
+
378
+ jQuery.extend({
379
+ // Unique for each copy of jQuery on the page
380
+ // Non-digits removed to match rinlinejQuery
381
+ expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
382
+
383
+ noConflict: function( deep ) {
384
+ if ( window.$ === jQuery ) {
385
+ window.$ = _$;
386
+ }
387
+
388
+ if ( deep && window.jQuery === jQuery ) {
389
+ window.jQuery = _jQuery;
390
+ }
391
+
392
+ return jQuery;
393
+ },
394
+
395
+ // Is the DOM ready to be used? Set to true once it occurs.
396
+ isReady: false,
397
+
398
+ // A counter to track how many items to wait for before
399
+ // the ready event fires. See #6781
400
+ readyWait: 1,
401
+
402
+ // Hold (or release) the ready event
403
+ holdReady: function( hold ) {
404
+ if ( hold ) {
405
+ jQuery.readyWait++;
406
+ } else {
407
+ jQuery.ready( true );
408
+ }
409
+ },
410
+
411
+ // Handle when the DOM is ready
412
+ ready: function( wait ) {
413
+
414
+ // Abort if there are pending holds or we're already ready
415
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
416
+ return;
417
+ }
418
+
419
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
420
+ if ( !document.body ) {
421
+ return setTimeout( jQuery.ready );
422
+ }
423
+
424
+ // Remember that the DOM is ready
425
+ jQuery.isReady = true;
426
+
427
+ // If a normal DOM Ready event fired, decrement, and wait if need be
428
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
429
+ return;
430
+ }
431
+
432
+ // If there are functions bound, to execute
433
+ readyList.resolveWith( document, [ jQuery ] );
434
+
435
+ // Trigger any bound ready events
436
+ if ( jQuery.fn.trigger ) {
437
+ jQuery( document ).trigger("ready").off("ready");
438
+ }
439
+ },
440
+
441
+ // See test/unit/core.js for details concerning isFunction.
442
+ // Since version 1.3, DOM methods and functions like alert
443
+ // aren't supported. They return false on IE (#2968).
444
+ isFunction: function( obj ) {
445
+ return jQuery.type(obj) === "function";
446
+ },
447
+
448
+ isArray: Array.isArray || function( obj ) {
449
+ return jQuery.type(obj) === "array";
450
+ },
451
+
452
+ isWindow: function( obj ) {
453
+ /* jshint eqeqeq: false */
454
+ return obj != null && obj == obj.window;
455
+ },
456
+
457
+ isNumeric: function( obj ) {
458
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
459
+ },
460
+
461
+ type: function( obj ) {
462
+ if ( obj == null ) {
463
+ return String( obj );
464
+ }
465
+ return typeof obj === "object" || typeof obj === "function" ?
466
+ class2type[ core_toString.call(obj) ] || "object" :
467
+ typeof obj;
468
+ },
469
+
470
+ isPlainObject: function( obj ) {
471
+ var key;
472
+
473
+ // Must be an Object.
474
+ // Because of IE, we also have to check the presence of the constructor property.
475
+ // Make sure that DOM nodes and window objects don't pass through, as well
476
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
477
+ return false;
478
+ }
479
+
480
+ try {
481
+ // Not own constructor property must be Object
482
+ if ( obj.constructor &&
483
+ !core_hasOwn.call(obj, "constructor") &&
484
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
485
+ return false;
486
+ }
487
+ } catch ( e ) {
488
+ // IE8,9 Will throw exceptions on certain host objects #9897
489
+ return false;
490
+ }
491
+
492
+ // Support: IE<9
493
+ // Handle iteration over inherited properties before own properties.
494
+ if ( jQuery.support.ownLast ) {
495
+ for ( key in obj ) {
496
+ return core_hasOwn.call( obj, key );
497
+ }
498
+ }
499
+
500
+ // Own properties are enumerated firstly, so to speed up,
501
+ // if last one is own, then all properties are own.
502
+ for ( key in obj ) {}
503
+
504
+ return key === undefined || core_hasOwn.call( obj, key );
505
+ },
506
+
507
+ isEmptyObject: function( obj ) {
508
+ var name;
509
+ for ( name in obj ) {
510
+ return false;
511
+ }
512
+ return true;
513
+ },
514
+
515
+ error: function( msg ) {
516
+ throw new Error( msg );
517
+ },
518
+
519
+ // data: string of html
520
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
521
+ // keepScripts (optional): If true, will include scripts passed in the html string
522
+ parseHTML: function( data, context, keepScripts ) {
523
+ if ( !data || typeof data !== "string" ) {
524
+ return null;
525
+ }
526
+ if ( typeof context === "boolean" ) {
527
+ keepScripts = context;
528
+ context = false;
529
+ }
530
+ context = context || document;
531
+
532
+ var parsed = rsingleTag.exec( data ),
533
+ scripts = !keepScripts && [];
534
+
535
+ // Single tag
536
+ if ( parsed ) {
537
+ return [ context.createElement( parsed[1] ) ];
538
+ }
539
+
540
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
541
+ if ( scripts ) {
542
+ jQuery( scripts ).remove();
543
+ }
544
+ return jQuery.merge( [], parsed.childNodes );
545
+ },
546
+
547
+ parseJSON: function( data ) {
548
+ // Attempt to parse using the native JSON parser first
549
+ if ( window.JSON && window.JSON.parse ) {
550
+ return window.JSON.parse( data );
551
+ }
552
+
553
+ if ( data === null ) {
554
+ return data;
555
+ }
556
+
557
+ if ( typeof data === "string" ) {
558
+
559
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
560
+ data = jQuery.trim( data );
561
+
562
+ if ( data ) {
563
+ // Make sure the incoming data is actual JSON
564
+ // Logic borrowed from http://json.org/json2.js
565
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
566
+ .replace( rvalidtokens, "]" )
567
+ .replace( rvalidbraces, "")) ) {
568
+
569
+ return ( new Function( "return " + data ) )();
570
+ }
571
+ }
572
+ }
573
+
574
+ jQuery.error( "Invalid JSON: " + data );
575
+ },
576
+
577
+ // Cross-browser xml parsing
578
+ parseXML: function( data ) {
579
+ var xml, tmp;
580
+ if ( !data || typeof data !== "string" ) {
581
+ return null;
582
+ }
583
+ try {
584
+ if ( window.DOMParser ) { // Standard
585
+ tmp = new DOMParser();
586
+ xml = tmp.parseFromString( data , "text/xml" );
587
+ } else { // IE
588
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
589
+ xml.async = "false";
590
+ xml.loadXML( data );
591
+ }
592
+ } catch( e ) {
593
+ xml = undefined;
594
+ }
595
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
596
+ jQuery.error( "Invalid XML: " + data );
597
+ }
598
+ return xml;
599
+ },
600
+
601
+ noop: function() {},
602
+
603
+ // Evaluates a script in a global context
604
+ // Workarounds based on findings by Jim Driscoll
605
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
606
+ globalEval: function( data ) {
607
+ if ( data && jQuery.trim( data ) ) {
608
+ // We use execScript on Internet Explorer
609
+ // We use an anonymous function so that context is window
610
+ // rather than jQuery in Firefox
611
+ ( window.execScript || function( data ) {
612
+ window[ "eval" ].call( window, data );
613
+ } )( data );
614
+ }
615
+ },
616
+
617
+ // Convert dashed to camelCase; used by the css and data modules
618
+ // Microsoft forgot to hump their vendor prefix (#9572)
619
+ camelCase: function( string ) {
620
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
621
+ },
622
+
623
+ nodeName: function( elem, name ) {
624
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
625
+ },
626
+
627
+ // args is for internal usage only
628
+ each: function( obj, callback, args ) {
629
+ var value,
630
+ i = 0,
631
+ length = obj.length,
632
+ isArray = isArraylike( obj );
633
+
634
+ if ( args ) {
635
+ if ( isArray ) {
636
+ for ( ; i < length; i++ ) {
637
+ value = callback.apply( obj[ i ], args );
638
+
639
+ if ( value === false ) {
640
+ break;
641
+ }
642
+ }
643
+ } else {
644
+ for ( i in obj ) {
645
+ value = callback.apply( obj[ i ], args );
646
+
647
+ if ( value === false ) {
648
+ break;
649
+ }
650
+ }
651
+ }
652
+
653
+ // A special, fast, case for the most common use of each
654
+ } else {
655
+ if ( isArray ) {
656
+ for ( ; i < length; i++ ) {
657
+ value = callback.call( obj[ i ], i, obj[ i ] );
658
+
659
+ if ( value === false ) {
660
+ break;
661
+ }
662
+ }
663
+ } else {
664
+ for ( i in obj ) {
665
+ value = callback.call( obj[ i ], i, obj[ i ] );
666
+
667
+ if ( value === false ) {
668
+ break;
669
+ }
670
+ }
671
+ }
672
+ }
673
+
674
+ return obj;
675
+ },
676
+
677
+ // Use native String.trim function wherever possible
678
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
679
+ function( text ) {
680
+ return text == null ?
681
+ "" :
682
+ core_trim.call( text );
683
+ } :
684
+
685
+ // Otherwise use our own trimming functionality
686
+ function( text ) {
687
+ return text == null ?
688
+ "" :
689
+ ( text + "" ).replace( rtrim, "" );
690
+ },
691
+
692
+ // results is for internal usage only
693
+ makeArray: function( arr, results ) {
694
+ var ret = results || [];
695
+
696
+ if ( arr != null ) {
697
+ if ( isArraylike( Object(arr) ) ) {
698
+ jQuery.merge( ret,
699
+ typeof arr === "string" ?
700
+ [ arr ] : arr
701
+ );
702
+ } else {
703
+ core_push.call( ret, arr );
704
+ }
705
+ }
706
+
707
+ return ret;
708
+ },
709
+
710
+ inArray: function( elem, arr, i ) {
711
+ var len;
712
+
713
+ if ( arr ) {
714
+ if ( core_indexOf ) {
715
+ return core_indexOf.call( arr, elem, i );
716
+ }
717
+
718
+ len = arr.length;
719
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
720
+
721
+ for ( ; i < len; i++ ) {
722
+ // Skip accessing in sparse arrays
723
+ if ( i in arr && arr[ i ] === elem ) {
724
+ return i;
725
+ }
726
+ }
727
+ }
728
+
729
+ return -1;
730
+ },
731
+
732
+ merge: function( first, second ) {
733
+ var l = second.length,
734
+ i = first.length,
735
+ j = 0;
736
+
737
+ if ( typeof l === "number" ) {
738
+ for ( ; j < l; j++ ) {
739
+ first[ i++ ] = second[ j ];
740
+ }
741
+ } else {
742
+ while ( second[j] !== undefined ) {
743
+ first[ i++ ] = second[ j++ ];
744
+ }
745
+ }
746
+
747
+ first.length = i;
748
+
749
+ return first;
750
+ },
751
+
752
+ grep: function( elems, callback, inv ) {
753
+ var retVal,
754
+ ret = [],
755
+ i = 0,
756
+ length = elems.length;
757
+ inv = !!inv;
758
+
759
+ // Go through the array, only saving the items
760
+ // that pass the validator function
761
+ for ( ; i < length; i++ ) {
762
+ retVal = !!callback( elems[ i ], i );
763
+ if ( inv !== retVal ) {
764
+ ret.push( elems[ i ] );
765
+ }
766
+ }
767
+
768
+ return ret;
769
+ },
770
+
771
+ // arg is for internal usage only
772
+ map: function( elems, callback, arg ) {
773
+ var value,
774
+ i = 0,
775
+ length = elems.length,
776
+ isArray = isArraylike( elems ),
777
+ ret = [];
778
+
779
+ // Go through the array, translating each of the items to their
780
+ if ( isArray ) {
781
+ for ( ; i < length; i++ ) {
782
+ value = callback( elems[ i ], i, arg );
783
+
784
+ if ( value != null ) {
785
+ ret[ ret.length ] = value;
786
+ }
787
+ }
788
+
789
+ // Go through every key on the object,
790
+ } else {
791
+ for ( i in elems ) {
792
+ value = callback( elems[ i ], i, arg );
793
+
794
+ if ( value != null ) {
795
+ ret[ ret.length ] = value;
796
+ }
797
+ }
798
+ }
799
+
800
+ // Flatten any nested arrays
801
+ return core_concat.apply( [], ret );
802
+ },
803
+
804
+ // A global GUID counter for objects
805
+ guid: 1,
806
+
807
+ // Bind a function to a context, optionally partially applying any
808
+ // arguments.
809
+ proxy: function( fn, context ) {
810
+ var args, proxy, tmp;
811
+
812
+ if ( typeof context === "string" ) {
813
+ tmp = fn[ context ];
814
+ context = fn;
815
+ fn = tmp;
816
+ }
817
+
818
+ // Quick check to determine if target is callable, in the spec
819
+ // this throws a TypeError, but we will just return undefined.
820
+ if ( !jQuery.isFunction( fn ) ) {
821
+ return undefined;
822
+ }
823
+
824
+ // Simulated bind
825
+ args = core_slice.call( arguments, 2 );
826
+ proxy = function() {
827
+ return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
828
+ };
829
+
830
+ // Set the guid of unique handler to the same of original handler, so it can be removed
831
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
832
+
833
+ return proxy;
834
+ },
835
+
836
+ // Multifunctional method to get and set values of a collection
837
+ // The value/s can optionally be executed if it's a function
838
+ access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
839
+ var i = 0,
840
+ length = elems.length,
841
+ bulk = key == null;
842
+
843
+ // Sets many values
844
+ if ( jQuery.type( key ) === "object" ) {
845
+ chainable = true;
846
+ for ( i in key ) {
847
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
848
+ }
849
+
850
+ // Sets one value
851
+ } else if ( value !== undefined ) {
852
+ chainable = true;
853
+
854
+ if ( !jQuery.isFunction( value ) ) {
855
+ raw = true;
856
+ }
857
+
858
+ if ( bulk ) {
859
+ // Bulk operations run against the entire set
860
+ if ( raw ) {
861
+ fn.call( elems, value );
862
+ fn = null;
863
+
864
+ // ...except when executing function values
865
+ } else {
866
+ bulk = fn;
867
+ fn = function( elem, key, value ) {
868
+ return bulk.call( jQuery( elem ), value );
869
+ };
870
+ }
871
+ }
872
+
873
+ if ( fn ) {
874
+ for ( ; i < length; i++ ) {
875
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
876
+ }
877
+ }
878
+ }
879
+
880
+ return chainable ?
881
+ elems :
882
+
883
+ // Gets
884
+ bulk ?
885
+ fn.call( elems ) :
886
+ length ? fn( elems[0], key ) : emptyGet;
887
+ },
888
+
889
+ now: function() {
890
+ return ( new Date() ).getTime();
891
+ },
892
+
893
+ // A method for quickly swapping in/out CSS properties to get correct calculations.
894
+ // Note: this method belongs to the css module but it's needed here for the support module.
895
+ // If support gets modularized, this method should be moved back to the css module.
896
+ swap: function( elem, options, callback, args ) {
897
+ var ret, name,
898
+ old = {};
899
+
900
+ // Remember the old values, and insert the new ones
901
+ for ( name in options ) {
902
+ old[ name ] = elem.style[ name ];
903
+ elem.style[ name ] = options[ name ];
904
+ }
905
+
906
+ ret = callback.apply( elem, args || [] );
907
+
908
+ // Revert the old values
909
+ for ( name in options ) {
910
+ elem.style[ name ] = old[ name ];
911
+ }
912
+
913
+ return ret;
914
+ }
915
+ });
916
+
917
+ jQuery.ready.promise = function( obj ) {
918
+ if ( !readyList ) {
919
+
920
+ readyList = jQuery.Deferred();
921
+
922
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
923
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
924
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
925
+ if ( document.readyState === "complete" ) {
926
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
927
+ setTimeout( jQuery.ready );
928
+
929
+ // Standards-based browsers support DOMContentLoaded
930
+ } else if ( document.addEventListener ) {
931
+ // Use the handy event callback
932
+ document.addEventListener( "DOMContentLoaded", completed, false );
933
+
934
+ // A fallback to window.onload, that will always work
935
+ window.addEventListener( "load", completed, false );
936
+
937
+ // If IE event model is used
938
+ } else {
939
+ // Ensure firing before onload, maybe late but safe also for iframes
940
+ document.attachEvent( "onreadystatechange", completed );
941
+
942
+ // A fallback to window.onload, that will always work
943
+ window.attachEvent( "onload", completed );
944
+
945
+ // If IE and not a frame
946
+ // continually check to see if the document is ready
947
+ var top = false;
948
+
949
+ try {
950
+ top = window.frameElement == null && document.documentElement;
951
+ } catch(e) {}
952
+
953
+ if ( top && top.doScroll ) {
954
+ (function doScrollCheck() {
955
+ if ( !jQuery.isReady ) {
956
+
957
+ try {
958
+ // Use the trick by Diego Perini
959
+ // http://javascript.nwbox.com/IEContentLoaded/
960
+ top.doScroll("left");
961
+ } catch(e) {
962
+ return setTimeout( doScrollCheck, 50 );
963
+ }
964
+
965
+ // detach all dom ready events
966
+ detach();
967
+
968
+ // and execute any waiting functions
969
+ jQuery.ready();
970
+ }
971
+ })();
972
+ }
973
+ }
974
+ }
975
+ return readyList.promise( obj );
976
+ };
977
+
978
+ // Populate the class2type map
979
+ jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
980
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
981
+ });
982
+
983
+ function isArraylike( obj ) {
984
+ var length = obj.length,
985
+ type = jQuery.type( obj );
986
+
987
+ if ( jQuery.isWindow( obj ) ) {
988
+ return false;
989
+ }
990
+
991
+ if ( obj.nodeType === 1 && length ) {
992
+ return true;
993
+ }
994
+
995
+ return type === "array" || type !== "function" &&
996
+ ( length === 0 ||
997
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj );
998
+ }
999
+
1000
+ // All jQuery objects should point back to these
1001
+ rootjQuery = jQuery(document);
1002
+ /*!
1003
+ * Sizzle CSS Selector Engine v1.10.2
1004
+ * http://sizzlejs.com/
1005
+ *
1006
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
1007
+ * Released under the MIT license
1008
+ * http://jquery.org/license
1009
+ *
1010
+ * Date: 2013-07-03
1011
+ */
1012
+ (function( window, undefined ) {
1013
+
1014
+ var i,
1015
+ support,
1016
+ cachedruns,
1017
+ Expr,
1018
+ getText,
1019
+ isXML,
1020
+ compile,
1021
+ outermostContext,
1022
+ sortInput,
1023
+
1024
+ // Local document vars
1025
+ setDocument,
1026
+ document,
1027
+ docElem,
1028
+ documentIsHTML,
1029
+ rbuggyQSA,
1030
+ rbuggyMatches,
1031
+ matches,
1032
+ contains,
1033
+
1034
+ // Instance-specific data
1035
+ expando = "sizzle" + -(new Date()),
1036
+ preferredDoc = window.document,
1037
+ dirruns = 0,
1038
+ done = 0,
1039
+ classCache = createCache(),
1040
+ tokenCache = createCache(),
1041
+ compilerCache = createCache(),
1042
+ hasDuplicate = false,
1043
+ sortOrder = function( a, b ) {
1044
+ if ( a === b ) {
1045
+ hasDuplicate = true;
1046
+ return 0;
1047
+ }
1048
+ return 0;
1049
+ },
1050
+
1051
+ // General-purpose constants
1052
+ strundefined = typeof undefined,
1053
+ MAX_NEGATIVE = 1 << 31,
1054
+
1055
+ // Instance methods
1056
+ hasOwn = ({}).hasOwnProperty,
1057
+ arr = [],
1058
+ pop = arr.pop,
1059
+ push_native = arr.push,
1060
+ push = arr.push,
1061
+ slice = arr.slice,
1062
+ // Use a stripped-down indexOf if we can't use a native one
1063
+ indexOf = arr.indexOf || function( elem ) {
1064
+ var i = 0,
1065
+ len = this.length;
1066
+ for ( ; i < len; i++ ) {
1067
+ if ( this[i] === elem ) {
1068
+ return i;
1069
+ }
1070
+ }
1071
+ return -1;
1072
+ },
1073
+
1074
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
1075
+
1076
+ // Regular expressions
1077
+
1078
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
1079
+ whitespace = "[\\x20\\t\\r\\n\\f]",
1080
+ // http://www.w3.org/TR/css3-syntax/#characters
1081
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
1082
+
1083
+ // Loosely modeled on CSS identifier characters
1084
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
1085
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
1086
+ identifier = characterEncoding.replace( "w", "w#" ),
1087
+
1088
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
1089
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
1090
+ "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
1091
+
1092
+ // Prefer arguments quoted,
1093
+ // then not containing pseudos/brackets,
1094
+ // then attribute selectors/non-parenthetical expressions,
1095
+ // then anything else
1096
+ // These preferences are here to reduce the number of selectors
1097
+ // needing tokenize in the PSEUDO preFilter
1098
+ pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
1099
+
1100
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
1101
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
1102
+
1103
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
1104
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
1105
+
1106
+ rsibling = new RegExp( whitespace + "*[+~]" ),
1107
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
1108
+
1109
+ rpseudo = new RegExp( pseudos ),
1110
+ ridentifier = new RegExp( "^" + identifier + "$" ),
1111
+
1112
+ matchExpr = {
1113
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
1114
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
1115
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
1116
+ "ATTR": new RegExp( "^" + attributes ),
1117
+ "PSEUDO": new RegExp( "^" + pseudos ),
1118
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
1119
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
1120
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
1121
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
1122
+ // For use in libraries implementing .is()
1123
+ // We use this for POS matching in `select`
1124
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
1125
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
1126
+ },
1127
+
1128
+ rnative = /^[^{]+\{\s*\[native \w/,
1129
+
1130
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
1131
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
1132
+
1133
+ rinputs = /^(?:input|select|textarea|button)$/i,
1134
+ rheader = /^h\d$/i,
1135
+
1136
+ rescape = /'|\\/g,
1137
+
1138
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
1139
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
1140
+ funescape = function( _, escaped, escapedWhitespace ) {
1141
+ var high = "0x" + escaped - 0x10000;
1142
+ // NaN means non-codepoint
1143
+ // Support: Firefox
1144
+ // Workaround erroneous numeric interpretation of +"0x"
1145
+ return high !== high || escapedWhitespace ?
1146
+ escaped :
1147
+ // BMP codepoint
1148
+ high < 0 ?
1149
+ String.fromCharCode( high + 0x10000 ) :
1150
+ // Supplemental Plane codepoint (surrogate pair)
1151
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
1152
+ };
1153
+
1154
+ // Optimize for push.apply( _, NodeList )
1155
+ try {
1156
+ push.apply(
1157
+ (arr = slice.call( preferredDoc.childNodes )),
1158
+ preferredDoc.childNodes
1159
+ );
1160
+ // Support: Android<4.0
1161
+ // Detect silently failing push.apply
1162
+ arr[ preferredDoc.childNodes.length ].nodeType;
1163
+ } catch ( e ) {
1164
+ push = { apply: arr.length ?
1165
+
1166
+ // Leverage slice if possible
1167
+ function( target, els ) {
1168
+ push_native.apply( target, slice.call(els) );
1169
+ } :
1170
+
1171
+ // Support: IE<9
1172
+ // Otherwise append directly
1173
+ function( target, els ) {
1174
+ var j = target.length,
1175
+ i = 0;
1176
+ // Can't trust NodeList.length
1177
+ while ( (target[j++] = els[i++]) ) {}
1178
+ target.length = j - 1;
1179
+ }
1180
+ };
1181
+ }
1182
+
1183
+ function Sizzle( selector, context, results, seed ) {
1184
+ var match, elem, m, nodeType,
1185
+ // QSA vars
1186
+ i, groups, old, nid, newContext, newSelector;
1187
+
1188
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
1189
+ setDocument( context );
1190
+ }
1191
+
1192
+ context = context || document;
1193
+ results = results || [];
1194
+
1195
+ if ( !selector || typeof selector !== "string" ) {
1196
+ return results;
1197
+ }
1198
+
1199
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
1200
+ return [];
1201
+ }
1202
+
1203
+ if ( documentIsHTML && !seed ) {
1204
+
1205
+ // Shortcuts
1206
+ if ( (match = rquickExpr.exec( selector )) ) {
1207
+ // Speed-up: Sizzle("#ID")
1208
+ if ( (m = match[1]) ) {
1209
+ if ( nodeType === 9 ) {
1210
+ elem = context.getElementById( m );
1211
+ // Check parentNode to catch when Blackberry 4.6 returns
1212
+ // nodes that are no longer in the document #6963
1213
+ if ( elem && elem.parentNode ) {
1214
+ // Handle the case where IE, Opera, and Webkit return items
1215
+ // by name instead of ID
1216
+ if ( elem.id === m ) {
1217
+ results.push( elem );
1218
+ return results;
1219
+ }
1220
+ } else {
1221
+ return results;
1222
+ }
1223
+ } else {
1224
+ // Context is not a document
1225
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
1226
+ contains( context, elem ) && elem.id === m ) {
1227
+ results.push( elem );
1228
+ return results;
1229
+ }
1230
+ }
1231
+
1232
+ // Speed-up: Sizzle("TAG")
1233
+ } else if ( match[2] ) {
1234
+ push.apply( results, context.getElementsByTagName( selector ) );
1235
+ return results;
1236
+
1237
+ // Speed-up: Sizzle(".CLASS")
1238
+ } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
1239
+ push.apply( results, context.getElementsByClassName( m ) );
1240
+ return results;
1241
+ }
1242
+ }
1243
+
1244
+ // QSA path
1245
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
1246
+ nid = old = expando;
1247
+ newContext = context;
1248
+ newSelector = nodeType === 9 && selector;
1249
+
1250
+ // qSA works strangely on Element-rooted queries
1251
+ // We can work around this by specifying an extra ID on the root
1252
+ // and working up from there (Thanks to Andrew Dupont for the technique)
1253
+ // IE 8 doesn't work on object elements
1254
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
1255
+ groups = tokenize( selector );
1256
+
1257
+ if ( (old = context.getAttribute("id")) ) {
1258
+ nid = old.replace( rescape, "\\$&" );
1259
+ } else {
1260
+ context.setAttribute( "id", nid );
1261
+ }
1262
+ nid = "[id='" + nid + "'] ";
1263
+
1264
+ i = groups.length;
1265
+ while ( i-- ) {
1266
+ groups[i] = nid + toSelector( groups[i] );
1267
+ }
1268
+ newContext = rsibling.test( selector ) && context.parentNode || context;
1269
+ newSelector = groups.join(",");
1270
+ }
1271
+
1272
+ if ( newSelector ) {
1273
+ try {
1274
+ push.apply( results,
1275
+ newContext.querySelectorAll( newSelector )
1276
+ );
1277
+ return results;
1278
+ } catch(qsaError) {
1279
+ } finally {
1280
+ if ( !old ) {
1281
+ context.removeAttribute("id");
1282
+ }
1283
+ }
1284
+ }
1285
+ }
1286
+ }
1287
+
1288
+ // All others
1289
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
1290
+ }
1291
+
1292
+ /**
1293
+ * Create key-value caches of limited size
1294
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
1295
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
1296
+ * deleting the oldest entry
1297
+ */
1298
+ function createCache() {
1299
+ var keys = [];
1300
+
1301
+ function cache( key, value ) {
1302
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
1303
+ if ( keys.push( key += " " ) > Expr.cacheLength ) {
1304
+ // Only keep the most recent entries
1305
+ delete cache[ keys.shift() ];
1306
+ }
1307
+ return (cache[ key ] = value);
1308
+ }
1309
+ return cache;
1310
+ }
1311
+
1312
+ /**
1313
+ * Mark a function for special use by Sizzle
1314
+ * @param {Function} fn The function to mark
1315
+ */
1316
+ function markFunction( fn ) {
1317
+ fn[ expando ] = true;
1318
+ return fn;
1319
+ }
1320
+
1321
+ /**
1322
+ * Support testing using an element
1323
+ * @param {Function} fn Passed the created div and expects a boolean result
1324
+ */
1325
+ function assert( fn ) {
1326
+ var div = document.createElement("div");
1327
+
1328
+ try {
1329
+ return !!fn( div );
1330
+ } catch (e) {
1331
+ return false;
1332
+ } finally {
1333
+ // Remove from its parent by default
1334
+ if ( div.parentNode ) {
1335
+ div.parentNode.removeChild( div );
1336
+ }
1337
+ // release memory in IE
1338
+ div = null;
1339
+ }
1340
+ }
1341
+
1342
+ /**
1343
+ * Adds the same handler for all of the specified attrs
1344
+ * @param {String} attrs Pipe-separated list of attributes
1345
+ * @param {Function} handler The method that will be applied
1346
+ */
1347
+ function addHandle( attrs, handler ) {
1348
+ var arr = attrs.split("|"),
1349
+ i = attrs.length;
1350
+
1351
+ while ( i-- ) {
1352
+ Expr.attrHandle[ arr[i] ] = handler;
1353
+ }
1354
+ }
1355
+
1356
+ /**
1357
+ * Checks document order of two siblings
1358
+ * @param {Element} a
1359
+ * @param {Element} b
1360
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
1361
+ */
1362
+ function siblingCheck( a, b ) {
1363
+ var cur = b && a,
1364
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
1365
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
1366
+ ( ~a.sourceIndex || MAX_NEGATIVE );
1367
+
1368
+ // Use IE sourceIndex if available on both nodes
1369
+ if ( diff ) {
1370
+ return diff;
1371
+ }
1372
+
1373
+ // Check if b follows a
1374
+ if ( cur ) {
1375
+ while ( (cur = cur.nextSibling) ) {
1376
+ if ( cur === b ) {
1377
+ return -1;
1378
+ }
1379
+ }
1380
+ }
1381
+
1382
+ return a ? 1 : -1;
1383
+ }
1384
+
1385
+ /**
1386
+ * Returns a function to use in pseudos for input types
1387
+ * @param {String} type
1388
+ */
1389
+ function createInputPseudo( type ) {
1390
+ return function( elem ) {
1391
+ var name = elem.nodeName.toLowerCase();
1392
+ return name === "input" && elem.type === type;
1393
+ };
1394
+ }
1395
+
1396
+ /**
1397
+ * Returns a function to use in pseudos for buttons
1398
+ * @param {String} type
1399
+ */
1400
+ function createButtonPseudo( type ) {
1401
+ return function( elem ) {
1402
+ var name = elem.nodeName.toLowerCase();
1403
+ return (name === "input" || name === "button") && elem.type === type;
1404
+ };
1405
+ }
1406
+
1407
+ /**
1408
+ * Returns a function to use in pseudos for positionals
1409
+ * @param {Function} fn
1410
+ */
1411
+ function createPositionalPseudo( fn ) {
1412
+ return markFunction(function( argument ) {
1413
+ argument = +argument;
1414
+ return markFunction(function( seed, matches ) {
1415
+ var j,
1416
+ matchIndexes = fn( [], seed.length, argument ),
1417
+ i = matchIndexes.length;
1418
+
1419
+ // Match elements found at the specified indexes
1420
+ while ( i-- ) {
1421
+ if ( seed[ (j = matchIndexes[i]) ] ) {
1422
+ seed[j] = !(matches[j] = seed[j]);
1423
+ }
1424
+ }
1425
+ });
1426
+ });
1427
+ }
1428
+
1429
+ /**
1430
+ * Detect xml
1431
+ * @param {Element|Object} elem An element or a document
1432
+ */
1433
+ isXML = Sizzle.isXML = function( elem ) {
1434
+ // documentElement is verified for cases where it doesn't yet exist
1435
+ // (such as loading iframes in IE - #4833)
1436
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1437
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
1438
+ };
1439
+
1440
+ // Expose support vars for convenience
1441
+ support = Sizzle.support = {};
1442
+
1443
+ /**
1444
+ * Sets document-related variables once based on the current document
1445
+ * @param {Element|Object} [doc] An element or document object to use to set the document
1446
+ * @returns {Object} Returns the current document
1447
+ */
1448
+ setDocument = Sizzle.setDocument = function( node ) {
1449
+ var doc = node ? node.ownerDocument || node : preferredDoc,
1450
+ parent = doc.defaultView;
1451
+
1452
+ // If no document and documentElement is available, return
1453
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1454
+ return document;
1455
+ }
1456
+
1457
+ // Set our document
1458
+ document = doc;
1459
+ docElem = doc.documentElement;
1460
+
1461
+ // Support tests
1462
+ documentIsHTML = !isXML( doc );
1463
+
1464
+ // Support: IE>8
1465
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
1466
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
1467
+ // IE6-8 do not support the defaultView property so parent will be undefined
1468
+ if ( parent && parent.attachEvent && parent !== parent.top ) {
1469
+ parent.attachEvent( "onbeforeunload", function() {
1470
+ setDocument();
1471
+ });
1472
+ }
1473
+
1474
+ /* Attributes
1475
+ ---------------------------------------------------------------------- */
1476
+
1477
+ // Support: IE<8
1478
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
1479
+ support.attributes = assert(function( div ) {
1480
+ div.className = "i";
1481
+ return !div.getAttribute("className");
1482
+ });
1483
+
1484
+ /* getElement(s)By*
1485
+ ---------------------------------------------------------------------- */
1486
+
1487
+ // Check if getElementsByTagName("*") returns only elements
1488
+ support.getElementsByTagName = assert(function( div ) {
1489
+ div.appendChild( doc.createComment("") );
1490
+ return !div.getElementsByTagName("*").length;
1491
+ });
1492
+
1493
+ // Check if getElementsByClassName can be trusted
1494
+ support.getElementsByClassName = assert(function( div ) {
1495
+ div.innerHTML = "<div class='a'></div><div class='a i'></div>";
1496
+
1497
+ // Support: Safari<4
1498
+ // Catch class over-caching
1499
+ div.firstChild.className = "i";
1500
+ // Support: Opera<10
1501
+ // Catch gEBCN failure to find non-leading classes
1502
+ return div.getElementsByClassName("i").length === 2;
1503
+ });
1504
+
1505
+ // Support: IE<10
1506
+ // Check if getElementById returns elements by name
1507
+ // The broken getElementById methods don't pick up programatically-set names,
1508
+ // so use a roundabout getElementsByName test
1509
+ support.getById = assert(function( div ) {
1510
+ docElem.appendChild( div ).id = expando;
1511
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
1512
+ });
1513
+
1514
+ // ID find and filter
1515
+ if ( support.getById ) {
1516
+ Expr.find["ID"] = function( id, context ) {
1517
+ if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
1518
+ var m = context.getElementById( id );
1519
+ // Check parentNode to catch when Blackberry 4.6 returns
1520
+ // nodes that are no longer in the document #6963
1521
+ return m && m.parentNode ? [m] : [];
1522
+ }
1523
+ };
1524
+ Expr.filter["ID"] = function( id ) {
1525
+ var attrId = id.replace( runescape, funescape );
1526
+ return function( elem ) {
1527
+ return elem.getAttribute("id") === attrId;
1528
+ };
1529
+ };
1530
+ } else {
1531
+ // Support: IE6/7
1532
+ // getElementById is not reliable as a find shortcut
1533
+ delete Expr.find["ID"];
1534
+
1535
+ Expr.filter["ID"] = function( id ) {
1536
+ var attrId = id.replace( runescape, funescape );
1537
+ return function( elem ) {
1538
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
1539
+ return node && node.value === attrId;
1540
+ };
1541
+ };
1542
+ }
1543
+
1544
+ // Tag
1545
+ Expr.find["TAG"] = support.getElementsByTagName ?
1546
+ function( tag, context ) {
1547
+ if ( typeof context.getElementsByTagName !== strundefined ) {
1548
+ return context.getElementsByTagName( tag );
1549
+ }
1550
+ } :
1551
+ function( tag, context ) {
1552
+ var elem,
1553
+ tmp = [],
1554
+ i = 0,
1555
+ results = context.getElementsByTagName( tag );
1556
+
1557
+ // Filter out possible comments
1558
+ if ( tag === "*" ) {
1559
+ while ( (elem = results[i++]) ) {
1560
+ if ( elem.nodeType === 1 ) {
1561
+ tmp.push( elem );
1562
+ }
1563
+ }
1564
+
1565
+ return tmp;
1566
+ }
1567
+ return results;
1568
+ };
1569
+
1570
+ // Class
1571
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1572
+ if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
1573
+ return context.getElementsByClassName( className );
1574
+ }
1575
+ };
1576
+
1577
+ /* QSA/matchesSelector
1578
+ ---------------------------------------------------------------------- */
1579
+
1580
+ // QSA and matchesSelector support
1581
+
1582
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1583
+ rbuggyMatches = [];
1584
+
1585
+ // qSa(:focus) reports false when true (Chrome 21)
1586
+ // We allow this because of a bug in IE8/9 that throws an error
1587
+ // whenever `document.activeElement` is accessed on an iframe
1588
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
1589
+ // See http://bugs.jquery.com/ticket/13378
1590
+ rbuggyQSA = [];
1591
+
1592
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
1593
+ // Build QSA regex
1594
+ // Regex strategy adopted from Diego Perini
1595
+ assert(function( div ) {
1596
+ // Select is set to empty string on purpose
1597
+ // This is to test IE's treatment of not explicitly
1598
+ // setting a boolean content attribute,
1599
+ // since its presence should be enough
1600
+ // http://bugs.jquery.com/ticket/12359
1601
+ div.innerHTML = "<select><option selected=''></option></select>";
1602
+
1603
+ // Support: IE8
1604
+ // Boolean attributes and "value" are not treated correctly
1605
+ if ( !div.querySelectorAll("[selected]").length ) {
1606
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1607
+ }
1608
+
1609
+ // Webkit/Opera - :checked should return selected option elements
1610
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1611
+ // IE8 throws error here and will not see later tests
1612
+ if ( !div.querySelectorAll(":checked").length ) {
1613
+ rbuggyQSA.push(":checked");
1614
+ }
1615
+ });
1616
+
1617
+ assert(function( div ) {
1618
+
1619
+ // Support: Opera 10-12/IE8
1620
+ // ^= $= *= and empty values
1621
+ // Should not select anything
1622
+ // Support: Windows 8 Native Apps
1623
+ // The type attribute is restricted during .innerHTML assignment
1624
+ var input = doc.createElement("input");
1625
+ input.setAttribute( "type", "hidden" );
1626
+ div.appendChild( input ).setAttribute( "t", "" );
1627
+
1628
+ if ( div.querySelectorAll("[t^='']").length ) {
1629
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1630
+ }
1631
+
1632
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1633
+ // IE8 throws error here and will not see later tests
1634
+ if ( !div.querySelectorAll(":enabled").length ) {
1635
+ rbuggyQSA.push( ":enabled", ":disabled" );
1636
+ }
1637
+
1638
+ // Opera 10-11 does not throw on post-comma invalid pseudos
1639
+ div.querySelectorAll("*,:x");
1640
+ rbuggyQSA.push(",.*:");
1641
+ });
1642
+ }
1643
+
1644
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
1645
+ docElem.mozMatchesSelector ||
1646
+ docElem.oMatchesSelector ||
1647
+ docElem.msMatchesSelector) )) ) {
1648
+
1649
+ assert(function( div ) {
1650
+ // Check to see if it's possible to do matchesSelector
1651
+ // on a disconnected node (IE 9)
1652
+ support.disconnectedMatch = matches.call( div, "div" );
1653
+
1654
+ // This should fail with an exception
1655
+ // Gecko does not error, returns false instead
1656
+ matches.call( div, "[s!='']:x" );
1657
+ rbuggyMatches.push( "!=", pseudos );
1658
+ });
1659
+ }
1660
+
1661
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1662
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1663
+
1664
+ /* Contains
1665
+ ---------------------------------------------------------------------- */
1666
+
1667
+ // Element contains another
1668
+ // Purposefully does not implement inclusive descendent
1669
+ // As in, an element does not contain itself
1670
+ contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
1671
+ function( a, b ) {
1672
+ var adown = a.nodeType === 9 ? a.documentElement : a,
1673
+ bup = b && b.parentNode;
1674
+ return a === bup || !!( bup && bup.nodeType === 1 && (
1675
+ adown.contains ?
1676
+ adown.contains( bup ) :
1677
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1678
+ ));
1679
+ } :
1680
+ function( a, b ) {
1681
+ if ( b ) {
1682
+ while ( (b = b.parentNode) ) {
1683
+ if ( b === a ) {
1684
+ return true;
1685
+ }
1686
+ }
1687
+ }
1688
+ return false;
1689
+ };
1690
+
1691
+ /* Sorting
1692
+ ---------------------------------------------------------------------- */
1693
+
1694
+ // Document order sorting
1695
+ sortOrder = docElem.compareDocumentPosition ?
1696
+ function( a, b ) {
1697
+
1698
+ // Flag for duplicate removal
1699
+ if ( a === b ) {
1700
+ hasDuplicate = true;
1701
+ return 0;
1702
+ }
1703
+
1704
+ var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
1705
+
1706
+ if ( compare ) {
1707
+ // Disconnected nodes
1708
+ if ( compare & 1 ||
1709
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1710
+
1711
+ // Choose the first element that is related to our preferred document
1712
+ if ( a === doc || contains(preferredDoc, a) ) {
1713
+ return -1;
1714
+ }
1715
+ if ( b === doc || contains(preferredDoc, b) ) {
1716
+ return 1;
1717
+ }
1718
+
1719
+ // Maintain original order
1720
+ return sortInput ?
1721
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1722
+ 0;
1723
+ }
1724
+
1725
+ return compare & 4 ? -1 : 1;
1726
+ }
1727
+
1728
+ // Not directly comparable, sort on existence of method
1729
+ return a.compareDocumentPosition ? -1 : 1;
1730
+ } :
1731
+ function( a, b ) {
1732
+ var cur,
1733
+ i = 0,
1734
+ aup = a.parentNode,
1735
+ bup = b.parentNode,
1736
+ ap = [ a ],
1737
+ bp = [ b ];
1738
+
1739
+ // Exit early if the nodes are identical
1740
+ if ( a === b ) {
1741
+ hasDuplicate = true;
1742
+ return 0;
1743
+
1744
+ // Parentless nodes are either documents or disconnected
1745
+ } else if ( !aup || !bup ) {
1746
+ return a === doc ? -1 :
1747
+ b === doc ? 1 :
1748
+ aup ? -1 :
1749
+ bup ? 1 :
1750
+ sortInput ?
1751
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1752
+ 0;
1753
+
1754
+ // If the nodes are siblings, we can do a quick check
1755
+ } else if ( aup === bup ) {
1756
+ return siblingCheck( a, b );
1757
+ }
1758
+
1759
+ // Otherwise we need full lists of their ancestors for comparison
1760
+ cur = a;
1761
+ while ( (cur = cur.parentNode) ) {
1762
+ ap.unshift( cur );
1763
+ }
1764
+ cur = b;
1765
+ while ( (cur = cur.parentNode) ) {
1766
+ bp.unshift( cur );
1767
+ }
1768
+
1769
+ // Walk down the tree looking for a discrepancy
1770
+ while ( ap[i] === bp[i] ) {
1771
+ i++;
1772
+ }
1773
+
1774
+ return i ?
1775
+ // Do a sibling check if the nodes have a common ancestor
1776
+ siblingCheck( ap[i], bp[i] ) :
1777
+
1778
+ // Otherwise nodes in our document sort first
1779
+ ap[i] === preferredDoc ? -1 :
1780
+ bp[i] === preferredDoc ? 1 :
1781
+ 0;
1782
+ };
1783
+
1784
+ return doc;
1785
+ };
1786
+
1787
+ Sizzle.matches = function( expr, elements ) {
1788
+ return Sizzle( expr, null, null, elements );
1789
+ };
1790
+
1791
+ Sizzle.matchesSelector = function( elem, expr ) {
1792
+ // Set document vars if needed
1793
+ if ( ( elem.ownerDocument || elem ) !== document ) {
1794
+ setDocument( elem );
1795
+ }
1796
+
1797
+ // Make sure that attribute selectors are quoted
1798
+ expr = expr.replace( rattributeQuotes, "='$1']" );
1799
+
1800
+ if ( support.matchesSelector && documentIsHTML &&
1801
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1802
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
1803
+
1804
+ try {
1805
+ var ret = matches.call( elem, expr );
1806
+
1807
+ // IE 9's matchesSelector returns false on disconnected nodes
1808
+ if ( ret || support.disconnectedMatch ||
1809
+ // As well, disconnected nodes are said to be in a document
1810
+ // fragment in IE 9
1811
+ elem.document && elem.document.nodeType !== 11 ) {
1812
+ return ret;
1813
+ }
1814
+ } catch(e) {}
1815
+ }
1816
+
1817
+ return Sizzle( expr, document, null, [elem] ).length > 0;
1818
+ };
1819
+
1820
+ Sizzle.contains = function( context, elem ) {
1821
+ // Set document vars if needed
1822
+ if ( ( context.ownerDocument || context ) !== document ) {
1823
+ setDocument( context );
1824
+ }
1825
+ return contains( context, elem );
1826
+ };
1827
+
1828
+ Sizzle.attr = function( elem, name ) {
1829
+ // Set document vars if needed
1830
+ if ( ( elem.ownerDocument || elem ) !== document ) {
1831
+ setDocument( elem );
1832
+ }
1833
+
1834
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
1835
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
1836
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1837
+ fn( elem, name, !documentIsHTML ) :
1838
+ undefined;
1839
+
1840
+ return val === undefined ?
1841
+ support.attributes || !documentIsHTML ?
1842
+ elem.getAttribute( name ) :
1843
+ (val = elem.getAttributeNode(name)) && val.specified ?
1844
+ val.value :
1845
+ null :
1846
+ val;
1847
+ };
1848
+
1849
+ Sizzle.error = function( msg ) {
1850
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
1851
+ };
1852
+
1853
+ /**
1854
+ * Document sorting and removing duplicates
1855
+ * @param {ArrayLike} results
1856
+ */
1857
+ Sizzle.uniqueSort = function( results ) {
1858
+ var elem,
1859
+ duplicates = [],
1860
+ j = 0,
1861
+ i = 0;
1862
+
1863
+ // Unless we *know* we can detect duplicates, assume their presence
1864
+ hasDuplicate = !support.detectDuplicates;
1865
+ sortInput = !support.sortStable && results.slice( 0 );
1866
+ results.sort( sortOrder );
1867
+
1868
+ if ( hasDuplicate ) {
1869
+ while ( (elem = results[i++]) ) {
1870
+ if ( elem === results[ i ] ) {
1871
+ j = duplicates.push( i );
1872
+ }
1873
+ }
1874
+ while ( j-- ) {
1875
+ results.splice( duplicates[ j ], 1 );
1876
+ }
1877
+ }
1878
+
1879
+ return results;
1880
+ };
1881
+
1882
+ /**
1883
+ * Utility function for retrieving the text value of an array of DOM nodes
1884
+ * @param {Array|Element} elem
1885
+ */
1886
+ getText = Sizzle.getText = function( elem ) {
1887
+ var node,
1888
+ ret = "",
1889
+ i = 0,
1890
+ nodeType = elem.nodeType;
1891
+
1892
+ if ( !nodeType ) {
1893
+ // If no nodeType, this is expected to be an array
1894
+ for ( ; (node = elem[i]); i++ ) {
1895
+ // Do not traverse comment nodes
1896
+ ret += getText( node );
1897
+ }
1898
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1899
+ // Use textContent for elements
1900
+ // innerText usage removed for consistency of new lines (see #11153)
1901
+ if ( typeof elem.textContent === "string" ) {
1902
+ return elem.textContent;
1903
+ } else {
1904
+ // Traverse its children
1905
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1906
+ ret += getText( elem );
1907
+ }
1908
+ }
1909
+ } else if ( nodeType === 3 || nodeType === 4 ) {
1910
+ return elem.nodeValue;
1911
+ }
1912
+ // Do not include comment or processing instruction nodes
1913
+
1914
+ return ret;
1915
+ };
1916
+
1917
+ Expr = Sizzle.selectors = {
1918
+
1919
+ // Can be adjusted by the user
1920
+ cacheLength: 50,
1921
+
1922
+ createPseudo: markFunction,
1923
+
1924
+ match: matchExpr,
1925
+
1926
+ attrHandle: {},
1927
+
1928
+ find: {},
1929
+
1930
+ relative: {
1931
+ ">": { dir: "parentNode", first: true },
1932
+ " ": { dir: "parentNode" },
1933
+ "+": { dir: "previousSibling", first: true },
1934
+ "~": { dir: "previousSibling" }
1935
+ },
1936
+
1937
+ preFilter: {
1938
+ "ATTR": function( match ) {
1939
+ match[1] = match[1].replace( runescape, funescape );
1940
+
1941
+ // Move the given value to match[3] whether quoted or unquoted
1942
+ match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
1943
+
1944
+ if ( match[2] === "~=" ) {
1945
+ match[3] = " " + match[3] + " ";
1946
+ }
1947
+
1948
+ return match.slice( 0, 4 );
1949
+ },
1950
+
1951
+ "CHILD": function( match ) {
1952
+ /* matches from matchExpr["CHILD"]
1953
+ 1 type (only|nth|...)
1954
+ 2 what (child|of-type)
1955
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1956
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
1957
+ 5 sign of xn-component
1958
+ 6 x of xn-component
1959
+ 7 sign of y-component
1960
+ 8 y of y-component
1961
+ */
1962
+ match[1] = match[1].toLowerCase();
1963
+
1964
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
1965
+ // nth-* requires argument
1966
+ if ( !match[3] ) {
1967
+ Sizzle.error( match[0] );
1968
+ }
1969
+
1970
+ // numeric x and y parameters for Expr.filter.CHILD
1971
+ // remember that false/true cast respectively to 0/1
1972
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1973
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1974
+
1975
+ // other types prohibit arguments
1976
+ } else if ( match[3] ) {
1977
+ Sizzle.error( match[0] );
1978
+ }
1979
+
1980
+ return match;
1981
+ },
1982
+
1983
+ "PSEUDO": function( match ) {
1984
+ var excess,
1985
+ unquoted = !match[5] && match[2];
1986
+
1987
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
1988
+ return null;
1989
+ }
1990
+
1991
+ // Accept quoted arguments as-is
1992
+ if ( match[3] && match[4] !== undefined ) {
1993
+ match[2] = match[4];
1994
+
1995
+ // Strip excess characters from unquoted arguments
1996
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
1997
+ // Get excess from tokenize (recursively)
1998
+ (excess = tokenize( unquoted, true )) &&
1999
+ // advance to the next closing parenthesis
2000
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
2001
+
2002
+ // excess is a negative index
2003
+ match[0] = match[0].slice( 0, excess );
2004
+ match[2] = unquoted.slice( 0, excess );
2005
+ }
2006
+
2007
+ // Return only captures needed by the pseudo filter method (type and argument)
2008
+ return match.slice( 0, 3 );
2009
+ }
2010
+ },
2011
+
2012
+ filter: {
2013
+
2014
+ "TAG": function( nodeNameSelector ) {
2015
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
2016
+ return nodeNameSelector === "*" ?
2017
+ function() { return true; } :
2018
+ function( elem ) {
2019
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
2020
+ };
2021
+ },
2022
+
2023
+ "CLASS": function( className ) {
2024
+ var pattern = classCache[ className + " " ];
2025
+
2026
+ return pattern ||
2027
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
2028
+ classCache( className, function( elem ) {
2029
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
2030
+ });
2031
+ },
2032
+
2033
+ "ATTR": function( name, operator, check ) {
2034
+ return function( elem ) {
2035
+ var result = Sizzle.attr( elem, name );
2036
+
2037
+ if ( result == null ) {
2038
+ return operator === "!=";
2039
+ }
2040
+ if ( !operator ) {
2041
+ return true;
2042
+ }
2043
+
2044
+ result += "";
2045
+
2046
+ return operator === "=" ? result === check :
2047
+ operator === "!=" ? result !== check :
2048
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
2049
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
2050
+ operator === "$=" ? check && result.slice( -check.length ) === check :
2051
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
2052
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
2053
+ false;
2054
+ };
2055
+ },
2056
+
2057
+ "CHILD": function( type, what, argument, first, last ) {
2058
+ var simple = type.slice( 0, 3 ) !== "nth",
2059
+ forward = type.slice( -4 ) !== "last",
2060
+ ofType = what === "of-type";
2061
+
2062
+ return first === 1 && last === 0 ?
2063
+
2064
+ // Shortcut for :nth-*(n)
2065
+ function( elem ) {
2066
+ return !!elem.parentNode;
2067
+ } :
2068
+
2069
+ function( elem, context, xml ) {
2070
+ var cache, outerCache, node, diff, nodeIndex, start,
2071
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
2072
+ parent = elem.parentNode,
2073
+ name = ofType && elem.nodeName.toLowerCase(),
2074
+ useCache = !xml && !ofType;
2075
+
2076
+ if ( parent ) {
2077
+
2078
+ // :(first|last|only)-(child|of-type)
2079
+ if ( simple ) {
2080
+ while ( dir ) {
2081
+ node = elem;
2082
+ while ( (node = node[ dir ]) ) {
2083
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
2084
+ return false;
2085
+ }
2086
+ }
2087
+ // Reverse direction for :only-* (if we haven't yet done so)
2088
+ start = dir = type === "only" && !start && "nextSibling";
2089
+ }
2090
+ return true;
2091
+ }
2092
+
2093
+ start = [ forward ? parent.firstChild : parent.lastChild ];
2094
+
2095
+ // non-xml :nth-child(...) stores cache data on `parent`
2096
+ if ( forward && useCache ) {
2097
+ // Seek `elem` from a previously-cached index
2098
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
2099
+ cache = outerCache[ type ] || [];
2100
+ nodeIndex = cache[0] === dirruns && cache[1];
2101
+ diff = cache[0] === dirruns && cache[2];
2102
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
2103
+
2104
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
2105
+
2106
+ // Fallback to seeking `elem` from the start
2107
+ (diff = nodeIndex = 0) || start.pop()) ) {
2108
+
2109
+ // When found, cache indexes on `parent` and break
2110
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
2111
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
2112
+ break;
2113
+ }
2114
+ }
2115
+
2116
+ // Use previously-cached element index if available
2117
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
2118
+ diff = cache[1];
2119
+
2120
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
2121
+ } else {
2122
+ // Use the same loop as above to seek `elem` from the start
2123
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
2124
+ (diff = nodeIndex = 0) || start.pop()) ) {
2125
+
2126
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
2127
+ // Cache the index of each encountered element
2128
+ if ( useCache ) {
2129
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
2130
+ }
2131
+
2132
+ if ( node === elem ) {
2133
+ break;
2134
+ }
2135
+ }
2136
+ }
2137
+ }
2138
+
2139
+ // Incorporate the offset, then check against cycle size
2140
+ diff -= last;
2141
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
2142
+ }
2143
+ };
2144
+ },
2145
+
2146
+ "PSEUDO": function( pseudo, argument ) {
2147
+ // pseudo-class names are case-insensitive
2148
+ // http://www.w3.org/TR/selectors/#pseudo-classes
2149
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
2150
+ // Remember that setFilters inherits from pseudos
2151
+ var args,
2152
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
2153
+ Sizzle.error( "unsupported pseudo: " + pseudo );
2154
+
2155
+ // The user may use createPseudo to indicate that
2156
+ // arguments are needed to create the filter function
2157
+ // just as Sizzle does
2158
+ if ( fn[ expando ] ) {
2159
+ return fn( argument );
2160
+ }
2161
+
2162
+ // But maintain support for old signatures
2163
+ if ( fn.length > 1 ) {
2164
+ args = [ pseudo, pseudo, "", argument ];
2165
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
2166
+ markFunction(function( seed, matches ) {
2167
+ var idx,
2168
+ matched = fn( seed, argument ),
2169
+ i = matched.length;
2170
+ while ( i-- ) {
2171
+ idx = indexOf.call( seed, matched[i] );
2172
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
2173
+ }
2174
+ }) :
2175
+ function( elem ) {
2176
+ return fn( elem, 0, args );
2177
+ };
2178
+ }
2179
+
2180
+ return fn;
2181
+ }
2182
+ },
2183
+
2184
+ pseudos: {
2185
+ // Potentially complex pseudos
2186
+ "not": markFunction(function( selector ) {
2187
+ // Trim the selector passed to compile
2188
+ // to avoid treating leading and trailing
2189
+ // spaces as combinators
2190
+ var input = [],
2191
+ results = [],
2192
+ matcher = compile( selector.replace( rtrim, "$1" ) );
2193
+
2194
+ return matcher[ expando ] ?
2195
+ markFunction(function( seed, matches, context, xml ) {
2196
+ var elem,
2197
+ unmatched = matcher( seed, null, xml, [] ),
2198
+ i = seed.length;
2199
+
2200
+ // Match elements unmatched by `matcher`
2201
+ while ( i-- ) {
2202
+ if ( (elem = unmatched[i]) ) {
2203
+ seed[i] = !(matches[i] = elem);
2204
+ }
2205
+ }
2206
+ }) :
2207
+ function( elem, context, xml ) {
2208
+ input[0] = elem;
2209
+ matcher( input, null, xml, results );
2210
+ return !results.pop();
2211
+ };
2212
+ }),
2213
+
2214
+ "has": markFunction(function( selector ) {
2215
+ return function( elem ) {
2216
+ return Sizzle( selector, elem ).length > 0;
2217
+ };
2218
+ }),
2219
+
2220
+ "contains": markFunction(function( text ) {
2221
+ return function( elem ) {
2222
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
2223
+ };
2224
+ }),
2225
+
2226
+ // "Whether an element is represented by a :lang() selector
2227
+ // is based solely on the element's language value
2228
+ // being equal to the identifier C,
2229
+ // or beginning with the identifier C immediately followed by "-".
2230
+ // The matching of C against the element's language value is performed case-insensitively.
2231
+ // The identifier C does not have to be a valid language name."
2232
+ // http://www.w3.org/TR/selectors/#lang-pseudo
2233
+ "lang": markFunction( function( lang ) {
2234
+ // lang value must be a valid identifier
2235
+ if ( !ridentifier.test(lang || "") ) {
2236
+ Sizzle.error( "unsupported lang: " + lang );
2237
+ }
2238
+ lang = lang.replace( runescape, funescape ).toLowerCase();
2239
+ return function( elem ) {
2240
+ var elemLang;
2241
+ do {
2242
+ if ( (elemLang = documentIsHTML ?
2243
+ elem.lang :
2244
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2245
+
2246
+ elemLang = elemLang.toLowerCase();
2247
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2248
+ }
2249
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2250
+ return false;
2251
+ };
2252
+ }),
2253
+
2254
+ // Miscellaneous
2255
+ "target": function( elem ) {
2256
+ var hash = window.location && window.location.hash;
2257
+ return hash && hash.slice( 1 ) === elem.id;
2258
+ },
2259
+
2260
+ "root": function( elem ) {
2261
+ return elem === docElem;
2262
+ },
2263
+
2264
+ "focus": function( elem ) {
2265
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2266
+ },
2267
+
2268
+ // Boolean properties
2269
+ "enabled": function( elem ) {
2270
+ return elem.disabled === false;
2271
+ },
2272
+
2273
+ "disabled": function( elem ) {
2274
+ return elem.disabled === true;
2275
+ },
2276
+
2277
+ "checked": function( elem ) {
2278
+ // In CSS3, :checked should return both checked and selected elements
2279
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2280
+ var nodeName = elem.nodeName.toLowerCase();
2281
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2282
+ },
2283
+
2284
+ "selected": function( elem ) {
2285
+ // Accessing this property makes selected-by-default
2286
+ // options in Safari work properly
2287
+ if ( elem.parentNode ) {
2288
+ elem.parentNode.selectedIndex;
2289
+ }
2290
+
2291
+ return elem.selected === true;
2292
+ },
2293
+
2294
+ // Contents
2295
+ "empty": function( elem ) {
2296
+ // http://www.w3.org/TR/selectors/#empty-pseudo
2297
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
2298
+ // not comment, processing instructions, or others
2299
+ // Thanks to Diego Perini for the nodeName shortcut
2300
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
2301
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2302
+ if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
2303
+ return false;
2304
+ }
2305
+ }
2306
+ return true;
2307
+ },
2308
+
2309
+ "parent": function( elem ) {
2310
+ return !Expr.pseudos["empty"]( elem );
2311
+ },
2312
+
2313
+ // Element/input types
2314
+ "header": function( elem ) {
2315
+ return rheader.test( elem.nodeName );
2316
+ },
2317
+
2318
+ "input": function( elem ) {
2319
+ return rinputs.test( elem.nodeName );
2320
+ },
2321
+
2322
+ "button": function( elem ) {
2323
+ var name = elem.nodeName.toLowerCase();
2324
+ return name === "input" && elem.type === "button" || name === "button";
2325
+ },
2326
+
2327
+ "text": function( elem ) {
2328
+ var attr;
2329
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
2330
+ // use getAttribute instead to test this case
2331
+ return elem.nodeName.toLowerCase() === "input" &&
2332
+ elem.type === "text" &&
2333
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
2334
+ },
2335
+
2336
+ // Position-in-collection
2337
+ "first": createPositionalPseudo(function() {
2338
+ return [ 0 ];
2339
+ }),
2340
+
2341
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
2342
+ return [ length - 1 ];
2343
+ }),
2344
+
2345
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2346
+ return [ argument < 0 ? argument + length : argument ];
2347
+ }),
2348
+
2349
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
2350
+ var i = 0;
2351
+ for ( ; i < length; i += 2 ) {
2352
+ matchIndexes.push( i );
2353
+ }
2354
+ return matchIndexes;
2355
+ }),
2356
+
2357
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
2358
+ var i = 1;
2359
+ for ( ; i < length; i += 2 ) {
2360
+ matchIndexes.push( i );
2361
+ }
2362
+ return matchIndexes;
2363
+ }),
2364
+
2365
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2366
+ var i = argument < 0 ? argument + length : argument;
2367
+ for ( ; --i >= 0; ) {
2368
+ matchIndexes.push( i );
2369
+ }
2370
+ return matchIndexes;
2371
+ }),
2372
+
2373
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2374
+ var i = argument < 0 ? argument + length : argument;
2375
+ for ( ; ++i < length; ) {
2376
+ matchIndexes.push( i );
2377
+ }
2378
+ return matchIndexes;
2379
+ })
2380
+ }
2381
+ };
2382
+
2383
+ Expr.pseudos["nth"] = Expr.pseudos["eq"];
2384
+
2385
+ // Add button/input type pseudos
2386
+ for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2387
+ Expr.pseudos[ i ] = createInputPseudo( i );
2388
+ }
2389
+ for ( i in { submit: true, reset: true } ) {
2390
+ Expr.pseudos[ i ] = createButtonPseudo( i );
2391
+ }
2392
+
2393
+ // Easy API for creating new setFilters
2394
+ function setFilters() {}
2395
+ setFilters.prototype = Expr.filters = Expr.pseudos;
2396
+ Expr.setFilters = new setFilters();
2397
+
2398
+ function tokenize( selector, parseOnly ) {
2399
+ var matched, match, tokens, type,
2400
+ soFar, groups, preFilters,
2401
+ cached = tokenCache[ selector + " " ];
2402
+
2403
+ if ( cached ) {
2404
+ return parseOnly ? 0 : cached.slice( 0 );
2405
+ }
2406
+
2407
+ soFar = selector;
2408
+ groups = [];
2409
+ preFilters = Expr.preFilter;
2410
+
2411
+ while ( soFar ) {
2412
+
2413
+ // Comma and first run
2414
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
2415
+ if ( match ) {
2416
+ // Don't consume trailing commas as valid
2417
+ soFar = soFar.slice( match[0].length ) || soFar;
2418
+ }
2419
+ groups.push( tokens = [] );
2420
+ }
2421
+
2422
+ matched = false;
2423
+
2424
+ // Combinators
2425
+ if ( (match = rcombinators.exec( soFar )) ) {
2426
+ matched = match.shift();
2427
+ tokens.push({
2428
+ value: matched,
2429
+ // Cast descendant combinators to space
2430
+ type: match[0].replace( rtrim, " " )
2431
+ });
2432
+ soFar = soFar.slice( matched.length );
2433
+ }
2434
+
2435
+ // Filters
2436
+ for ( type in Expr.filter ) {
2437
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2438
+ (match = preFilters[ type ]( match ))) ) {
2439
+ matched = match.shift();
2440
+ tokens.push({
2441
+ value: matched,
2442
+ type: type,
2443
+ matches: match
2444
+ });
2445
+ soFar = soFar.slice( matched.length );
2446
+ }
2447
+ }
2448
+
2449
+ if ( !matched ) {
2450
+ break;
2451
+ }
2452
+ }
2453
+
2454
+ // Return the length of the invalid excess
2455
+ // if we're just parsing
2456
+ // Otherwise, throw an error or return tokens
2457
+ return parseOnly ?
2458
+ soFar.length :
2459
+ soFar ?
2460
+ Sizzle.error( selector ) :
2461
+ // Cache the tokens
2462
+ tokenCache( selector, groups ).slice( 0 );
2463
+ }
2464
+
2465
+ function toSelector( tokens ) {
2466
+ var i = 0,
2467
+ len = tokens.length,
2468
+ selector = "";
2469
+ for ( ; i < len; i++ ) {
2470
+ selector += tokens[i].value;
2471
+ }
2472
+ return selector;
2473
+ }
2474
+
2475
+ function addCombinator( matcher, combinator, base ) {
2476
+ var dir = combinator.dir,
2477
+ checkNonElements = base && dir === "parentNode",
2478
+ doneName = done++;
2479
+
2480
+ return combinator.first ?
2481
+ // Check against closest ancestor/preceding element
2482
+ function( elem, context, xml ) {
2483
+ while ( (elem = elem[ dir ]) ) {
2484
+ if ( elem.nodeType === 1 || checkNonElements ) {
2485
+ return matcher( elem, context, xml );
2486
+ }
2487
+ }
2488
+ } :
2489
+
2490
+ // Check against all ancestor/preceding elements
2491
+ function( elem, context, xml ) {
2492
+ var data, cache, outerCache,
2493
+ dirkey = dirruns + " " + doneName;
2494
+
2495
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
2496
+ if ( xml ) {
2497
+ while ( (elem = elem[ dir ]) ) {
2498
+ if ( elem.nodeType === 1 || checkNonElements ) {
2499
+ if ( matcher( elem, context, xml ) ) {
2500
+ return true;
2501
+ }
2502
+ }
2503
+ }
2504
+ } else {
2505
+ while ( (elem = elem[ dir ]) ) {
2506
+ if ( elem.nodeType === 1 || checkNonElements ) {
2507
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
2508
+ if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
2509
+ if ( (data = cache[1]) === true || data === cachedruns ) {
2510
+ return data === true;
2511
+ }
2512
+ } else {
2513
+ cache = outerCache[ dir ] = [ dirkey ];
2514
+ cache[1] = matcher( elem, context, xml ) || cachedruns;
2515
+ if ( cache[1] === true ) {
2516
+ return true;
2517
+ }
2518
+ }
2519
+ }
2520
+ }
2521
+ }
2522
+ };
2523
+ }
2524
+
2525
+ function elementMatcher( matchers ) {
2526
+ return matchers.length > 1 ?
2527
+ function( elem, context, xml ) {
2528
+ var i = matchers.length;
2529
+ while ( i-- ) {
2530
+ if ( !matchers[i]( elem, context, xml ) ) {
2531
+ return false;
2532
+ }
2533
+ }
2534
+ return true;
2535
+ } :
2536
+ matchers[0];
2537
+ }
2538
+
2539
+ function condense( unmatched, map, filter, context, xml ) {
2540
+ var elem,
2541
+ newUnmatched = [],
2542
+ i = 0,
2543
+ len = unmatched.length,
2544
+ mapped = map != null;
2545
+
2546
+ for ( ; i < len; i++ ) {
2547
+ if ( (elem = unmatched[i]) ) {
2548
+ if ( !filter || filter( elem, context, xml ) ) {
2549
+ newUnmatched.push( elem );
2550
+ if ( mapped ) {
2551
+ map.push( i );
2552
+ }
2553
+ }
2554
+ }
2555
+ }
2556
+
2557
+ return newUnmatched;
2558
+ }
2559
+
2560
+ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2561
+ if ( postFilter && !postFilter[ expando ] ) {
2562
+ postFilter = setMatcher( postFilter );
2563
+ }
2564
+ if ( postFinder && !postFinder[ expando ] ) {
2565
+ postFinder = setMatcher( postFinder, postSelector );
2566
+ }
2567
+ return markFunction(function( seed, results, context, xml ) {
2568
+ var temp, i, elem,
2569
+ preMap = [],
2570
+ postMap = [],
2571
+ preexisting = results.length,
2572
+
2573
+ // Get initial elements from seed or context
2574
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2575
+
2576
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
2577
+ matcherIn = preFilter && ( seed || !selector ) ?
2578
+ condense( elems, preMap, preFilter, context, xml ) :
2579
+ elems,
2580
+
2581
+ matcherOut = matcher ?
2582
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2583
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2584
+
2585
+ // ...intermediate processing is necessary
2586
+ [] :
2587
+
2588
+ // ...otherwise use results directly
2589
+ results :
2590
+ matcherIn;
2591
+
2592
+ // Find primary matches
2593
+ if ( matcher ) {
2594
+ matcher( matcherIn, matcherOut, context, xml );
2595
+ }
2596
+
2597
+ // Apply postFilter
2598
+ if ( postFilter ) {
2599
+ temp = condense( matcherOut, postMap );
2600
+ postFilter( temp, [], context, xml );
2601
+
2602
+ // Un-match failing elements by moving them back to matcherIn
2603
+ i = temp.length;
2604
+ while ( i-- ) {
2605
+ if ( (elem = temp[i]) ) {
2606
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2607
+ }
2608
+ }
2609
+ }
2610
+
2611
+ if ( seed ) {
2612
+ if ( postFinder || preFilter ) {
2613
+ if ( postFinder ) {
2614
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
2615
+ temp = [];
2616
+ i = matcherOut.length;
2617
+ while ( i-- ) {
2618
+ if ( (elem = matcherOut[i]) ) {
2619
+ // Restore matcherIn since elem is not yet a final match
2620
+ temp.push( (matcherIn[i] = elem) );
2621
+ }
2622
+ }
2623
+ postFinder( null, (matcherOut = []), temp, xml );
2624
+ }
2625
+
2626
+ // Move matched elements from seed to results to keep them synchronized
2627
+ i = matcherOut.length;
2628
+ while ( i-- ) {
2629
+ if ( (elem = matcherOut[i]) &&
2630
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
2631
+
2632
+ seed[temp] = !(results[temp] = elem);
2633
+ }
2634
+ }
2635
+ }
2636
+
2637
+ // Add elements to results, through postFinder if defined
2638
+ } else {
2639
+ matcherOut = condense(
2640
+ matcherOut === results ?
2641
+ matcherOut.splice( preexisting, matcherOut.length ) :
2642
+ matcherOut
2643
+ );
2644
+ if ( postFinder ) {
2645
+ postFinder( null, results, matcherOut, xml );
2646
+ } else {
2647
+ push.apply( results, matcherOut );
2648
+ }
2649
+ }
2650
+ });
2651
+ }
2652
+
2653
+ function matcherFromTokens( tokens ) {
2654
+ var checkContext, matcher, j,
2655
+ len = tokens.length,
2656
+ leadingRelative = Expr.relative[ tokens[0].type ],
2657
+ implicitRelative = leadingRelative || Expr.relative[" "],
2658
+ i = leadingRelative ? 1 : 0,
2659
+
2660
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
2661
+ matchContext = addCombinator( function( elem ) {
2662
+ return elem === checkContext;
2663
+ }, implicitRelative, true ),
2664
+ matchAnyContext = addCombinator( function( elem ) {
2665
+ return indexOf.call( checkContext, elem ) > -1;
2666
+ }, implicitRelative, true ),
2667
+ matchers = [ function( elem, context, xml ) {
2668
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2669
+ (checkContext = context).nodeType ?
2670
+ matchContext( elem, context, xml ) :
2671
+ matchAnyContext( elem, context, xml ) );
2672
+ } ];
2673
+
2674
+ for ( ; i < len; i++ ) {
2675
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2676
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2677
+ } else {
2678
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2679
+
2680
+ // Return special upon seeing a positional matcher
2681
+ if ( matcher[ expando ] ) {
2682
+ // Find the next relative operator (if any) for proper handling
2683
+ j = ++i;
2684
+ for ( ; j < len; j++ ) {
2685
+ if ( Expr.relative[ tokens[j].type ] ) {
2686
+ break;
2687
+ }
2688
+ }
2689
+ return setMatcher(
2690
+ i > 1 && elementMatcher( matchers ),
2691
+ i > 1 && toSelector(
2692
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2693
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2694
+ ).replace( rtrim, "$1" ),
2695
+ matcher,
2696
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
2697
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2698
+ j < len && toSelector( tokens )
2699
+ );
2700
+ }
2701
+ matchers.push( matcher );
2702
+ }
2703
+ }
2704
+
2705
+ return elementMatcher( matchers );
2706
+ }
2707
+
2708
+ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2709
+ // A counter to specify which element is currently being matched
2710
+ var matcherCachedRuns = 0,
2711
+ bySet = setMatchers.length > 0,
2712
+ byElement = elementMatchers.length > 0,
2713
+ superMatcher = function( seed, context, xml, results, expandContext ) {
2714
+ var elem, j, matcher,
2715
+ setMatched = [],
2716
+ matchedCount = 0,
2717
+ i = "0",
2718
+ unmatched = seed && [],
2719
+ outermost = expandContext != null,
2720
+ contextBackup = outermostContext,
2721
+ // We must always have either seed elements or context
2722
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
2723
+ // Use integer dirruns iff this is the outermost matcher
2724
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
2725
+
2726
+ if ( outermost ) {
2727
+ outermostContext = context !== document && context;
2728
+ cachedruns = matcherCachedRuns;
2729
+ }
2730
+
2731
+ // Add elements passing elementMatchers directly to results
2732
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
2733
+ for ( ; (elem = elems[i]) != null; i++ ) {
2734
+ if ( byElement && elem ) {
2735
+ j = 0;
2736
+ while ( (matcher = elementMatchers[j++]) ) {
2737
+ if ( matcher( elem, context, xml ) ) {
2738
+ results.push( elem );
2739
+ break;
2740
+ }
2741
+ }
2742
+ if ( outermost ) {
2743
+ dirruns = dirrunsUnique;
2744
+ cachedruns = ++matcherCachedRuns;
2745
+ }
2746
+ }
2747
+
2748
+ // Track unmatched elements for set filters
2749
+ if ( bySet ) {
2750
+ // They will have gone through all possible matchers
2751
+ if ( (elem = !matcher && elem) ) {
2752
+ matchedCount--;
2753
+ }
2754
+
2755
+ // Lengthen the array for every element, matched or not
2756
+ if ( seed ) {
2757
+ unmatched.push( elem );
2758
+ }
2759
+ }
2760
+ }
2761
+
2762
+ // Apply set filters to unmatched elements
2763
+ matchedCount += i;
2764
+ if ( bySet && i !== matchedCount ) {
2765
+ j = 0;
2766
+ while ( (matcher = setMatchers[j++]) ) {
2767
+ matcher( unmatched, setMatched, context, xml );
2768
+ }
2769
+
2770
+ if ( seed ) {
2771
+ // Reintegrate element matches to eliminate the need for sorting
2772
+ if ( matchedCount > 0 ) {
2773
+ while ( i-- ) {
2774
+ if ( !(unmatched[i] || setMatched[i]) ) {
2775
+ setMatched[i] = pop.call( results );
2776
+ }
2777
+ }
2778
+ }
2779
+
2780
+ // Discard index placeholder values to get only actual matches
2781
+ setMatched = condense( setMatched );
2782
+ }
2783
+
2784
+ // Add matches to results
2785
+ push.apply( results, setMatched );
2786
+
2787
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
2788
+ if ( outermost && !seed && setMatched.length > 0 &&
2789
+ ( matchedCount + setMatchers.length ) > 1 ) {
2790
+
2791
+ Sizzle.uniqueSort( results );
2792
+ }
2793
+ }
2794
+
2795
+ // Override manipulation of globals by nested matchers
2796
+ if ( outermost ) {
2797
+ dirruns = dirrunsUnique;
2798
+ outermostContext = contextBackup;
2799
+ }
2800
+
2801
+ return unmatched;
2802
+ };
2803
+
2804
+ return bySet ?
2805
+ markFunction( superMatcher ) :
2806
+ superMatcher;
2807
+ }
2808
+
2809
+ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
2810
+ var i,
2811
+ setMatchers = [],
2812
+ elementMatchers = [],
2813
+ cached = compilerCache[ selector + " " ];
2814
+
2815
+ if ( !cached ) {
2816
+ // Generate a function of recursive functions that can be used to check each element
2817
+ if ( !group ) {
2818
+ group = tokenize( selector );
2819
+ }
2820
+ i = group.length;
2821
+ while ( i-- ) {
2822
+ cached = matcherFromTokens( group[i] );
2823
+ if ( cached[ expando ] ) {
2824
+ setMatchers.push( cached );
2825
+ } else {
2826
+ elementMatchers.push( cached );
2827
+ }
2828
+ }
2829
+
2830
+ // Cache the compiled function
2831
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2832
+ }
2833
+ return cached;
2834
+ };
2835
+
2836
+ function multipleContexts( selector, contexts, results ) {
2837
+ var i = 0,
2838
+ len = contexts.length;
2839
+ for ( ; i < len; i++ ) {
2840
+ Sizzle( selector, contexts[i], results );
2841
+ }
2842
+ return results;
2843
+ }
2844
+
2845
+ function select( selector, context, results, seed ) {
2846
+ var i, tokens, token, type, find,
2847
+ match = tokenize( selector );
2848
+
2849
+ if ( !seed ) {
2850
+ // Try to minimize operations if there is only one group
2851
+ if ( match.length === 1 ) {
2852
+
2853
+ // Take a shortcut and set the context if the root selector is an ID
2854
+ tokens = match[0] = match[0].slice( 0 );
2855
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2856
+ support.getById && context.nodeType === 9 && documentIsHTML &&
2857
+ Expr.relative[ tokens[1].type ] ) {
2858
+
2859
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2860
+ if ( !context ) {
2861
+ return results;
2862
+ }
2863
+ selector = selector.slice( tokens.shift().value.length );
2864
+ }
2865
+
2866
+ // Fetch a seed set for right-to-left matching
2867
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2868
+ while ( i-- ) {
2869
+ token = tokens[i];
2870
+
2871
+ // Abort if we hit a combinator
2872
+ if ( Expr.relative[ (type = token.type) ] ) {
2873
+ break;
2874
+ }
2875
+ if ( (find = Expr.find[ type ]) ) {
2876
+ // Search, expanding context for leading sibling combinators
2877
+ if ( (seed = find(
2878
+ token.matches[0].replace( runescape, funescape ),
2879
+ rsibling.test( tokens[0].type ) && context.parentNode || context
2880
+ )) ) {
2881
+
2882
+ // If seed is empty or no tokens remain, we can return early
2883
+ tokens.splice( i, 1 );
2884
+ selector = seed.length && toSelector( tokens );
2885
+ if ( !selector ) {
2886
+ push.apply( results, seed );
2887
+ return results;
2888
+ }
2889
+
2890
+ break;
2891
+ }
2892
+ }
2893
+ }
2894
+ }
2895
+ }
2896
+
2897
+ // Compile and execute a filtering function
2898
+ // Provide `match` to avoid retokenization if we modified the selector above
2899
+ compile( selector, match )(
2900
+ seed,
2901
+ context,
2902
+ !documentIsHTML,
2903
+ results,
2904
+ rsibling.test( selector )
2905
+ );
2906
+ return results;
2907
+ }
2908
+
2909
+ // One-time assignments
2910
+
2911
+ // Sort stability
2912
+ support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2913
+
2914
+ // Support: Chrome<14
2915
+ // Always assume duplicates if they aren't passed to the comparison function
2916
+ support.detectDuplicates = hasDuplicate;
2917
+
2918
+ // Initialize against the default document
2919
+ setDocument();
2920
+
2921
+ // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2922
+ // Detached nodes confoundingly follow *each other*
2923
+ support.sortDetached = assert(function( div1 ) {
2924
+ // Should return 1, but returns 4 (following)
2925
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2926
+ });
2927
+
2928
+ // Support: IE<8
2929
+ // Prevent attribute/property "interpolation"
2930
+ // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2931
+ if ( !assert(function( div ) {
2932
+ div.innerHTML = "<a href='#'></a>";
2933
+ return div.firstChild.getAttribute("href") === "#" ;
2934
+ }) ) {
2935
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
2936
+ if ( !isXML ) {
2937
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2938
+ }
2939
+ });
2940
+ }
2941
+
2942
+ // Support: IE<9
2943
+ // Use defaultValue in place of getAttribute("value")
2944
+ if ( !support.attributes || !assert(function( div ) {
2945
+ div.innerHTML = "<input/>";
2946
+ div.firstChild.setAttribute( "value", "" );
2947
+ return div.firstChild.getAttribute( "value" ) === "";
2948
+ }) ) {
2949
+ addHandle( "value", function( elem, name, isXML ) {
2950
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2951
+ return elem.defaultValue;
2952
+ }
2953
+ });
2954
+ }
2955
+
2956
+ // Support: IE<9
2957
+ // Use getAttributeNode to fetch booleans when getAttribute lies
2958
+ if ( !assert(function( div ) {
2959
+ return div.getAttribute("disabled") == null;
2960
+ }) ) {
2961
+ addHandle( booleans, function( elem, name, isXML ) {
2962
+ var val;
2963
+ if ( !isXML ) {
2964
+ return (val = elem.getAttributeNode( name )) && val.specified ?
2965
+ val.value :
2966
+ elem[ name ] === true ? name.toLowerCase() : null;
2967
+ }
2968
+ });
2969
+ }
2970
+
2971
+ jQuery.find = Sizzle;
2972
+ jQuery.expr = Sizzle.selectors;
2973
+ jQuery.expr[":"] = jQuery.expr.pseudos;
2974
+ jQuery.unique = Sizzle.uniqueSort;
2975
+ jQuery.text = Sizzle.getText;
2976
+ jQuery.isXMLDoc = Sizzle.isXML;
2977
+ jQuery.contains = Sizzle.contains;
2978
+
2979
+
2980
+ })( window );
2981
+ // String to Object options format cache
2982
+ var optionsCache = {};
2983
+
2984
+ // Convert String-formatted options into Object-formatted ones and store in cache
2985
+ function createOptions( options ) {
2986
+ var object = optionsCache[ options ] = {};
2987
+ jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
2988
+ object[ flag ] = true;
2989
+ });
2990
+ return object;
2991
+ }
2992
+
2993
+ /*
2994
+ * Create a callback list using the following parameters:
2995
+ *
2996
+ * options: an optional list of space-separated options that will change how
2997
+ * the callback list behaves or a more traditional option object
2998
+ *
2999
+ * By default a callback list will act like an event callback list and can be
3000
+ * "fired" multiple times.
3001
+ *
3002
+ * Possible options:
3003
+ *
3004
+ * once: will ensure the callback list can only be fired once (like a Deferred)
3005
+ *
3006
+ * memory: will keep track of previous values and will call any callback added
3007
+ * after the list has been fired right away with the latest "memorized"
3008
+ * values (like a Deferred)
3009
+ *
3010
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
3011
+ *
3012
+ * stopOnFalse: interrupt callings when a callback returns false
3013
+ *
3014
+ */
3015
+ jQuery.Callbacks = function( options ) {
3016
+
3017
+ // Convert options from String-formatted to Object-formatted if needed
3018
+ // (we check in cache first)
3019
+ options = typeof options === "string" ?
3020
+ ( optionsCache[ options ] || createOptions( options ) ) :
3021
+ jQuery.extend( {}, options );
3022
+
3023
+ var // Flag to know if list is currently firing
3024
+ firing,
3025
+ // Last fire value (for non-forgettable lists)
3026
+ memory,
3027
+ // Flag to know if list was already fired
3028
+ fired,
3029
+ // End of the loop when firing
3030
+ firingLength,
3031
+ // Index of currently firing callback (modified by remove if needed)
3032
+ firingIndex,
3033
+ // First callback to fire (used internally by add and fireWith)
3034
+ firingStart,
3035
+ // Actual callback list
3036
+ list = [],
3037
+ // Stack of fire calls for repeatable lists
3038
+ stack = !options.once && [],
3039
+ // Fire callbacks
3040
+ fire = function( data ) {
3041
+ memory = options.memory && data;
3042
+ fired = true;
3043
+ firingIndex = firingStart || 0;
3044
+ firingStart = 0;
3045
+ firingLength = list.length;
3046
+ firing = true;
3047
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
3048
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
3049
+ memory = false; // To prevent further calls using add
3050
+ break;
3051
+ }
3052
+ }
3053
+ firing = false;
3054
+ if ( list ) {
3055
+ if ( stack ) {
3056
+ if ( stack.length ) {
3057
+ fire( stack.shift() );
3058
+ }
3059
+ } else if ( memory ) {
3060
+ list = [];
3061
+ } else {
3062
+ self.disable();
3063
+ }
3064
+ }
3065
+ },
3066
+ // Actual Callbacks object
3067
+ self = {
3068
+ // Add a callback or a collection of callbacks to the list
3069
+ add: function() {
3070
+ if ( list ) {
3071
+ // First, we save the current length
3072
+ var start = list.length;
3073
+ (function add( args ) {
3074
+ jQuery.each( args, function( _, arg ) {
3075
+ var type = jQuery.type( arg );
3076
+ if ( type === "function" ) {
3077
+ if ( !options.unique || !self.has( arg ) ) {
3078
+ list.push( arg );
3079
+ }
3080
+ } else if ( arg && arg.length && type !== "string" ) {
3081
+ // Inspect recursively
3082
+ add( arg );
3083
+ }
3084
+ });
3085
+ })( arguments );
3086
+ // Do we need to add the callbacks to the
3087
+ // current firing batch?
3088
+ if ( firing ) {
3089
+ firingLength = list.length;
3090
+ // With memory, if we're not firing then
3091
+ // we should call right away
3092
+ } else if ( memory ) {
3093
+ firingStart = start;
3094
+ fire( memory );
3095
+ }
3096
+ }
3097
+ return this;
3098
+ },
3099
+ // Remove a callback from the list
3100
+ remove: function() {
3101
+ if ( list ) {
3102
+ jQuery.each( arguments, function( _, arg ) {
3103
+ var index;
3104
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3105
+ list.splice( index, 1 );
3106
+ // Handle firing indexes
3107
+ if ( firing ) {
3108
+ if ( index <= firingLength ) {
3109
+ firingLength--;
3110
+ }
3111
+ if ( index <= firingIndex ) {
3112
+ firingIndex--;
3113
+ }
3114
+ }
3115
+ }
3116
+ });
3117
+ }
3118
+ return this;
3119
+ },
3120
+ // Check if a given callback is in the list.
3121
+ // If no argument is given, return whether or not list has callbacks attached.
3122
+ has: function( fn ) {
3123
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
3124
+ },
3125
+ // Remove all callbacks from the list
3126
+ empty: function() {
3127
+ list = [];
3128
+ firingLength = 0;
3129
+ return this;
3130
+ },
3131
+ // Have the list do nothing anymore
3132
+ disable: function() {
3133
+ list = stack = memory = undefined;
3134
+ return this;
3135
+ },
3136
+ // Is it disabled?
3137
+ disabled: function() {
3138
+ return !list;
3139
+ },
3140
+ // Lock the list in its current state
3141
+ lock: function() {
3142
+ stack = undefined;
3143
+ if ( !memory ) {
3144
+ self.disable();
3145
+ }
3146
+ return this;
3147
+ },
3148
+ // Is it locked?
3149
+ locked: function() {
3150
+ return !stack;
3151
+ },
3152
+ // Call all callbacks with the given context and arguments
3153
+ fireWith: function( context, args ) {
3154
+ if ( list && ( !fired || stack ) ) {
3155
+ args = args || [];
3156
+ args = [ context, args.slice ? args.slice() : args ];
3157
+ if ( firing ) {
3158
+ stack.push( args );
3159
+ } else {
3160
+ fire( args );
3161
+ }
3162
+ }
3163
+ return this;
3164
+ },
3165
+ // Call all the callbacks with the given arguments
3166
+ fire: function() {
3167
+ self.fireWith( this, arguments );
3168
+ return this;
3169
+ },
3170
+ // To know if the callbacks have already been called at least once
3171
+ fired: function() {
3172
+ return !!fired;
3173
+ }
3174
+ };
3175
+
3176
+ return self;
3177
+ };
3178
+ jQuery.extend({
3179
+
3180
+ Deferred: function( func ) {
3181
+ var tuples = [
3182
+ // action, add listener, listener list, final state
3183
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
3184
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
3185
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
3186
+ ],
3187
+ state = "pending",
3188
+ promise = {
3189
+ state: function() {
3190
+ return state;
3191
+ },
3192
+ always: function() {
3193
+ deferred.done( arguments ).fail( arguments );
3194
+ return this;
3195
+ },
3196
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
3197
+ var fns = arguments;
3198
+ return jQuery.Deferred(function( newDefer ) {
3199
+ jQuery.each( tuples, function( i, tuple ) {
3200
+ var action = tuple[ 0 ],
3201
+ fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3202
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
3203
+ deferred[ tuple[1] ](function() {
3204
+ var returned = fn && fn.apply( this, arguments );
3205
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
3206
+ returned.promise()
3207
+ .done( newDefer.resolve )
3208
+ .fail( newDefer.reject )
3209
+ .progress( newDefer.notify );
3210
+ } else {
3211
+ newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
3212
+ }
3213
+ });
3214
+ });
3215
+ fns = null;
3216
+ }).promise();
3217
+ },
3218
+ // Get a promise for this deferred
3219
+ // If obj is provided, the promise aspect is added to the object
3220
+ promise: function( obj ) {
3221
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
3222
+ }
3223
+ },
3224
+ deferred = {};
3225
+
3226
+ // Keep pipe for back-compat
3227
+ promise.pipe = promise.then;
3228
+
3229
+ // Add list-specific methods
3230
+ jQuery.each( tuples, function( i, tuple ) {
3231
+ var list = tuple[ 2 ],
3232
+ stateString = tuple[ 3 ];
3233
+
3234
+ // promise[ done | fail | progress ] = list.add
3235
+ promise[ tuple[1] ] = list.add;
3236
+
3237
+ // Handle state
3238
+ if ( stateString ) {
3239
+ list.add(function() {
3240
+ // state = [ resolved | rejected ]
3241
+ state = stateString;
3242
+
3243
+ // [ reject_list | resolve_list ].disable; progress_list.lock
3244
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3245
+ }
3246
+
3247
+ // deferred[ resolve | reject | notify ]
3248
+ deferred[ tuple[0] ] = function() {
3249
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
3250
+ return this;
3251
+ };
3252
+ deferred[ tuple[0] + "With" ] = list.fireWith;
3253
+ });
3254
+
3255
+ // Make the deferred a promise
3256
+ promise.promise( deferred );
3257
+
3258
+ // Call given func if any
3259
+ if ( func ) {
3260
+ func.call( deferred, deferred );
3261
+ }
3262
+
3263
+ // All done!
3264
+ return deferred;
3265
+ },
3266
+
3267
+ // Deferred helper
3268
+ when: function( subordinate /* , ..., subordinateN */ ) {
3269
+ var i = 0,
3270
+ resolveValues = core_slice.call( arguments ),
3271
+ length = resolveValues.length,
3272
+
3273
+ // the count of uncompleted subordinates
3274
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3275
+
3276
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
3277
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3278
+
3279
+ // Update function for both resolve and progress values
3280
+ updateFunc = function( i, contexts, values ) {
3281
+ return function( value ) {
3282
+ contexts[ i ] = this;
3283
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
3284
+ if( values === progressValues ) {
3285
+ deferred.notifyWith( contexts, values );
3286
+ } else if ( !( --remaining ) ) {
3287
+ deferred.resolveWith( contexts, values );
3288
+ }
3289
+ };
3290
+ },
3291
+
3292
+ progressValues, progressContexts, resolveContexts;
3293
+
3294
+ // add listeners to Deferred subordinates; treat others as resolved
3295
+ if ( length > 1 ) {
3296
+ progressValues = new Array( length );
3297
+ progressContexts = new Array( length );
3298
+ resolveContexts = new Array( length );
3299
+ for ( ; i < length; i++ ) {
3300
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3301
+ resolveValues[ i ].promise()
3302
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
3303
+ .fail( deferred.reject )
3304
+ .progress( updateFunc( i, progressContexts, progressValues ) );
3305
+ } else {
3306
+ --remaining;
3307
+ }
3308
+ }
3309
+ }
3310
+
3311
+ // if we're not waiting on anything, resolve the master
3312
+ if ( !remaining ) {
3313
+ deferred.resolveWith( resolveContexts, resolveValues );
3314
+ }
3315
+
3316
+ return deferred.promise();
3317
+ }
3318
+ });
3319
+ jQuery.support = (function( support ) {
3320
+
3321
+ var all, a, input, select, fragment, opt, eventName, isSupported, i,
3322
+ div = document.createElement("div");
3323
+
3324
+ // Setup
3325
+ div.setAttribute( "className", "t" );
3326
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
3327
+
3328
+ // Finish early in limited (non-browser) environments
3329
+ all = div.getElementsByTagName("*") || [];
3330
+ a = div.getElementsByTagName("a")[ 0 ];
3331
+ if ( !a || !a.style || !all.length ) {
3332
+ return support;
3333
+ }
3334
+
3335
+ // First batch of tests
3336
+ select = document.createElement("select");
3337
+ opt = select.appendChild( document.createElement("option") );
3338
+ input = div.getElementsByTagName("input")[ 0 ];
3339
+
3340
+ a.style.cssText = "top:1px;float:left;opacity:.5";
3341
+
3342
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
3343
+ support.getSetAttribute = div.className !== "t";
3344
+
3345
+ // IE strips leading whitespace when .innerHTML is used
3346
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
3347
+
3348
+ // Make sure that tbody elements aren't automatically inserted
3349
+ // IE will insert them into empty tables
3350
+ support.tbody = !div.getElementsByTagName("tbody").length;
3351
+
3352
+ // Make sure that link elements get serialized correctly by innerHTML
3353
+ // This requires a wrapper element in IE
3354
+ support.htmlSerialize = !!div.getElementsByTagName("link").length;
3355
+
3356
+ // Get the style information from getAttribute
3357
+ // (IE uses .cssText instead)
3358
+ support.style = /top/.test( a.getAttribute("style") );
3359
+
3360
+ // Make sure that URLs aren't manipulated
3361
+ // (IE normalizes it by default)
3362
+ support.hrefNormalized = a.getAttribute("href") === "/a";
3363
+
3364
+ // Make sure that element opacity exists
3365
+ // (IE uses filter instead)
3366
+ // Use a regex to work around a WebKit issue. See #5145
3367
+ support.opacity = /^0.5/.test( a.style.opacity );
3368
+
3369
+ // Verify style float existence
3370
+ // (IE uses styleFloat instead of cssFloat)
3371
+ support.cssFloat = !!a.style.cssFloat;
3372
+
3373
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
3374
+ support.checkOn = !!input.value;
3375
+
3376
+ // Make sure that a selected-by-default option has a working selected property.
3377
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
3378
+ support.optSelected = opt.selected;
3379
+
3380
+ // Tests for enctype support on a form (#6743)
3381
+ support.enctype = !!document.createElement("form").enctype;
3382
+
3383
+ // Makes sure cloning an html5 element does not cause problems
3384
+ // Where outerHTML is undefined, this still works
3385
+ support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>";
3386
+
3387
+ // Will be defined later
3388
+ support.inlineBlockNeedsLayout = false;
3389
+ support.shrinkWrapBlocks = false;
3390
+ support.pixelPosition = false;
3391
+ support.deleteExpando = true;
3392
+ support.noCloneEvent = true;
3393
+ support.reliableMarginRight = true;
3394
+ support.boxSizingReliable = true;
3395
+
3396
+ // Make sure checked status is properly cloned
3397
+ input.checked = true;
3398
+ support.noCloneChecked = input.cloneNode( true ).checked;
3399
+
3400
+ // Make sure that the options inside disabled selects aren't marked as disabled
3401
+ // (WebKit marks them as disabled)
3402
+ select.disabled = true;
3403
+ support.optDisabled = !opt.disabled;
3404
+
3405
+ // Support: IE<9
3406
+ try {
3407
+ delete div.test;
3408
+ } catch( e ) {
3409
+ support.deleteExpando = false;
3410
+ }
3411
+
3412
+ // Check if we can trust getAttribute("value")
3413
+ input = document.createElement("input");
3414
+ input.setAttribute( "value", "" );
3415
+ support.input = input.getAttribute( "value" ) === "";
3416
+
3417
+ // Check if an input maintains its value after becoming a radio
3418
+ input.value = "t";
3419
+ input.setAttribute( "type", "radio" );
3420
+ support.radioValue = input.value === "t";
3421
+
3422
+ // #11217 - WebKit loses check when the name is after the checked attribute
3423
+ input.setAttribute( "checked", "t" );
3424
+ input.setAttribute( "name", "t" );
3425
+
3426
+ fragment = document.createDocumentFragment();
3427
+ fragment.appendChild( input );
3428
+
3429
+ // Check if a disconnected checkbox will retain its checked
3430
+ // value of true after appended to the DOM (IE6/7)
3431
+ support.appendChecked = input.checked;
3432
+
3433
+ // WebKit doesn't clone checked state correctly in fragments
3434
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
3435
+
3436
+ // Support: IE<9
3437
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
3438
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
3439
+ if ( div.attachEvent ) {
3440
+ div.attachEvent( "onclick", function() {
3441
+ support.noCloneEvent = false;
3442
+ });
3443
+
3444
+ div.cloneNode( true ).click();
3445
+ }
3446
+
3447
+ // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
3448
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
3449
+ for ( i in { submit: true, change: true, focusin: true }) {
3450
+ div.setAttribute( eventName = "on" + i, "t" );
3451
+
3452
+ support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
3453
+ }
3454
+
3455
+ div.style.backgroundClip = "content-box";
3456
+ div.cloneNode( true ).style.backgroundClip = "";
3457
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
3458
+
3459
+ // Support: IE<9
3460
+ // Iteration over object's inherited properties before its own.
3461
+ for ( i in jQuery( support ) ) {
3462
+ break;
3463
+ }
3464
+ support.ownLast = i !== "0";
3465
+
3466
+ // Run tests that need a body at doc ready
3467
+ jQuery(function() {
3468
+ var container, marginDiv, tds,
3469
+ divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
3470
+ body = document.getElementsByTagName("body")[0];
3471
+
3472
+ if ( !body ) {
3473
+ // Return for frameset docs that don't have a body
3474
+ return;
3475
+ }
3476
+
3477
+ container = document.createElement("div");
3478
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
3479
+
3480
+ body.appendChild( container ).appendChild( div );
3481
+
3482
+ // Support: IE8
3483
+ // Check if table cells still have offsetWidth/Height when they are set
3484
+ // to display:none and there are still other visible table cells in a
3485
+ // table row; if so, offsetWidth/Height are not reliable for use when
3486
+ // determining if an element has been hidden directly using
3487
+ // display:none (it is still safe to use offsets if a parent element is
3488
+ // hidden; don safety goggles and see bug #4512 for more information).
3489
+ div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
3490
+ tds = div.getElementsByTagName("td");
3491
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
3492
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
3493
+
3494
+ tds[ 0 ].style.display = "";
3495
+ tds[ 1 ].style.display = "none";
3496
+
3497
+ // Support: IE8
3498
+ // Check if empty table cells still have offsetWidth/Height
3499
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
3500
+
3501
+ // Check box-sizing and margin behavior.
3502
+ div.innerHTML = "";
3503
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
3504
+
3505
+ // Workaround failing boxSizing test due to offsetWidth returning wrong value
3506
+ // with some non-1 values of body zoom, ticket #13543
3507
+ jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
3508
+ support.boxSizing = div.offsetWidth === 4;
3509
+ });
3510
+
3511
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
3512
+ if ( window.getComputedStyle ) {
3513
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
3514
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
3515
+
3516
+ // Check if div with explicit width and no margin-right incorrectly
3517
+ // gets computed margin-right based on width of container. (#3333)
3518
+ // Fails in WebKit before Feb 2011 nightlies
3519
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
3520
+ marginDiv = div.appendChild( document.createElement("div") );
3521
+ marginDiv.style.cssText = div.style.cssText = divReset;
3522
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
3523
+ div.style.width = "1px";
3524
+
3525
+ support.reliableMarginRight =
3526
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
3527
+ }
3528
+
3529
+ if ( typeof div.style.zoom !== core_strundefined ) {
3530
+ // Support: IE<8
3531
+ // Check if natively block-level elements act like inline-block
3532
+ // elements when setting their display to 'inline' and giving
3533
+ // them layout
3534
+ div.innerHTML = "";
3535
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
3536
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
3537
+
3538
+ // Support: IE6
3539
+ // Check if elements with layout shrink-wrap their children
3540
+ div.style.display = "block";
3541
+ div.innerHTML = "<div></div>";
3542
+ div.firstChild.style.width = "5px";
3543
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
3544
+
3545
+ if ( support.inlineBlockNeedsLayout ) {
3546
+ // Prevent IE 6 from affecting layout for positioned elements #11048
3547
+ // Prevent IE from shrinking the body in IE 7 mode #12869
3548
+ // Support: IE<8
3549
+ body.style.zoom = 1;
3550
+ }
3551
+ }
3552
+
3553
+ body.removeChild( container );
3554
+
3555
+ // Null elements to avoid leaks in IE
3556
+ container = div = tds = marginDiv = null;
3557
+ });
3558
+
3559
+ // Null elements to avoid leaks in IE
3560
+ all = select = fragment = opt = a = input = null;
3561
+
3562
+ return support;
3563
+ })({});
3564
+
3565
+ var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
3566
+ rmultiDash = /([A-Z])/g;
3567
+
3568
+ function internalData( elem, name, data, pvt /* Internal Use Only */ ){
3569
+ if ( !jQuery.acceptData( elem ) ) {
3570
+ return;
3571
+ }
3572
+
3573
+ var ret, thisCache,
3574
+ internalKey = jQuery.expando,
3575
+
3576
+ // We have to handle DOM nodes and JS objects differently because IE6-7
3577
+ // can't GC object references properly across the DOM-JS boundary
3578
+ isNode = elem.nodeType,
3579
+
3580
+ // Only DOM nodes need the global jQuery cache; JS object data is
3581
+ // attached directly to the object so GC can occur automatically
3582
+ cache = isNode ? jQuery.cache : elem,
3583
+
3584
+ // Only defining an ID for JS objects if its cache already exists allows
3585
+ // the code to shortcut on the same path as a DOM node with no cache
3586
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
3587
+
3588
+ // Avoid doing any more work than we need to when trying to get data on an
3589
+ // object that has no data at all
3590
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
3591
+ return;
3592
+ }
3593
+
3594
+ if ( !id ) {
3595
+ // Only DOM nodes need a new unique ID for each element since their data
3596
+ // ends up in the global cache
3597
+ if ( isNode ) {
3598
+ id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++;
3599
+ } else {
3600
+ id = internalKey;
3601
+ }
3602
+ }
3603
+
3604
+ if ( !cache[ id ] ) {
3605
+ // Avoid exposing jQuery metadata on plain JS objects when the object
3606
+ // is serialized using JSON.stringify
3607
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
3608
+ }
3609
+
3610
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
3611
+ // shallow copied over onto the existing cache
3612
+ if ( typeof name === "object" || typeof name === "function" ) {
3613
+ if ( pvt ) {
3614
+ cache[ id ] = jQuery.extend( cache[ id ], name );
3615
+ } else {
3616
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
3617
+ }
3618
+ }
3619
+
3620
+ thisCache = cache[ id ];
3621
+
3622
+ // jQuery data() is stored in a separate object inside the object's internal data
3623
+ // cache in order to avoid key collisions between internal data and user-defined
3624
+ // data.
3625
+ if ( !pvt ) {
3626
+ if ( !thisCache.data ) {
3627
+ thisCache.data = {};
3628
+ }
3629
+
3630
+ thisCache = thisCache.data;
3631
+ }
3632
+
3633
+ if ( data !== undefined ) {
3634
+ thisCache[ jQuery.camelCase( name ) ] = data;
3635
+ }
3636
+
3637
+ // Check for both converted-to-camel and non-converted data property names
3638
+ // If a data property was specified
3639
+ if ( typeof name === "string" ) {
3640
+
3641
+ // First Try to find as-is property data
3642
+ ret = thisCache[ name ];
3643
+
3644
+ // Test for null|undefined property data
3645
+ if ( ret == null ) {
3646
+
3647
+ // Try to find the camelCased property
3648
+ ret = thisCache[ jQuery.camelCase( name ) ];
3649
+ }
3650
+ } else {
3651
+ ret = thisCache;
3652
+ }
3653
+
3654
+ return ret;
3655
+ }
3656
+
3657
+ function internalRemoveData( elem, name, pvt ) {
3658
+ if ( !jQuery.acceptData( elem ) ) {
3659
+ return;
3660
+ }
3661
+
3662
+ var thisCache, i,
3663
+ isNode = elem.nodeType,
3664
+
3665
+ // See jQuery.data for more information
3666
+ cache = isNode ? jQuery.cache : elem,
3667
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
3668
+
3669
+ // If there is already no cache entry for this object, there is no
3670
+ // purpose in continuing
3671
+ if ( !cache[ id ] ) {
3672
+ return;
3673
+ }
3674
+
3675
+ if ( name ) {
3676
+
3677
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
3678
+
3679
+ if ( thisCache ) {
3680
+
3681
+ // Support array or space separated string names for data keys
3682
+ if ( !jQuery.isArray( name ) ) {
3683
+
3684
+ // try the string as a key before any manipulation
3685
+ if ( name in thisCache ) {
3686
+ name = [ name ];
3687
+ } else {
3688
+
3689
+ // split the camel cased version by spaces unless a key with the spaces exists
3690
+ name = jQuery.camelCase( name );
3691
+ if ( name in thisCache ) {
3692
+ name = [ name ];
3693
+ } else {
3694
+ name = name.split(" ");
3695
+ }
3696
+ }
3697
+ } else {
3698
+ // If "name" is an array of keys...
3699
+ // When data is initially created, via ("key", "val") signature,
3700
+ // keys will be converted to camelCase.
3701
+ // Since there is no way to tell _how_ a key was added, remove
3702
+ // both plain key and camelCase key. #12786
3703
+ // This will only penalize the array argument path.
3704
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
3705
+ }
3706
+
3707
+ i = name.length;
3708
+ while ( i-- ) {
3709
+ delete thisCache[ name[i] ];
3710
+ }
3711
+
3712
+ // If there is no data left in the cache, we want to continue
3713
+ // and let the cache object itself get destroyed
3714
+ if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
3715
+ return;
3716
+ }
3717
+ }
3718
+ }
3719
+
3720
+ // See jQuery.data for more information
3721
+ if ( !pvt ) {
3722
+ delete cache[ id ].data;
3723
+
3724
+ // Don't destroy the parent cache unless the internal data object
3725
+ // had been the only thing left in it
3726
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
3727
+ return;
3728
+ }
3729
+ }
3730
+
3731
+ // Destroy the cache
3732
+ if ( isNode ) {
3733
+ jQuery.cleanData( [ elem ], true );
3734
+
3735
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
3736
+ /* jshint eqeqeq: false */
3737
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
3738
+ /* jshint eqeqeq: true */
3739
+ delete cache[ id ];
3740
+
3741
+ // When all else fails, null
3742
+ } else {
3743
+ cache[ id ] = null;
3744
+ }
3745
+ }
3746
+
3747
+ jQuery.extend({
3748
+ cache: {},
3749
+
3750
+ // The following elements throw uncatchable exceptions if you
3751
+ // attempt to add expando properties to them.
3752
+ noData: {
3753
+ "applet": true,
3754
+ "embed": true,
3755
+ // Ban all objects except for Flash (which handle expandos)
3756
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
3757
+ },
3758
+
3759
+ hasData: function( elem ) {
3760
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
3761
+ return !!elem && !isEmptyDataObject( elem );
3762
+ },
3763
+
3764
+ data: function( elem, name, data ) {
3765
+ return internalData( elem, name, data );
3766
+ },
3767
+
3768
+ removeData: function( elem, name ) {
3769
+ return internalRemoveData( elem, name );
3770
+ },
3771
+
3772
+ // For internal use only.
3773
+ _data: function( elem, name, data ) {
3774
+ return internalData( elem, name, data, true );
3775
+ },
3776
+
3777
+ _removeData: function( elem, name ) {
3778
+ return internalRemoveData( elem, name, true );
3779
+ },
3780
+
3781
+ // A method for determining if a DOM node can handle the data expando
3782
+ acceptData: function( elem ) {
3783
+ // Do not set data on non-element because it will not be cleared (#8335).
3784
+ if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
3785
+ return false;
3786
+ }
3787
+
3788
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
3789
+
3790
+ // nodes accept data unless otherwise specified; rejection can be conditional
3791
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
3792
+ }
3793
+ });
3794
+
3795
+ jQuery.fn.extend({
3796
+ data: function( key, value ) {
3797
+ var attrs, name,
3798
+ data = null,
3799
+ i = 0,
3800
+ elem = this[0];
3801
+
3802
+ // Special expections of .data basically thwart jQuery.access,
3803
+ // so implement the relevant behavior ourselves
3804
+
3805
+ // Gets all values
3806
+ if ( key === undefined ) {
3807
+ if ( this.length ) {
3808
+ data = jQuery.data( elem );
3809
+
3810
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
3811
+ attrs = elem.attributes;
3812
+ for ( ; i < attrs.length; i++ ) {
3813
+ name = attrs[i].name;
3814
+
3815
+ if ( name.indexOf("data-") === 0 ) {
3816
+ name = jQuery.camelCase( name.slice(5) );
3817
+
3818
+ dataAttr( elem, name, data[ name ] );
3819
+ }
3820
+ }
3821
+ jQuery._data( elem, "parsedAttrs", true );
3822
+ }
3823
+ }
3824
+
3825
+ return data;
3826
+ }
3827
+
3828
+ // Sets multiple values
3829
+ if ( typeof key === "object" ) {
3830
+ return this.each(function() {
3831
+ jQuery.data( this, key );
3832
+ });
3833
+ }
3834
+
3835
+ return arguments.length > 1 ?
3836
+
3837
+ // Sets one value
3838
+ this.each(function() {
3839
+ jQuery.data( this, key, value );
3840
+ }) :
3841
+
3842
+ // Gets one value
3843
+ // Try to fetch any internally stored data first
3844
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
3845
+ },
3846
+
3847
+ removeData: function( key ) {
3848
+ return this.each(function() {
3849
+ jQuery.removeData( this, key );
3850
+ });
3851
+ }
3852
+ });
3853
+
3854
+ function dataAttr( elem, key, data ) {
3855
+ // If nothing was found internally, try to fetch any
3856
+ // data from the HTML5 data-* attribute
3857
+ if ( data === undefined && elem.nodeType === 1 ) {
3858
+
3859
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
3860
+
3861
+ data = elem.getAttribute( name );
3862
+
3863
+ if ( typeof data === "string" ) {
3864
+ try {
3865
+ data = data === "true" ? true :
3866
+ data === "false" ? false :
3867
+ data === "null" ? null :
3868
+ // Only convert to a number if it doesn't change the string
3869
+ +data + "" === data ? +data :
3870
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
3871
+ data;
3872
+ } catch( e ) {}
3873
+
3874
+ // Make sure we set the data so it isn't changed later
3875
+ jQuery.data( elem, key, data );
3876
+
3877
+ } else {
3878
+ data = undefined;
3879
+ }
3880
+ }
3881
+
3882
+ return data;
3883
+ }
3884
+
3885
+ // checks a cache object for emptiness
3886
+ function isEmptyDataObject( obj ) {
3887
+ var name;
3888
+ for ( name in obj ) {
3889
+
3890
+ // if the public data object is empty, the private is still empty
3891
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
3892
+ continue;
3893
+ }
3894
+ if ( name !== "toJSON" ) {
3895
+ return false;
3896
+ }
3897
+ }
3898
+
3899
+ return true;
3900
+ }
3901
+ jQuery.extend({
3902
+ queue: function( elem, type, data ) {
3903
+ var queue;
3904
+
3905
+ if ( elem ) {
3906
+ type = ( type || "fx" ) + "queue";
3907
+ queue = jQuery._data( elem, type );
3908
+
3909
+ // Speed up dequeue by getting out quickly if this is just a lookup
3910
+ if ( data ) {
3911
+ if ( !queue || jQuery.isArray(data) ) {
3912
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
3913
+ } else {
3914
+ queue.push( data );
3915
+ }
3916
+ }
3917
+ return queue || [];
3918
+ }
3919
+ },
3920
+
3921
+ dequeue: function( elem, type ) {
3922
+ type = type || "fx";
3923
+
3924
+ var queue = jQuery.queue( elem, type ),
3925
+ startLength = queue.length,
3926
+ fn = queue.shift(),
3927
+ hooks = jQuery._queueHooks( elem, type ),
3928
+ next = function() {
3929
+ jQuery.dequeue( elem, type );
3930
+ };
3931
+
3932
+ // If the fx queue is dequeued, always remove the progress sentinel
3933
+ if ( fn === "inprogress" ) {
3934
+ fn = queue.shift();
3935
+ startLength--;
3936
+ }
3937
+
3938
+ if ( fn ) {
3939
+
3940
+ // Add a progress sentinel to prevent the fx queue from being
3941
+ // automatically dequeued
3942
+ if ( type === "fx" ) {
3943
+ queue.unshift( "inprogress" );
3944
+ }
3945
+
3946
+ // clear up the last queue stop function
3947
+ delete hooks.stop;
3948
+ fn.call( elem, next, hooks );
3949
+ }
3950
+
3951
+ if ( !startLength && hooks ) {
3952
+ hooks.empty.fire();
3953
+ }
3954
+ },
3955
+
3956
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
3957
+ _queueHooks: function( elem, type ) {
3958
+ var key = type + "queueHooks";
3959
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
3960
+ empty: jQuery.Callbacks("once memory").add(function() {
3961
+ jQuery._removeData( elem, type + "queue" );
3962
+ jQuery._removeData( elem, key );
3963
+ })
3964
+ });
3965
+ }
3966
+ });
3967
+
3968
+ jQuery.fn.extend({
3969
+ queue: function( type, data ) {
3970
+ var setter = 2;
3971
+
3972
+ if ( typeof type !== "string" ) {
3973
+ data = type;
3974
+ type = "fx";
3975
+ setter--;
3976
+ }
3977
+
3978
+ if ( arguments.length < setter ) {
3979
+ return jQuery.queue( this[0], type );
3980
+ }
3981
+
3982
+ return data === undefined ?
3983
+ this :
3984
+ this.each(function() {
3985
+ var queue = jQuery.queue( this, type, data );
3986
+
3987
+ // ensure a hooks for this queue
3988
+ jQuery._queueHooks( this, type );
3989
+
3990
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
3991
+ jQuery.dequeue( this, type );
3992
+ }
3993
+ });
3994
+ },
3995
+ dequeue: function( type ) {
3996
+ return this.each(function() {
3997
+ jQuery.dequeue( this, type );
3998
+ });
3999
+ },
4000
+ // Based off of the plugin by Clint Helfers, with permission.
4001
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
4002
+ delay: function( time, type ) {
4003
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
4004
+ type = type || "fx";
4005
+
4006
+ return this.queue( type, function( next, hooks ) {
4007
+ var timeout = setTimeout( next, time );
4008
+ hooks.stop = function() {
4009
+ clearTimeout( timeout );
4010
+ };
4011
+ });
4012
+ },
4013
+ clearQueue: function( type ) {
4014
+ return this.queue( type || "fx", [] );
4015
+ },
4016
+ // Get a promise resolved when queues of a certain type
4017
+ // are emptied (fx is the type by default)
4018
+ promise: function( type, obj ) {
4019
+ var tmp,
4020
+ count = 1,
4021
+ defer = jQuery.Deferred(),
4022
+ elements = this,
4023
+ i = this.length,
4024
+ resolve = function() {
4025
+ if ( !( --count ) ) {
4026
+ defer.resolveWith( elements, [ elements ] );
4027
+ }
4028
+ };
4029
+
4030
+ if ( typeof type !== "string" ) {
4031
+ obj = type;
4032
+ type = undefined;
4033
+ }
4034
+ type = type || "fx";
4035
+
4036
+ while( i-- ) {
4037
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
4038
+ if ( tmp && tmp.empty ) {
4039
+ count++;
4040
+ tmp.empty.add( resolve );
4041
+ }
4042
+ }
4043
+ resolve();
4044
+ return defer.promise( obj );
4045
+ }
4046
+ });
4047
+ var nodeHook, boolHook,
4048
+ rclass = /[\t\r\n\f]/g,
4049
+ rreturn = /\r/g,
4050
+ rfocusable = /^(?:input|select|textarea|button|object)$/i,
4051
+ rclickable = /^(?:a|area)$/i,
4052
+ ruseDefault = /^(?:checked|selected)$/i,
4053
+ getSetAttribute = jQuery.support.getSetAttribute,
4054
+ getSetInput = jQuery.support.input;
4055
+
4056
+ jQuery.fn.extend({
4057
+ attr: function( name, value ) {
4058
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
4059
+ },
4060
+
4061
+ removeAttr: function( name ) {
4062
+ return this.each(function() {
4063
+ jQuery.removeAttr( this, name );
4064
+ });
4065
+ },
4066
+
4067
+ prop: function( name, value ) {
4068
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
4069
+ },
4070
+
4071
+ removeProp: function( name ) {
4072
+ name = jQuery.propFix[ name ] || name;
4073
+ return this.each(function() {
4074
+ // try/catch handles cases where IE balks (such as removing a property on window)
4075
+ try {
4076
+ this[ name ] = undefined;
4077
+ delete this[ name ];
4078
+ } catch( e ) {}
4079
+ });
4080
+ },
4081
+
4082
+ addClass: function( value ) {
4083
+ var classes, elem, cur, clazz, j,
4084
+ i = 0,
4085
+ len = this.length,
4086
+ proceed = typeof value === "string" && value;
4087
+
4088
+ if ( jQuery.isFunction( value ) ) {
4089
+ return this.each(function( j ) {
4090
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
4091
+ });
4092
+ }
4093
+
4094
+ if ( proceed ) {
4095
+ // The disjunction here is for better compressibility (see removeClass)
4096
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
4097
+
4098
+ for ( ; i < len; i++ ) {
4099
+ elem = this[ i ];
4100
+ cur = elem.nodeType === 1 && ( elem.className ?
4101
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
4102
+ " "
4103
+ );
4104
+
4105
+ if ( cur ) {
4106
+ j = 0;
4107
+ while ( (clazz = classes[j++]) ) {
4108
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
4109
+ cur += clazz + " ";
4110
+ }
4111
+ }
4112
+ elem.className = jQuery.trim( cur );
4113
+
4114
+ }
4115
+ }
4116
+ }
4117
+
4118
+ return this;
4119
+ },
4120
+
4121
+ removeClass: function( value ) {
4122
+ var classes, elem, cur, clazz, j,
4123
+ i = 0,
4124
+ len = this.length,
4125
+ proceed = arguments.length === 0 || typeof value === "string" && value;
4126
+
4127
+ if ( jQuery.isFunction( value ) ) {
4128
+ return this.each(function( j ) {
4129
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
4130
+ });
4131
+ }
4132
+ if ( proceed ) {
4133
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
4134
+
4135
+ for ( ; i < len; i++ ) {
4136
+ elem = this[ i ];
4137
+ // This expression is here for better compressibility (see addClass)
4138
+ cur = elem.nodeType === 1 && ( elem.className ?
4139
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
4140
+ ""
4141
+ );
4142
+
4143
+ if ( cur ) {
4144
+ j = 0;
4145
+ while ( (clazz = classes[j++]) ) {
4146
+ // Remove *all* instances
4147
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
4148
+ cur = cur.replace( " " + clazz + " ", " " );
4149
+ }
4150
+ }
4151
+ elem.className = value ? jQuery.trim( cur ) : "";
4152
+ }
4153
+ }
4154
+ }
4155
+
4156
+ return this;
4157
+ },
4158
+
4159
+ toggleClass: function( value, stateVal ) {
4160
+ var type = typeof value;
4161
+
4162
+ if ( typeof stateVal === "boolean" && type === "string" ) {
4163
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
4164
+ }
4165
+
4166
+ if ( jQuery.isFunction( value ) ) {
4167
+ return this.each(function( i ) {
4168
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
4169
+ });
4170
+ }
4171
+
4172
+ return this.each(function() {
4173
+ if ( type === "string" ) {
4174
+ // toggle individual class names
4175
+ var className,
4176
+ i = 0,
4177
+ self = jQuery( this ),
4178
+ classNames = value.match( core_rnotwhite ) || [];
4179
+
4180
+ while ( (className = classNames[ i++ ]) ) {
4181
+ // check each className given, space separated list
4182
+ if ( self.hasClass( className ) ) {
4183
+ self.removeClass( className );
4184
+ } else {
4185
+ self.addClass( className );
4186
+ }
4187
+ }
4188
+
4189
+ // Toggle whole class name
4190
+ } else if ( type === core_strundefined || type === "boolean" ) {
4191
+ if ( this.className ) {
4192
+ // store className if set
4193
+ jQuery._data( this, "__className__", this.className );
4194
+ }
4195
+
4196
+ // If the element has a class name or if we're passed "false",
4197
+ // then remove the whole classname (if there was one, the above saved it).
4198
+ // Otherwise bring back whatever was previously saved (if anything),
4199
+ // falling back to the empty string if nothing was stored.
4200
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
4201
+ }
4202
+ });
4203
+ },
4204
+
4205
+ hasClass: function( selector ) {
4206
+ var className = " " + selector + " ",
4207
+ i = 0,
4208
+ l = this.length;
4209
+ for ( ; i < l; i++ ) {
4210
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
4211
+ return true;
4212
+ }
4213
+ }
4214
+
4215
+ return false;
4216
+ },
4217
+
4218
+ val: function( value ) {
4219
+ var ret, hooks, isFunction,
4220
+ elem = this[0];
4221
+
4222
+ if ( !arguments.length ) {
4223
+ if ( elem ) {
4224
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
4225
+
4226
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
4227
+ return ret;
4228
+ }
4229
+
4230
+ ret = elem.value;
4231
+
4232
+ return typeof ret === "string" ?
4233
+ // handle most common string cases
4234
+ ret.replace(rreturn, "") :
4235
+ // handle cases where value is null/undef or number
4236
+ ret == null ? "" : ret;
4237
+ }
4238
+
4239
+ return;
4240
+ }
4241
+
4242
+ isFunction = jQuery.isFunction( value );
4243
+
4244
+ return this.each(function( i ) {
4245
+ var val;
4246
+
4247
+ if ( this.nodeType !== 1 ) {
4248
+ return;
4249
+ }
4250
+
4251
+ if ( isFunction ) {
4252
+ val = value.call( this, i, jQuery( this ).val() );
4253
+ } else {
4254
+ val = value;
4255
+ }
4256
+
4257
+ // Treat null/undefined as ""; convert numbers to string
4258
+ if ( val == null ) {
4259
+ val = "";
4260
+ } else if ( typeof val === "number" ) {
4261
+ val += "";
4262
+ } else if ( jQuery.isArray( val ) ) {
4263
+ val = jQuery.map(val, function ( value ) {
4264
+ return value == null ? "" : value + "";
4265
+ });
4266
+ }
4267
+
4268
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
4269
+
4270
+ // If set returns undefined, fall back to normal setting
4271
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
4272
+ this.value = val;
4273
+ }
4274
+ });
4275
+ }
4276
+ });
4277
+
4278
+ jQuery.extend({
4279
+ valHooks: {
4280
+ option: {
4281
+ get: function( elem ) {
4282
+ // Use proper attribute retrieval(#6932, #12072)
4283
+ var val = jQuery.find.attr( elem, "value" );
4284
+ return val != null ?
4285
+ val :
4286
+ elem.text;
4287
+ }
4288
+ },
4289
+ select: {
4290
+ get: function( elem ) {
4291
+ var value, option,
4292
+ options = elem.options,
4293
+ index = elem.selectedIndex,
4294
+ one = elem.type === "select-one" || index < 0,
4295
+ values = one ? null : [],
4296
+ max = one ? index + 1 : options.length,
4297
+ i = index < 0 ?
4298
+ max :
4299
+ one ? index : 0;
4300
+
4301
+ // Loop through all the selected options
4302
+ for ( ; i < max; i++ ) {
4303
+ option = options[ i ];
4304
+
4305
+ // oldIE doesn't update selected after form reset (#2551)
4306
+ if ( ( option.selected || i === index ) &&
4307
+ // Don't return options that are disabled or in a disabled optgroup
4308
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
4309
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
4310
+
4311
+ // Get the specific value for the option
4312
+ value = jQuery( option ).val();
4313
+
4314
+ // We don't need an array for one selects
4315
+ if ( one ) {
4316
+ return value;
4317
+ }
4318
+
4319
+ // Multi-Selects return an array
4320
+ values.push( value );
4321
+ }
4322
+ }
4323
+
4324
+ return values;
4325
+ },
4326
+
4327
+ set: function( elem, value ) {
4328
+ var optionSet, option,
4329
+ options = elem.options,
4330
+ values = jQuery.makeArray( value ),
4331
+ i = options.length;
4332
+
4333
+ while ( i-- ) {
4334
+ option = options[ i ];
4335
+ if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
4336
+ optionSet = true;
4337
+ }
4338
+ }
4339
+
4340
+ // force browsers to behave consistently when non-matching value is set
4341
+ if ( !optionSet ) {
4342
+ elem.selectedIndex = -1;
4343
+ }
4344
+ return values;
4345
+ }
4346
+ }
4347
+ },
4348
+
4349
+ attr: function( elem, name, value ) {
4350
+ var hooks, ret,
4351
+ nType = elem.nodeType;
4352
+
4353
+ // don't get/set attributes on text, comment and attribute nodes
4354
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4355
+ return;
4356
+ }
4357
+
4358
+ // Fallback to prop when attributes are not supported
4359
+ if ( typeof elem.getAttribute === core_strundefined ) {
4360
+ return jQuery.prop( elem, name, value );
4361
+ }
4362
+
4363
+ // All attributes are lowercase
4364
+ // Grab necessary hook if one is defined
4365
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
4366
+ name = name.toLowerCase();
4367
+ hooks = jQuery.attrHooks[ name ] ||
4368
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
4369
+ }
4370
+
4371
+ if ( value !== undefined ) {
4372
+
4373
+ if ( value === null ) {
4374
+ jQuery.removeAttr( elem, name );
4375
+
4376
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
4377
+ return ret;
4378
+
4379
+ } else {
4380
+ elem.setAttribute( name, value + "" );
4381
+ return value;
4382
+ }
4383
+
4384
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
4385
+ return ret;
4386
+
4387
+ } else {
4388
+ ret = jQuery.find.attr( elem, name );
4389
+
4390
+ // Non-existent attributes return null, we normalize to undefined
4391
+ return ret == null ?
4392
+ undefined :
4393
+ ret;
4394
+ }
4395
+ },
4396
+
4397
+ removeAttr: function( elem, value ) {
4398
+ var name, propName,
4399
+ i = 0,
4400
+ attrNames = value && value.match( core_rnotwhite );
4401
+
4402
+ if ( attrNames && elem.nodeType === 1 ) {
4403
+ while ( (name = attrNames[i++]) ) {
4404
+ propName = jQuery.propFix[ name ] || name;
4405
+
4406
+ // Boolean attributes get special treatment (#10870)
4407
+ if ( jQuery.expr.match.bool.test( name ) ) {
4408
+ // Set corresponding property to false
4409
+ if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
4410
+ elem[ propName ] = false;
4411
+ // Support: IE<9
4412
+ // Also clear defaultChecked/defaultSelected (if appropriate)
4413
+ } else {
4414
+ elem[ jQuery.camelCase( "default-" + name ) ] =
4415
+ elem[ propName ] = false;
4416
+ }
4417
+
4418
+ // See #9699 for explanation of this approach (setting first, then removal)
4419
+ } else {
4420
+ jQuery.attr( elem, name, "" );
4421
+ }
4422
+
4423
+ elem.removeAttribute( getSetAttribute ? name : propName );
4424
+ }
4425
+ }
4426
+ },
4427
+
4428
+ attrHooks: {
4429
+ type: {
4430
+ set: function( elem, value ) {
4431
+ if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
4432
+ // Setting the type on a radio button after the value resets the value in IE6-9
4433
+ // Reset value to default in case type is set after value during creation
4434
+ var val = elem.value;
4435
+ elem.setAttribute( "type", value );
4436
+ if ( val ) {
4437
+ elem.value = val;
4438
+ }
4439
+ return value;
4440
+ }
4441
+ }
4442
+ }
4443
+ },
4444
+
4445
+ propFix: {
4446
+ "for": "htmlFor",
4447
+ "class": "className"
4448
+ },
4449
+
4450
+ prop: function( elem, name, value ) {
4451
+ var ret, hooks, notxml,
4452
+ nType = elem.nodeType;
4453
+
4454
+ // don't get/set properties on text, comment and attribute nodes
4455
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4456
+ return;
4457
+ }
4458
+
4459
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
4460
+
4461
+ if ( notxml ) {
4462
+ // Fix name and attach hooks
4463
+ name = jQuery.propFix[ name ] || name;
4464
+ hooks = jQuery.propHooks[ name ];
4465
+ }
4466
+
4467
+ if ( value !== undefined ) {
4468
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
4469
+ ret :
4470
+ ( elem[ name ] = value );
4471
+
4472
+ } else {
4473
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
4474
+ ret :
4475
+ elem[ name ];
4476
+ }
4477
+ },
4478
+
4479
+ propHooks: {
4480
+ tabIndex: {
4481
+ get: function( elem ) {
4482
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
4483
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
4484
+ // Use proper attribute retrieval(#12072)
4485
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
4486
+
4487
+ return tabindex ?
4488
+ parseInt( tabindex, 10 ) :
4489
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
4490
+ 0 :
4491
+ -1;
4492
+ }
4493
+ }
4494
+ }
4495
+ });
4496
+
4497
+ // Hooks for boolean attributes
4498
+ boolHook = {
4499
+ set: function( elem, value, name ) {
4500
+ if ( value === false ) {
4501
+ // Remove boolean attributes when set to false
4502
+ jQuery.removeAttr( elem, name );
4503
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
4504
+ // IE<8 needs the *property* name
4505
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
4506
+
4507
+ // Use defaultChecked and defaultSelected for oldIE
4508
+ } else {
4509
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
4510
+ }
4511
+
4512
+ return name;
4513
+ }
4514
+ };
4515
+ jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
4516
+ var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
4517
+
4518
+ jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
4519
+ function( elem, name, isXML ) {
4520
+ var fn = jQuery.expr.attrHandle[ name ],
4521
+ ret = isXML ?
4522
+ undefined :
4523
+ /* jshint eqeqeq: false */
4524
+ (jQuery.expr.attrHandle[ name ] = undefined) !=
4525
+ getter( elem, name, isXML ) ?
4526
+
4527
+ name.toLowerCase() :
4528
+ null;
4529
+ jQuery.expr.attrHandle[ name ] = fn;
4530
+ return ret;
4531
+ } :
4532
+ function( elem, name, isXML ) {
4533
+ return isXML ?
4534
+ undefined :
4535
+ elem[ jQuery.camelCase( "default-" + name ) ] ?
4536
+ name.toLowerCase() :
4537
+ null;
4538
+ };
4539
+ });
4540
+
4541
+ // fix oldIE attroperties
4542
+ if ( !getSetInput || !getSetAttribute ) {
4543
+ jQuery.attrHooks.value = {
4544
+ set: function( elem, value, name ) {
4545
+ if ( jQuery.nodeName( elem, "input" ) ) {
4546
+ // Does not return so that setAttribute is also used
4547
+ elem.defaultValue = value;
4548
+ } else {
4549
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
4550
+ return nodeHook && nodeHook.set( elem, value, name );
4551
+ }
4552
+ }
4553
+ };
4554
+ }
4555
+
4556
+ // IE6/7 do not support getting/setting some attributes with get/setAttribute
4557
+ if ( !getSetAttribute ) {
4558
+
4559
+ // Use this for any attribute in IE6/7
4560
+ // This fixes almost every IE6/7 issue
4561
+ nodeHook = {
4562
+ set: function( elem, value, name ) {
4563
+ // Set the existing or create a new attribute node
4564
+ var ret = elem.getAttributeNode( name );
4565
+ if ( !ret ) {
4566
+ elem.setAttributeNode(
4567
+ (ret = elem.ownerDocument.createAttribute( name ))
4568
+ );
4569
+ }
4570
+
4571
+ ret.value = value += "";
4572
+
4573
+ // Break association with cloned elements by also using setAttribute (#9646)
4574
+ return name === "value" || value === elem.getAttribute( name ) ?
4575
+ value :
4576
+ undefined;
4577
+ }
4578
+ };
4579
+ jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords =
4580
+ // Some attributes are constructed with empty-string values when not defined
4581
+ function( elem, name, isXML ) {
4582
+ var ret;
4583
+ return isXML ?
4584
+ undefined :
4585
+ (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
4586
+ ret.value :
4587
+ null;
4588
+ };
4589
+ jQuery.valHooks.button = {
4590
+ get: function( elem, name ) {
4591
+ var ret = elem.getAttributeNode( name );
4592
+ return ret && ret.specified ?
4593
+ ret.value :
4594
+ undefined;
4595
+ },
4596
+ set: nodeHook.set
4597
+ };
4598
+
4599
+ // Set contenteditable to false on removals(#10429)
4600
+ // Setting to empty string throws an error as an invalid value
4601
+ jQuery.attrHooks.contenteditable = {
4602
+ set: function( elem, value, name ) {
4603
+ nodeHook.set( elem, value === "" ? false : value, name );
4604
+ }
4605
+ };
4606
+
4607
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
4608
+ // This is for removals
4609
+ jQuery.each([ "width", "height" ], function( i, name ) {
4610
+ jQuery.attrHooks[ name ] = {
4611
+ set: function( elem, value ) {
4612
+ if ( value === "" ) {
4613
+ elem.setAttribute( name, "auto" );
4614
+ return value;
4615
+ }
4616
+ }
4617
+ };
4618
+ });
4619
+ }
4620
+
4621
+
4622
+ // Some attributes require a special call on IE
4623
+ // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
4624
+ if ( !jQuery.support.hrefNormalized ) {
4625
+ // href/src property should get the full normalized URL (#10299/#12915)
4626
+ jQuery.each([ "href", "src" ], function( i, name ) {
4627
+ jQuery.propHooks[ name ] = {
4628
+ get: function( elem ) {
4629
+ return elem.getAttribute( name, 4 );
4630
+ }
4631
+ };
4632
+ });
4633
+ }
4634
+
4635
+ if ( !jQuery.support.style ) {
4636
+ jQuery.attrHooks.style = {
4637
+ get: function( elem ) {
4638
+ // Return undefined in the case of empty string
4639
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
4640
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
4641
+ return elem.style.cssText || undefined;
4642
+ },
4643
+ set: function( elem, value ) {
4644
+ return ( elem.style.cssText = value + "" );
4645
+ }
4646
+ };
4647
+ }
4648
+
4649
+ // Safari mis-reports the default selected property of an option
4650
+ // Accessing the parent's selectedIndex property fixes it
4651
+ if ( !jQuery.support.optSelected ) {
4652
+ jQuery.propHooks.selected = {
4653
+ get: function( elem ) {
4654
+ var parent = elem.parentNode;
4655
+
4656
+ if ( parent ) {
4657
+ parent.selectedIndex;
4658
+
4659
+ // Make sure that it also works with optgroups, see #5701
4660
+ if ( parent.parentNode ) {
4661
+ parent.parentNode.selectedIndex;
4662
+ }
4663
+ }
4664
+ return null;
4665
+ }
4666
+ };
4667
+ }
4668
+
4669
+ jQuery.each([
4670
+ "tabIndex",
4671
+ "readOnly",
4672
+ "maxLength",
4673
+ "cellSpacing",
4674
+ "cellPadding",
4675
+ "rowSpan",
4676
+ "colSpan",
4677
+ "useMap",
4678
+ "frameBorder",
4679
+ "contentEditable"
4680
+ ], function() {
4681
+ jQuery.propFix[ this.toLowerCase() ] = this;
4682
+ });
4683
+
4684
+ // IE6/7 call enctype encoding
4685
+ if ( !jQuery.support.enctype ) {
4686
+ jQuery.propFix.enctype = "encoding";
4687
+ }
4688
+
4689
+ // Radios and checkboxes getter/setter
4690
+ jQuery.each([ "radio", "checkbox" ], function() {
4691
+ jQuery.valHooks[ this ] = {
4692
+ set: function( elem, value ) {
4693
+ if ( jQuery.isArray( value ) ) {
4694
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
4695
+ }
4696
+ }
4697
+ };
4698
+ if ( !jQuery.support.checkOn ) {
4699
+ jQuery.valHooks[ this ].get = function( elem ) {
4700
+ // Support: Webkit
4701
+ // "" is returned instead of "on" if a value isn't specified
4702
+ return elem.getAttribute("value") === null ? "on" : elem.value;
4703
+ };
4704
+ }
4705
+ });
4706
+ var rformElems = /^(?:input|select|textarea)$/i,
4707
+ rkeyEvent = /^key/,
4708
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
4709
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
4710
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
4711
+
4712
+ function returnTrue() {
4713
+ return true;
4714
+ }
4715
+
4716
+ function returnFalse() {
4717
+ return false;
4718
+ }
4719
+
4720
+ function safeActiveElement() {
4721
+ try {
4722
+ return document.activeElement;
4723
+ } catch ( err ) { }
4724
+ }
4725
+
4726
+ /*
4727
+ * Helper functions for managing events -- not part of the public interface.
4728
+ * Props to Dean Edwards' addEvent library for many of the ideas.
4729
+ */
4730
+ jQuery.event = {
4731
+
4732
+ global: {},
4733
+
4734
+ add: function( elem, types, handler, data, selector ) {
4735
+ var tmp, events, t, handleObjIn,
4736
+ special, eventHandle, handleObj,
4737
+ handlers, type, namespaces, origType,
4738
+ elemData = jQuery._data( elem );
4739
+
4740
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
4741
+ if ( !elemData ) {
4742
+ return;
4743
+ }
4744
+
4745
+ // Caller can pass in an object of custom data in lieu of the handler
4746
+ if ( handler.handler ) {
4747
+ handleObjIn = handler;
4748
+ handler = handleObjIn.handler;
4749
+ selector = handleObjIn.selector;
4750
+ }
4751
+
4752
+ // Make sure that the handler has a unique ID, used to find/remove it later
4753
+ if ( !handler.guid ) {
4754
+ handler.guid = jQuery.guid++;
4755
+ }
4756
+
4757
+ // Init the element's event structure and main handler, if this is the first
4758
+ if ( !(events = elemData.events) ) {
4759
+ events = elemData.events = {};
4760
+ }
4761
+ if ( !(eventHandle = elemData.handle) ) {
4762
+ eventHandle = elemData.handle = function( e ) {
4763
+ // Discard the second event of a jQuery.event.trigger() and
4764
+ // when an event is called after a page has unloaded
4765
+ return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
4766
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
4767
+ undefined;
4768
+ };
4769
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
4770
+ eventHandle.elem = elem;
4771
+ }
4772
+
4773
+ // Handle multiple events separated by a space
4774
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
4775
+ t = types.length;
4776
+ while ( t-- ) {
4777
+ tmp = rtypenamespace.exec( types[t] ) || [];
4778
+ type = origType = tmp[1];
4779
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
4780
+
4781
+ // There *must* be a type, no attaching namespace-only handlers
4782
+ if ( !type ) {
4783
+ continue;
4784
+ }
4785
+
4786
+ // If event changes its type, use the special event handlers for the changed type
4787
+ special = jQuery.event.special[ type ] || {};
4788
+
4789
+ // If selector defined, determine special event api type, otherwise given type
4790
+ type = ( selector ? special.delegateType : special.bindType ) || type;
4791
+
4792
+ // Update special based on newly reset type
4793
+ special = jQuery.event.special[ type ] || {};
4794
+
4795
+ // handleObj is passed to all event handlers
4796
+ handleObj = jQuery.extend({
4797
+ type: type,
4798
+ origType: origType,
4799
+ data: data,
4800
+ handler: handler,
4801
+ guid: handler.guid,
4802
+ selector: selector,
4803
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4804
+ namespace: namespaces.join(".")
4805
+ }, handleObjIn );
4806
+
4807
+ // Init the event handler queue if we're the first
4808
+ if ( !(handlers = events[ type ]) ) {
4809
+ handlers = events[ type ] = [];
4810
+ handlers.delegateCount = 0;
4811
+
4812
+ // Only use addEventListener/attachEvent if the special events handler returns false
4813
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4814
+ // Bind the global event handler to the element
4815
+ if ( elem.addEventListener ) {
4816
+ elem.addEventListener( type, eventHandle, false );
4817
+
4818
+ } else if ( elem.attachEvent ) {
4819
+ elem.attachEvent( "on" + type, eventHandle );
4820
+ }
4821
+ }
4822
+ }
4823
+
4824
+ if ( special.add ) {
4825
+ special.add.call( elem, handleObj );
4826
+
4827
+ if ( !handleObj.handler.guid ) {
4828
+ handleObj.handler.guid = handler.guid;
4829
+ }
4830
+ }
4831
+
4832
+ // Add to the element's handler list, delegates in front
4833
+ if ( selector ) {
4834
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
4835
+ } else {
4836
+ handlers.push( handleObj );
4837
+ }
4838
+
4839
+ // Keep track of which events have ever been used, for event optimization
4840
+ jQuery.event.global[ type ] = true;
4841
+ }
4842
+
4843
+ // Nullify elem to prevent memory leaks in IE
4844
+ elem = null;
4845
+ },
4846
+
4847
+ // Detach an event or set of events from an element
4848
+ remove: function( elem, types, handler, selector, mappedTypes ) {
4849
+ var j, handleObj, tmp,
4850
+ origCount, t, events,
4851
+ special, handlers, type,
4852
+ namespaces, origType,
4853
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
4854
+
4855
+ if ( !elemData || !(events = elemData.events) ) {
4856
+ return;
4857
+ }
4858
+
4859
+ // Once for each type.namespace in types; type may be omitted
4860
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
4861
+ t = types.length;
4862
+ while ( t-- ) {
4863
+ tmp = rtypenamespace.exec( types[t] ) || [];
4864
+ type = origType = tmp[1];
4865
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
4866
+
4867
+ // Unbind all events (on this namespace, if provided) for the element
4868
+ if ( !type ) {
4869
+ for ( type in events ) {
4870
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4871
+ }
4872
+ continue;
4873
+ }
4874
+
4875
+ special = jQuery.event.special[ type ] || {};
4876
+ type = ( selector ? special.delegateType : special.bindType ) || type;
4877
+ handlers = events[ type ] || [];
4878
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
4879
+
4880
+ // Remove matching events
4881
+ origCount = j = handlers.length;
4882
+ while ( j-- ) {
4883
+ handleObj = handlers[ j ];
4884
+
4885
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
4886
+ ( !handler || handler.guid === handleObj.guid ) &&
4887
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
4888
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
4889
+ handlers.splice( j, 1 );
4890
+
4891
+ if ( handleObj.selector ) {
4892
+ handlers.delegateCount--;
4893
+ }
4894
+ if ( special.remove ) {
4895
+ special.remove.call( elem, handleObj );
4896
+ }
4897
+ }
4898
+ }
4899
+
4900
+ // Remove generic event handler if we removed something and no more handlers exist
4901
+ // (avoids potential for endless recursion during removal of special event handlers)
4902
+ if ( origCount && !handlers.length ) {
4903
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4904
+ jQuery.removeEvent( elem, type, elemData.handle );
4905
+ }
4906
+
4907
+ delete events[ type ];
4908
+ }
4909
+ }
4910
+
4911
+ // Remove the expando if it's no longer used
4912
+ if ( jQuery.isEmptyObject( events ) ) {
4913
+ delete elemData.handle;
4914
+
4915
+ // removeData also checks for emptiness and clears the expando if empty
4916
+ // so use it instead of delete
4917
+ jQuery._removeData( elem, "events" );
4918
+ }
4919
+ },
4920
+
4921
+ trigger: function( event, data, elem, onlyHandlers ) {
4922
+ var handle, ontype, cur,
4923
+ bubbleType, special, tmp, i,
4924
+ eventPath = [ elem || document ],
4925
+ type = core_hasOwn.call( event, "type" ) ? event.type : event,
4926
+ namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
4927
+
4928
+ cur = tmp = elem = elem || document;
4929
+
4930
+ // Don't do events on text and comment nodes
4931
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
4932
+ return;
4933
+ }
4934
+
4935
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
4936
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
4937
+ return;
4938
+ }
4939
+
4940
+ if ( type.indexOf(".") >= 0 ) {
4941
+ // Namespaced trigger; create a regexp to match event type in handle()
4942
+ namespaces = type.split(".");
4943
+ type = namespaces.shift();
4944
+ namespaces.sort();
4945
+ }
4946
+ ontype = type.indexOf(":") < 0 && "on" + type;
4947
+
4948
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
4949
+ event = event[ jQuery.expando ] ?
4950
+ event :
4951
+ new jQuery.Event( type, typeof event === "object" && event );
4952
+
4953
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
4954
+ event.isTrigger = onlyHandlers ? 2 : 3;
4955
+ event.namespace = namespaces.join(".");
4956
+ event.namespace_re = event.namespace ?
4957
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
4958
+ null;
4959
+
4960
+ // Clean up the event in case it is being reused
4961
+ event.result = undefined;
4962
+ if ( !event.target ) {
4963
+ event.target = elem;
4964
+ }
4965
+
4966
+ // Clone any incoming data and prepend the event, creating the handler arg list
4967
+ data = data == null ?
4968
+ [ event ] :
4969
+ jQuery.makeArray( data, [ event ] );
4970
+
4971
+ // Allow special events to draw outside the lines
4972
+ special = jQuery.event.special[ type ] || {};
4973
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
4974
+ return;
4975
+ }
4976
+
4977
+ // Determine event propagation path in advance, per W3C events spec (#9951)
4978
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
4979
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
4980
+
4981
+ bubbleType = special.delegateType || type;
4982
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
4983
+ cur = cur.parentNode;
4984
+ }
4985
+ for ( ; cur; cur = cur.parentNode ) {
4986
+ eventPath.push( cur );
4987
+ tmp = cur;
4988
+ }
4989
+
4990
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
4991
+ if ( tmp === (elem.ownerDocument || document) ) {
4992
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
4993
+ }
4994
+ }
4995
+
4996
+ // Fire handlers on the event path
4997
+ i = 0;
4998
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
4999
+
5000
+ event.type = i > 1 ?
5001
+ bubbleType :
5002
+ special.bindType || type;
5003
+
5004
+ // jQuery handler
5005
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
5006
+ if ( handle ) {
5007
+ handle.apply( cur, data );
5008
+ }
5009
+
5010
+ // Native handler
5011
+ handle = ontype && cur[ ontype ];
5012
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
5013
+ event.preventDefault();
5014
+ }
5015
+ }
5016
+ event.type = type;
5017
+
5018
+ // If nobody prevented the default action, do it now
5019
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
5020
+
5021
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
5022
+ jQuery.acceptData( elem ) ) {
5023
+
5024
+ // Call a native DOM method on the target with the same name name as the event.
5025
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
5026
+ // Don't do default actions on window, that's where global variables be (#6170)
5027
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
5028
+
5029
+ // Don't re-trigger an onFOO event when we call its FOO() method
5030
+ tmp = elem[ ontype ];
5031
+
5032
+ if ( tmp ) {
5033
+ elem[ ontype ] = null;
5034
+ }
5035
+
5036
+ // Prevent re-triggering of the same event, since we already bubbled it above
5037
+ jQuery.event.triggered = type;
5038
+ try {
5039
+ elem[ type ]();
5040
+ } catch ( e ) {
5041
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
5042
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
5043
+ }
5044
+ jQuery.event.triggered = undefined;
5045
+
5046
+ if ( tmp ) {
5047
+ elem[ ontype ] = tmp;
5048
+ }
5049
+ }
5050
+ }
5051
+ }
5052
+
5053
+ return event.result;
5054
+ },
5055
+
5056
+ dispatch: function( event ) {
5057
+
5058
+ // Make a writable jQuery.Event from the native event object
5059
+ event = jQuery.event.fix( event );
5060
+
5061
+ var i, ret, handleObj, matched, j,
5062
+ handlerQueue = [],
5063
+ args = core_slice.call( arguments ),
5064
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
5065
+ special = jQuery.event.special[ event.type ] || {};
5066
+
5067
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
5068
+ args[0] = event;
5069
+ event.delegateTarget = this;
5070
+
5071
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
5072
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
5073
+ return;
5074
+ }
5075
+
5076
+ // Determine handlers
5077
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
5078
+
5079
+ // Run delegates first; they may want to stop propagation beneath us
5080
+ i = 0;
5081
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
5082
+ event.currentTarget = matched.elem;
5083
+
5084
+ j = 0;
5085
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
5086
+
5087
+ // Triggered event must either 1) have no namespace, or
5088
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
5089
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
5090
+
5091
+ event.handleObj = handleObj;
5092
+ event.data = handleObj.data;
5093
+
5094
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
5095
+ .apply( matched.elem, args );
5096
+
5097
+ if ( ret !== undefined ) {
5098
+ if ( (event.result = ret) === false ) {
5099
+ event.preventDefault();
5100
+ event.stopPropagation();
5101
+ }
5102
+ }
5103
+ }
5104
+ }
5105
+ }
5106
+
5107
+ // Call the postDispatch hook for the mapped type
5108
+ if ( special.postDispatch ) {
5109
+ special.postDispatch.call( this, event );
5110
+ }
5111
+
5112
+ return event.result;
5113
+ },
5114
+
5115
+ handlers: function( event, handlers ) {
5116
+ var sel, handleObj, matches, i,
5117
+ handlerQueue = [],
5118
+ delegateCount = handlers.delegateCount,
5119
+ cur = event.target;
5120
+
5121
+ // Find delegate handlers
5122
+ // Black-hole SVG <use> instance trees (#13180)
5123
+ // Avoid non-left-click bubbling in Firefox (#3861)
5124
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
5125
+
5126
+ /* jshint eqeqeq: false */
5127
+ for ( ; cur != this; cur = cur.parentNode || this ) {
5128
+ /* jshint eqeqeq: true */
5129
+
5130
+ // Don't check non-elements (#13208)
5131
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
5132
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
5133
+ matches = [];
5134
+ for ( i = 0; i < delegateCount; i++ ) {
5135
+ handleObj = handlers[ i ];
5136
+
5137
+ // Don't conflict with Object.prototype properties (#13203)
5138
+ sel = handleObj.selector + " ";
5139
+
5140
+ if ( matches[ sel ] === undefined ) {
5141
+ matches[ sel ] = handleObj.needsContext ?
5142
+ jQuery( sel, this ).index( cur ) >= 0 :
5143
+ jQuery.find( sel, this, null, [ cur ] ).length;
5144
+ }
5145
+ if ( matches[ sel ] ) {
5146
+ matches.push( handleObj );
5147
+ }
5148
+ }
5149
+ if ( matches.length ) {
5150
+ handlerQueue.push({ elem: cur, handlers: matches });
5151
+ }
5152
+ }
5153
+ }
5154
+ }
5155
+
5156
+ // Add the remaining (directly-bound) handlers
5157
+ if ( delegateCount < handlers.length ) {
5158
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
5159
+ }
5160
+
5161
+ return handlerQueue;
5162
+ },
5163
+
5164
+ fix: function( event ) {
5165
+ if ( event[ jQuery.expando ] ) {
5166
+ return event;
5167
+ }
5168
+
5169
+ // Create a writable copy of the event object and normalize some properties
5170
+ var i, prop, copy,
5171
+ type = event.type,
5172
+ originalEvent = event,
5173
+ fixHook = this.fixHooks[ type ];
5174
+
5175
+ if ( !fixHook ) {
5176
+ this.fixHooks[ type ] = fixHook =
5177
+ rmouseEvent.test( type ) ? this.mouseHooks :
5178
+ rkeyEvent.test( type ) ? this.keyHooks :
5179
+ {};
5180
+ }
5181
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
5182
+
5183
+ event = new jQuery.Event( originalEvent );
5184
+
5185
+ i = copy.length;
5186
+ while ( i-- ) {
5187
+ prop = copy[ i ];
5188
+ event[ prop ] = originalEvent[ prop ];
5189
+ }
5190
+
5191
+ // Support: IE<9
5192
+ // Fix target property (#1925)
5193
+ if ( !event.target ) {
5194
+ event.target = originalEvent.srcElement || document;
5195
+ }
5196
+
5197
+ // Support: Chrome 23+, Safari?
5198
+ // Target should not be a text node (#504, #13143)
5199
+ if ( event.target.nodeType === 3 ) {
5200
+ event.target = event.target.parentNode;
5201
+ }
5202
+
5203
+ // Support: IE<9
5204
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
5205
+ event.metaKey = !!event.metaKey;
5206
+
5207
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
5208
+ },
5209
+
5210
+ // Includes some event props shared by KeyEvent and MouseEvent
5211
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
5212
+
5213
+ fixHooks: {},
5214
+
5215
+ keyHooks: {
5216
+ props: "char charCode key keyCode".split(" "),
5217
+ filter: function( event, original ) {
5218
+
5219
+ // Add which for key events
5220
+ if ( event.which == null ) {
5221
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
5222
+ }
5223
+
5224
+ return event;
5225
+ }
5226
+ },
5227
+
5228
+ mouseHooks: {
5229
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
5230
+ filter: function( event, original ) {
5231
+ var body, eventDoc, doc,
5232
+ button = original.button,
5233
+ fromElement = original.fromElement;
5234
+
5235
+ // Calculate pageX/Y if missing and clientX/Y available
5236
+ if ( event.pageX == null && original.clientX != null ) {
5237
+ eventDoc = event.target.ownerDocument || document;
5238
+ doc = eventDoc.documentElement;
5239
+ body = eventDoc.body;
5240
+
5241
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
5242
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
5243
+ }
5244
+
5245
+ // Add relatedTarget, if necessary
5246
+ if ( !event.relatedTarget && fromElement ) {
5247
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
5248
+ }
5249
+
5250
+ // Add which for click: 1 === left; 2 === middle; 3 === right
5251
+ // Note: button is not normalized, so don't use it
5252
+ if ( !event.which && button !== undefined ) {
5253
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
5254
+ }
5255
+
5256
+ return event;
5257
+ }
5258
+ },
5259
+
5260
+ special: {
5261
+ load: {
5262
+ // Prevent triggered image.load events from bubbling to window.load
5263
+ noBubble: true
5264
+ },
5265
+ focus: {
5266
+ // Fire native event if possible so blur/focus sequence is correct
5267
+ trigger: function() {
5268
+ if ( this !== safeActiveElement() && this.focus ) {
5269
+ try {
5270
+ this.focus();
5271
+ return false;
5272
+ } catch ( e ) {
5273
+ // Support: IE<9
5274
+ // If we error on focus to hidden element (#1486, #12518),
5275
+ // let .trigger() run the handlers
5276
+ }
5277
+ }
5278
+ },
5279
+ delegateType: "focusin"
5280
+ },
5281
+ blur: {
5282
+ trigger: function() {
5283
+ if ( this === safeActiveElement() && this.blur ) {
5284
+ this.blur();
5285
+ return false;
5286
+ }
5287
+ },
5288
+ delegateType: "focusout"
5289
+ },
5290
+ click: {
5291
+ // For checkbox, fire native event so checked state will be right
5292
+ trigger: function() {
5293
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
5294
+ this.click();
5295
+ return false;
5296
+ }
5297
+ },
5298
+
5299
+ // For cross-browser consistency, don't fire native .click() on links
5300
+ _default: function( event ) {
5301
+ return jQuery.nodeName( event.target, "a" );
5302
+ }
5303
+ },
5304
+
5305
+ beforeunload: {
5306
+ postDispatch: function( event ) {
5307
+
5308
+ // Even when returnValue equals to undefined Firefox will still show alert
5309
+ if ( event.result !== undefined ) {
5310
+ event.originalEvent.returnValue = event.result;
5311
+ }
5312
+ }
5313
+ }
5314
+ },
5315
+
5316
+ simulate: function( type, elem, event, bubble ) {
5317
+ // Piggyback on a donor event to simulate a different one.
5318
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
5319
+ // simulated event prevents default then we do the same on the donor.
5320
+ var e = jQuery.extend(
5321
+ new jQuery.Event(),
5322
+ event,
5323
+ {
5324
+ type: type,
5325
+ isSimulated: true,
5326
+ originalEvent: {}
5327
+ }
5328
+ );
5329
+ if ( bubble ) {
5330
+ jQuery.event.trigger( e, null, elem );
5331
+ } else {
5332
+ jQuery.event.dispatch.call( elem, e );
5333
+ }
5334
+ if ( e.isDefaultPrevented() ) {
5335
+ event.preventDefault();
5336
+ }
5337
+ }
5338
+ };
5339
+
5340
+ jQuery.removeEvent = document.removeEventListener ?
5341
+ function( elem, type, handle ) {
5342
+ if ( elem.removeEventListener ) {
5343
+ elem.removeEventListener( type, handle, false );
5344
+ }
5345
+ } :
5346
+ function( elem, type, handle ) {
5347
+ var name = "on" + type;
5348
+
5349
+ if ( elem.detachEvent ) {
5350
+
5351
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
5352
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
5353
+ if ( typeof elem[ name ] === core_strundefined ) {
5354
+ elem[ name ] = null;
5355
+ }
5356
+
5357
+ elem.detachEvent( name, handle );
5358
+ }
5359
+ };
5360
+
5361
+ jQuery.Event = function( src, props ) {
5362
+ // Allow instantiation without the 'new' keyword
5363
+ if ( !(this instanceof jQuery.Event) ) {
5364
+ return new jQuery.Event( src, props );
5365
+ }
5366
+
5367
+ // Event object
5368
+ if ( src && src.type ) {
5369
+ this.originalEvent = src;
5370
+ this.type = src.type;
5371
+
5372
+ // Events bubbling up the document may have been marked as prevented
5373
+ // by a handler lower down the tree; reflect the correct value.
5374
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
5375
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
5376
+
5377
+ // Event type
5378
+ } else {
5379
+ this.type = src;
5380
+ }
5381
+
5382
+ // Put explicitly provided properties onto the event object
5383
+ if ( props ) {
5384
+ jQuery.extend( this, props );
5385
+ }
5386
+
5387
+ // Create a timestamp if incoming event doesn't have one
5388
+ this.timeStamp = src && src.timeStamp || jQuery.now();
5389
+
5390
+ // Mark it as fixed
5391
+ this[ jQuery.expando ] = true;
5392
+ };
5393
+
5394
+ // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
5395
+ // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
5396
+ jQuery.Event.prototype = {
5397
+ isDefaultPrevented: returnFalse,
5398
+ isPropagationStopped: returnFalse,
5399
+ isImmediatePropagationStopped: returnFalse,
5400
+
5401
+ preventDefault: function() {
5402
+ var e = this.originalEvent;
5403
+
5404
+ this.isDefaultPrevented = returnTrue;
5405
+ if ( !e ) {
5406
+ return;
5407
+ }
5408
+
5409
+ // If preventDefault exists, run it on the original event
5410
+ if ( e.preventDefault ) {
5411
+ e.preventDefault();
5412
+
5413
+ // Support: IE
5414
+ // Otherwise set the returnValue property of the original event to false
5415
+ } else {
5416
+ e.returnValue = false;
5417
+ }
5418
+ },
5419
+ stopPropagation: function() {
5420
+ var e = this.originalEvent;
5421
+
5422
+ this.isPropagationStopped = returnTrue;
5423
+ if ( !e ) {
5424
+ return;
5425
+ }
5426
+ // If stopPropagation exists, run it on the original event
5427
+ if ( e.stopPropagation ) {
5428
+ e.stopPropagation();
5429
+ }
5430
+
5431
+ // Support: IE
5432
+ // Set the cancelBubble property of the original event to true
5433
+ e.cancelBubble = true;
5434
+ },
5435
+ stopImmediatePropagation: function() {
5436
+ this.isImmediatePropagationStopped = returnTrue;
5437
+ this.stopPropagation();
5438
+ }
5439
+ };
5440
+
5441
+ // Create mouseenter/leave events using mouseover/out and event-time checks
5442
+ jQuery.each({
5443
+ mouseenter: "mouseover",
5444
+ mouseleave: "mouseout"
5445
+ }, function( orig, fix ) {
5446
+ jQuery.event.special[ orig ] = {
5447
+ delegateType: fix,
5448
+ bindType: fix,
5449
+
5450
+ handle: function( event ) {
5451
+ var ret,
5452
+ target = this,
5453
+ related = event.relatedTarget,
5454
+ handleObj = event.handleObj;
5455
+
5456
+ // For mousenter/leave call the handler if related is outside the target.
5457
+ // NB: No relatedTarget if the mouse left/entered the browser window
5458
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
5459
+ event.type = handleObj.origType;
5460
+ ret = handleObj.handler.apply( this, arguments );
5461
+ event.type = fix;
5462
+ }
5463
+ return ret;
5464
+ }
5465
+ };
5466
+ });
5467
+
5468
+ // IE submit delegation
5469
+ if ( !jQuery.support.submitBubbles ) {
5470
+
5471
+ jQuery.event.special.submit = {
5472
+ setup: function() {
5473
+ // Only need this for delegated form submit events
5474
+ if ( jQuery.nodeName( this, "form" ) ) {
5475
+ return false;
5476
+ }
5477
+
5478
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
5479
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
5480
+ // Node name check avoids a VML-related crash in IE (#9807)
5481
+ var elem = e.target,
5482
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
5483
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
5484
+ jQuery.event.add( form, "submit._submit", function( event ) {
5485
+ event._submit_bubble = true;
5486
+ });
5487
+ jQuery._data( form, "submitBubbles", true );
5488
+ }
5489
+ });
5490
+ // return undefined since we don't need an event listener
5491
+ },
5492
+
5493
+ postDispatch: function( event ) {
5494
+ // If form was submitted by the user, bubble the event up the tree
5495
+ if ( event._submit_bubble ) {
5496
+ delete event._submit_bubble;
5497
+ if ( this.parentNode && !event.isTrigger ) {
5498
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
5499
+ }
5500
+ }
5501
+ },
5502
+
5503
+ teardown: function() {
5504
+ // Only need this for delegated form submit events
5505
+ if ( jQuery.nodeName( this, "form" ) ) {
5506
+ return false;
5507
+ }
5508
+
5509
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
5510
+ jQuery.event.remove( this, "._submit" );
5511
+ }
5512
+ };
5513
+ }
5514
+
5515
+ // IE change delegation and checkbox/radio fix
5516
+ if ( !jQuery.support.changeBubbles ) {
5517
+
5518
+ jQuery.event.special.change = {
5519
+
5520
+ setup: function() {
5521
+
5522
+ if ( rformElems.test( this.nodeName ) ) {
5523
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
5524
+ // after a propertychange. Eat the blur-change in special.change.handle.
5525
+ // This still fires onchange a second time for check/radio after blur.
5526
+ if ( this.type === "checkbox" || this.type === "radio" ) {
5527
+ jQuery.event.add( this, "propertychange._change", function( event ) {
5528
+ if ( event.originalEvent.propertyName === "checked" ) {
5529
+ this._just_changed = true;
5530
+ }
5531
+ });
5532
+ jQuery.event.add( this, "click._change", function( event ) {
5533
+ if ( this._just_changed && !event.isTrigger ) {
5534
+ this._just_changed = false;
5535
+ }
5536
+ // Allow triggered, simulated change events (#11500)
5537
+ jQuery.event.simulate( "change", this, event, true );
5538
+ });
5539
+ }
5540
+ return false;
5541
+ }
5542
+ // Delegated event; lazy-add a change handler on descendant inputs
5543
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
5544
+ var elem = e.target;
5545
+
5546
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
5547
+ jQuery.event.add( elem, "change._change", function( event ) {
5548
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
5549
+ jQuery.event.simulate( "change", this.parentNode, event, true );
5550
+ }
5551
+ });
5552
+ jQuery._data( elem, "changeBubbles", true );
5553
+ }
5554
+ });
5555
+ },
5556
+
5557
+ handle: function( event ) {
5558
+ var elem = event.target;
5559
+
5560
+ // Swallow native change events from checkbox/radio, we already triggered them above
5561
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
5562
+ return event.handleObj.handler.apply( this, arguments );
5563
+ }
5564
+ },
5565
+
5566
+ teardown: function() {
5567
+ jQuery.event.remove( this, "._change" );
5568
+
5569
+ return !rformElems.test( this.nodeName );
5570
+ }
5571
+ };
5572
+ }
5573
+
5574
+ // Create "bubbling" focus and blur events
5575
+ if ( !jQuery.support.focusinBubbles ) {
5576
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
5577
+
5578
+ // Attach a single capturing handler while someone wants focusin/focusout
5579
+ var attaches = 0,
5580
+ handler = function( event ) {
5581
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
5582
+ };
5583
+
5584
+ jQuery.event.special[ fix ] = {
5585
+ setup: function() {
5586
+ if ( attaches++ === 0 ) {
5587
+ document.addEventListener( orig, handler, true );
5588
+ }
5589
+ },
5590
+ teardown: function() {
5591
+ if ( --attaches === 0 ) {
5592
+ document.removeEventListener( orig, handler, true );
5593
+ }
5594
+ }
5595
+ };
5596
+ });
5597
+ }
5598
+
5599
+ jQuery.fn.extend({
5600
+
5601
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
5602
+ var type, origFn;
5603
+
5604
+ // Types can be a map of types/handlers
5605
+ if ( typeof types === "object" ) {
5606
+ // ( types-Object, selector, data )
5607
+ if ( typeof selector !== "string" ) {
5608
+ // ( types-Object, data )
5609
+ data = data || selector;
5610
+ selector = undefined;
5611
+ }
5612
+ for ( type in types ) {
5613
+ this.on( type, selector, data, types[ type ], one );
5614
+ }
5615
+ return this;
5616
+ }
5617
+
5618
+ if ( data == null && fn == null ) {
5619
+ // ( types, fn )
5620
+ fn = selector;
5621
+ data = selector = undefined;
5622
+ } else if ( fn == null ) {
5623
+ if ( typeof selector === "string" ) {
5624
+ // ( types, selector, fn )
5625
+ fn = data;
5626
+ data = undefined;
5627
+ } else {
5628
+ // ( types, data, fn )
5629
+ fn = data;
5630
+ data = selector;
5631
+ selector = undefined;
5632
+ }
5633
+ }
5634
+ if ( fn === false ) {
5635
+ fn = returnFalse;
5636
+ } else if ( !fn ) {
5637
+ return this;
5638
+ }
5639
+
5640
+ if ( one === 1 ) {
5641
+ origFn = fn;
5642
+ fn = function( event ) {
5643
+ // Can use an empty set, since event contains the info
5644
+ jQuery().off( event );
5645
+ return origFn.apply( this, arguments );
5646
+ };
5647
+ // Use same guid so caller can remove using origFn
5648
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
5649
+ }
5650
+ return this.each( function() {
5651
+ jQuery.event.add( this, types, fn, data, selector );
5652
+ });
5653
+ },
5654
+ one: function( types, selector, data, fn ) {
5655
+ return this.on( types, selector, data, fn, 1 );
5656
+ },
5657
+ off: function( types, selector, fn ) {
5658
+ var handleObj, type;
5659
+ if ( types && types.preventDefault && types.handleObj ) {
5660
+ // ( event ) dispatched jQuery.Event
5661
+ handleObj = types.handleObj;
5662
+ jQuery( types.delegateTarget ).off(
5663
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
5664
+ handleObj.selector,
5665
+ handleObj.handler
5666
+ );
5667
+ return this;
5668
+ }
5669
+ if ( typeof types === "object" ) {
5670
+ // ( types-object [, selector] )
5671
+ for ( type in types ) {
5672
+ this.off( type, selector, types[ type ] );
5673
+ }
5674
+ return this;
5675
+ }
5676
+ if ( selector === false || typeof selector === "function" ) {
5677
+ // ( types [, fn] )
5678
+ fn = selector;
5679
+ selector = undefined;
5680
+ }
5681
+ if ( fn === false ) {
5682
+ fn = returnFalse;
5683
+ }
5684
+ return this.each(function() {
5685
+ jQuery.event.remove( this, types, fn, selector );
5686
+ });
5687
+ },
5688
+
5689
+ trigger: function( type, data ) {
5690
+ return this.each(function() {
5691
+ jQuery.event.trigger( type, data, this );
5692
+ });
5693
+ },
5694
+ triggerHandler: function( type, data ) {
5695
+ var elem = this[0];
5696
+ if ( elem ) {
5697
+ return jQuery.event.trigger( type, data, elem, true );
5698
+ }
5699
+ }
5700
+ });
5701
+ var isSimple = /^.[^:#\[\.,]*$/,
5702
+ rparentsprev = /^(?:parents|prev(?:Until|All))/,
5703
+ rneedsContext = jQuery.expr.match.needsContext,
5704
+ // methods guaranteed to produce a unique set when starting from a unique set
5705
+ guaranteedUnique = {
5706
+ children: true,
5707
+ contents: true,
5708
+ next: true,
5709
+ prev: true
5710
+ };
5711
+
5712
+ jQuery.fn.extend({
5713
+ find: function( selector ) {
5714
+ var i,
5715
+ ret = [],
5716
+ self = this,
5717
+ len = self.length;
5718
+
5719
+ if ( typeof selector !== "string" ) {
5720
+ return this.pushStack( jQuery( selector ).filter(function() {
5721
+ for ( i = 0; i < len; i++ ) {
5722
+ if ( jQuery.contains( self[ i ], this ) ) {
5723
+ return true;
5724
+ }
5725
+ }
5726
+ }) );
5727
+ }
5728
+
5729
+ for ( i = 0; i < len; i++ ) {
5730
+ jQuery.find( selector, self[ i ], ret );
5731
+ }
5732
+
5733
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
5734
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
5735
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
5736
+ return ret;
5737
+ },
5738
+
5739
+ has: function( target ) {
5740
+ var i,
5741
+ targets = jQuery( target, this ),
5742
+ len = targets.length;
5743
+
5744
+ return this.filter(function() {
5745
+ for ( i = 0; i < len; i++ ) {
5746
+ if ( jQuery.contains( this, targets[i] ) ) {
5747
+ return true;
5748
+ }
5749
+ }
5750
+ });
5751
+ },
5752
+
5753
+ not: function( selector ) {
5754
+ return this.pushStack( winnow(this, selector || [], true) );
5755
+ },
5756
+
5757
+ filter: function( selector ) {
5758
+ return this.pushStack( winnow(this, selector || [], false) );
5759
+ },
5760
+
5761
+ is: function( selector ) {
5762
+ return !!winnow(
5763
+ this,
5764
+
5765
+ // If this is a positional/relative selector, check membership in the returned set
5766
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
5767
+ typeof selector === "string" && rneedsContext.test( selector ) ?
5768
+ jQuery( selector ) :
5769
+ selector || [],
5770
+ false
5771
+ ).length;
5772
+ },
5773
+
5774
+ closest: function( selectors, context ) {
5775
+ var cur,
5776
+ i = 0,
5777
+ l = this.length,
5778
+ ret = [],
5779
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
5780
+ jQuery( selectors, context || this.context ) :
5781
+ 0;
5782
+
5783
+ for ( ; i < l; i++ ) {
5784
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
5785
+ // Always skip document fragments
5786
+ if ( cur.nodeType < 11 && (pos ?
5787
+ pos.index(cur) > -1 :
5788
+
5789
+ // Don't pass non-elements to Sizzle
5790
+ cur.nodeType === 1 &&
5791
+ jQuery.find.matchesSelector(cur, selectors)) ) {
5792
+
5793
+ cur = ret.push( cur );
5794
+ break;
5795
+ }
5796
+ }
5797
+ }
5798
+
5799
+ return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
5800
+ },
5801
+
5802
+ // Determine the position of an element within
5803
+ // the matched set of elements
5804
+ index: function( elem ) {
5805
+
5806
+ // No argument, return index in parent
5807
+ if ( !elem ) {
5808
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
5809
+ }
5810
+
5811
+ // index in selector
5812
+ if ( typeof elem === "string" ) {
5813
+ return jQuery.inArray( this[0], jQuery( elem ) );
5814
+ }
5815
+
5816
+ // Locate the position of the desired element
5817
+ return jQuery.inArray(
5818
+ // If it receives a jQuery object, the first element is used
5819
+ elem.jquery ? elem[0] : elem, this );
5820
+ },
5821
+
5822
+ add: function( selector, context ) {
5823
+ var set = typeof selector === "string" ?
5824
+ jQuery( selector, context ) :
5825
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
5826
+ all = jQuery.merge( this.get(), set );
5827
+
5828
+ return this.pushStack( jQuery.unique(all) );
5829
+ },
5830
+
5831
+ addBack: function( selector ) {
5832
+ return this.add( selector == null ?
5833
+ this.prevObject : this.prevObject.filter(selector)
5834
+ );
5835
+ }
5836
+ });
5837
+
5838
+ function sibling( cur, dir ) {
5839
+ do {
5840
+ cur = cur[ dir ];
5841
+ } while ( cur && cur.nodeType !== 1 );
5842
+
5843
+ return cur;
5844
+ }
5845
+
5846
+ jQuery.each({
5847
+ parent: function( elem ) {
5848
+ var parent = elem.parentNode;
5849
+ return parent && parent.nodeType !== 11 ? parent : null;
5850
+ },
5851
+ parents: function( elem ) {
5852
+ return jQuery.dir( elem, "parentNode" );
5853
+ },
5854
+ parentsUntil: function( elem, i, until ) {
5855
+ return jQuery.dir( elem, "parentNode", until );
5856
+ },
5857
+ next: function( elem ) {
5858
+ return sibling( elem, "nextSibling" );
5859
+ },
5860
+ prev: function( elem ) {
5861
+ return sibling( elem, "previousSibling" );
5862
+ },
5863
+ nextAll: function( elem ) {
5864
+ return jQuery.dir( elem, "nextSibling" );
5865
+ },
5866
+ prevAll: function( elem ) {
5867
+ return jQuery.dir( elem, "previousSibling" );
5868
+ },
5869
+ nextUntil: function( elem, i, until ) {
5870
+ return jQuery.dir( elem, "nextSibling", until );
5871
+ },
5872
+ prevUntil: function( elem, i, until ) {
5873
+ return jQuery.dir( elem, "previousSibling", until );
5874
+ },
5875
+ siblings: function( elem ) {
5876
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
5877
+ },
5878
+ children: function( elem ) {
5879
+ return jQuery.sibling( elem.firstChild );
5880
+ },
5881
+ contents: function( elem ) {
5882
+ return jQuery.nodeName( elem, "iframe" ) ?
5883
+ elem.contentDocument || elem.contentWindow.document :
5884
+ jQuery.merge( [], elem.childNodes );
5885
+ }
5886
+ }, function( name, fn ) {
5887
+ jQuery.fn[ name ] = function( until, selector ) {
5888
+ var ret = jQuery.map( this, fn, until );
5889
+
5890
+ if ( name.slice( -5 ) !== "Until" ) {
5891
+ selector = until;
5892
+ }
5893
+
5894
+ if ( selector && typeof selector === "string" ) {
5895
+ ret = jQuery.filter( selector, ret );
5896
+ }
5897
+
5898
+ if ( this.length > 1 ) {
5899
+ // Remove duplicates
5900
+ if ( !guaranteedUnique[ name ] ) {
5901
+ ret = jQuery.unique( ret );
5902
+ }
5903
+
5904
+ // Reverse order for parents* and prev-derivatives
5905
+ if ( rparentsprev.test( name ) ) {
5906
+ ret = ret.reverse();
5907
+ }
5908
+ }
5909
+
5910
+ return this.pushStack( ret );
5911
+ };
5912
+ });
5913
+
5914
+ jQuery.extend({
5915
+ filter: function( expr, elems, not ) {
5916
+ var elem = elems[ 0 ];
5917
+
5918
+ if ( not ) {
5919
+ expr = ":not(" + expr + ")";
5920
+ }
5921
+
5922
+ return elems.length === 1 && elem.nodeType === 1 ?
5923
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
5924
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
5925
+ return elem.nodeType === 1;
5926
+ }));
5927
+ },
5928
+
5929
+ dir: function( elem, dir, until ) {
5930
+ var matched = [],
5931
+ cur = elem[ dir ];
5932
+
5933
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
5934
+ if ( cur.nodeType === 1 ) {
5935
+ matched.push( cur );
5936
+ }
5937
+ cur = cur[dir];
5938
+ }
5939
+ return matched;
5940
+ },
5941
+
5942
+ sibling: function( n, elem ) {
5943
+ var r = [];
5944
+
5945
+ for ( ; n; n = n.nextSibling ) {
5946
+ if ( n.nodeType === 1 && n !== elem ) {
5947
+ r.push( n );
5948
+ }
5949
+ }
5950
+
5951
+ return r;
5952
+ }
5953
+ });
5954
+
5955
+ // Implement the identical functionality for filter and not
5956
+ function winnow( elements, qualifier, not ) {
5957
+ if ( jQuery.isFunction( qualifier ) ) {
5958
+ return jQuery.grep( elements, function( elem, i ) {
5959
+ /* jshint -W018 */
5960
+ return !!qualifier.call( elem, i, elem ) !== not;
5961
+ });
5962
+
5963
+ }
5964
+
5965
+ if ( qualifier.nodeType ) {
5966
+ return jQuery.grep( elements, function( elem ) {
5967
+ return ( elem === qualifier ) !== not;
5968
+ });
5969
+
5970
+ }
5971
+
5972
+ if ( typeof qualifier === "string" ) {
5973
+ if ( isSimple.test( qualifier ) ) {
5974
+ return jQuery.filter( qualifier, elements, not );
5975
+ }
5976
+
5977
+ qualifier = jQuery.filter( qualifier, elements );
5978
+ }
5979
+
5980
+ return jQuery.grep( elements, function( elem ) {
5981
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
5982
+ });
5983
+ }
5984
+ function createSafeFragment( document ) {
5985
+ var list = nodeNames.split( "|" ),
5986
+ safeFrag = document.createDocumentFragment();
5987
+
5988
+ if ( safeFrag.createElement ) {
5989
+ while ( list.length ) {
5990
+ safeFrag.createElement(
5991
+ list.pop()
5992
+ );
5993
+ }
5994
+ }
5995
+ return safeFrag;
5996
+ }
5997
+
5998
+ var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
5999
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
6000
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
6001
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
6002
+ rleadingWhitespace = /^\s+/,
6003
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
6004
+ rtagName = /<([\w:]+)/,
6005
+ rtbody = /<tbody/i,
6006
+ rhtml = /<|&#?\w+;/,
6007
+ rnoInnerhtml = /<(?:script|style|link)/i,
6008
+ manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
6009
+ // checked="checked" or checked
6010
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
6011
+ rscriptType = /^$|\/(?:java|ecma)script/i,
6012
+ rscriptTypeMasked = /^true\/(.*)/,
6013
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
6014
+
6015
+ // We have to close these tags to support XHTML (#13200)
6016
+ wrapMap = {
6017
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
6018
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
6019
+ area: [ 1, "<map>", "</map>" ],
6020
+ param: [ 1, "<object>", "</object>" ],
6021
+ thead: [ 1, "<table>", "</table>" ],
6022
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
6023
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
6024
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
6025
+
6026
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
6027
+ // unless wrapped in a div with non-breaking characters in front of it.
6028
+ _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
6029
+ },
6030
+ safeFragment = createSafeFragment( document ),
6031
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
6032
+
6033
+ wrapMap.optgroup = wrapMap.option;
6034
+ wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
6035
+ wrapMap.th = wrapMap.td;
6036
+
6037
+ jQuery.fn.extend({
6038
+ text: function( value ) {
6039
+ return jQuery.access( this, function( value ) {
6040
+ return value === undefined ?
6041
+ jQuery.text( this ) :
6042
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
6043
+ }, null, value, arguments.length );
6044
+ },
6045
+
6046
+ append: function() {
6047
+ return this.domManip( arguments, function( elem ) {
6048
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6049
+ var target = manipulationTarget( this, elem );
6050
+ target.appendChild( elem );
6051
+ }
6052
+ });
6053
+ },
6054
+
6055
+ prepend: function() {
6056
+ return this.domManip( arguments, function( elem ) {
6057
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6058
+ var target = manipulationTarget( this, elem );
6059
+ target.insertBefore( elem, target.firstChild );
6060
+ }
6061
+ });
6062
+ },
6063
+
6064
+ before: function() {
6065
+ return this.domManip( arguments, function( elem ) {
6066
+ if ( this.parentNode ) {
6067
+ this.parentNode.insertBefore( elem, this );
6068
+ }
6069
+ });
6070
+ },
6071
+
6072
+ after: function() {
6073
+ return this.domManip( arguments, function( elem ) {
6074
+ if ( this.parentNode ) {
6075
+ this.parentNode.insertBefore( elem, this.nextSibling );
6076
+ }
6077
+ });
6078
+ },
6079
+
6080
+ // keepData is for internal use only--do not document
6081
+ remove: function( selector, keepData ) {
6082
+ var elem,
6083
+ elems = selector ? jQuery.filter( selector, this ) : this,
6084
+ i = 0;
6085
+
6086
+ for ( ; (elem = elems[i]) != null; i++ ) {
6087
+
6088
+ if ( !keepData && elem.nodeType === 1 ) {
6089
+ jQuery.cleanData( getAll( elem ) );
6090
+ }
6091
+
6092
+ if ( elem.parentNode ) {
6093
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
6094
+ setGlobalEval( getAll( elem, "script" ) );
6095
+ }
6096
+ elem.parentNode.removeChild( elem );
6097
+ }
6098
+ }
6099
+
6100
+ return this;
6101
+ },
6102
+
6103
+ empty: function() {
6104
+ var elem,
6105
+ i = 0;
6106
+
6107
+ for ( ; (elem = this[i]) != null; i++ ) {
6108
+ // Remove element nodes and prevent memory leaks
6109
+ if ( elem.nodeType === 1 ) {
6110
+ jQuery.cleanData( getAll( elem, false ) );
6111
+ }
6112
+
6113
+ // Remove any remaining nodes
6114
+ while ( elem.firstChild ) {
6115
+ elem.removeChild( elem.firstChild );
6116
+ }
6117
+
6118
+ // If this is a select, ensure that it displays empty (#12336)
6119
+ // Support: IE<9
6120
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
6121
+ elem.options.length = 0;
6122
+ }
6123
+ }
6124
+
6125
+ return this;
6126
+ },
6127
+
6128
+ clone: function( dataAndEvents, deepDataAndEvents ) {
6129
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6130
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6131
+
6132
+ return this.map( function () {
6133
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6134
+ });
6135
+ },
6136
+
6137
+ html: function( value ) {
6138
+ return jQuery.access( this, function( value ) {
6139
+ var elem = this[0] || {},
6140
+ i = 0,
6141
+ l = this.length;
6142
+
6143
+ if ( value === undefined ) {
6144
+ return elem.nodeType === 1 ?
6145
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
6146
+ undefined;
6147
+ }
6148
+
6149
+ // See if we can take a shortcut and just use innerHTML
6150
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6151
+ ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
6152
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
6153
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
6154
+
6155
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
6156
+
6157
+ try {
6158
+ for (; i < l; i++ ) {
6159
+ // Remove element nodes and prevent memory leaks
6160
+ elem = this[i] || {};
6161
+ if ( elem.nodeType === 1 ) {
6162
+ jQuery.cleanData( getAll( elem, false ) );
6163
+ elem.innerHTML = value;
6164
+ }
6165
+ }
6166
+
6167
+ elem = 0;
6168
+
6169
+ // If using innerHTML throws an exception, use the fallback method
6170
+ } catch(e) {}
6171
+ }
6172
+
6173
+ if ( elem ) {
6174
+ this.empty().append( value );
6175
+ }
6176
+ }, null, value, arguments.length );
6177
+ },
6178
+
6179
+ replaceWith: function() {
6180
+ var
6181
+ // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
6182
+ args = jQuery.map( this, function( elem ) {
6183
+ return [ elem.nextSibling, elem.parentNode ];
6184
+ }),
6185
+ i = 0;
6186
+
6187
+ // Make the changes, replacing each context element with the new content
6188
+ this.domManip( arguments, function( elem ) {
6189
+ var next = args[ i++ ],
6190
+ parent = args[ i++ ];
6191
+
6192
+ if ( parent ) {
6193
+ // Don't use the snapshot next if it has moved (#13810)
6194
+ if ( next && next.parentNode !== parent ) {
6195
+ next = this.nextSibling;
6196
+ }
6197
+ jQuery( this ).remove();
6198
+ parent.insertBefore( elem, next );
6199
+ }
6200
+ // Allow new content to include elements from the context set
6201
+ }, true );
6202
+
6203
+ // Force removal if there was no new content (e.g., from empty arguments)
6204
+ return i ? this : this.remove();
6205
+ },
6206
+
6207
+ detach: function( selector ) {
6208
+ return this.remove( selector, true );
6209
+ },
6210
+
6211
+ domManip: function( args, callback, allowIntersection ) {
6212
+
6213
+ // Flatten any nested arrays
6214
+ args = core_concat.apply( [], args );
6215
+
6216
+ var first, node, hasScripts,
6217
+ scripts, doc, fragment,
6218
+ i = 0,
6219
+ l = this.length,
6220
+ set = this,
6221
+ iNoClone = l - 1,
6222
+ value = args[0],
6223
+ isFunction = jQuery.isFunction( value );
6224
+
6225
+ // We can't cloneNode fragments that contain checked, in WebKit
6226
+ if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
6227
+ return this.each(function( index ) {
6228
+ var self = set.eq( index );
6229
+ if ( isFunction ) {
6230
+ args[0] = value.call( this, index, self.html() );
6231
+ }
6232
+ self.domManip( args, callback, allowIntersection );
6233
+ });
6234
+ }
6235
+
6236
+ if ( l ) {
6237
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
6238
+ first = fragment.firstChild;
6239
+
6240
+ if ( fragment.childNodes.length === 1 ) {
6241
+ fragment = first;
6242
+ }
6243
+
6244
+ if ( first ) {
6245
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
6246
+ hasScripts = scripts.length;
6247
+
6248
+ // Use the original fragment for the last item instead of the first because it can end up
6249
+ // being emptied incorrectly in certain situations (#8070).
6250
+ for ( ; i < l; i++ ) {
6251
+ node = fragment;
6252
+
6253
+ if ( i !== iNoClone ) {
6254
+ node = jQuery.clone( node, true, true );
6255
+
6256
+ // Keep references to cloned scripts for later restoration
6257
+ if ( hasScripts ) {
6258
+ jQuery.merge( scripts, getAll( node, "script" ) );
6259
+ }
6260
+ }
6261
+
6262
+ callback.call( this[i], node, i );
6263
+ }
6264
+
6265
+ if ( hasScripts ) {
6266
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
6267
+
6268
+ // Reenable scripts
6269
+ jQuery.map( scripts, restoreScript );
6270
+
6271
+ // Evaluate executable scripts on first document insertion
6272
+ for ( i = 0; i < hasScripts; i++ ) {
6273
+ node = scripts[ i ];
6274
+ if ( rscriptType.test( node.type || "" ) &&
6275
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
6276
+
6277
+ if ( node.src ) {
6278
+ // Hope ajax is available...
6279
+ jQuery._evalUrl( node.src );
6280
+ } else {
6281
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
6282
+ }
6283
+ }
6284
+ }
6285
+ }
6286
+
6287
+ // Fix #11809: Avoid leaking memory
6288
+ fragment = first = null;
6289
+ }
6290
+ }
6291
+
6292
+ return this;
6293
+ }
6294
+ });
6295
+
6296
+ // Support: IE<8
6297
+ // Manipulating tables requires a tbody
6298
+ function manipulationTarget( elem, content ) {
6299
+ return jQuery.nodeName( elem, "table" ) &&
6300
+ jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
6301
+
6302
+ elem.getElementsByTagName("tbody")[0] ||
6303
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
6304
+ elem;
6305
+ }
6306
+
6307
+ // Replace/restore the type attribute of script elements for safe DOM manipulation
6308
+ function disableScript( elem ) {
6309
+ elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
6310
+ return elem;
6311
+ }
6312
+ function restoreScript( elem ) {
6313
+ var match = rscriptTypeMasked.exec( elem.type );
6314
+ if ( match ) {
6315
+ elem.type = match[1];
6316
+ } else {
6317
+ elem.removeAttribute("type");
6318
+ }
6319
+ return elem;
6320
+ }
6321
+
6322
+ // Mark scripts as having already been evaluated
6323
+ function setGlobalEval( elems, refElements ) {
6324
+ var elem,
6325
+ i = 0;
6326
+ for ( ; (elem = elems[i]) != null; i++ ) {
6327
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
6328
+ }
6329
+ }
6330
+
6331
+ function cloneCopyEvent( src, dest ) {
6332
+
6333
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
6334
+ return;
6335
+ }
6336
+
6337
+ var type, i, l,
6338
+ oldData = jQuery._data( src ),
6339
+ curData = jQuery._data( dest, oldData ),
6340
+ events = oldData.events;
6341
+
6342
+ if ( events ) {
6343
+ delete curData.handle;
6344
+ curData.events = {};
6345
+
6346
+ for ( type in events ) {
6347
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
6348
+ jQuery.event.add( dest, type, events[ type ][ i ] );
6349
+ }
6350
+ }
6351
+ }
6352
+
6353
+ // make the cloned public data object a copy from the original
6354
+ if ( curData.data ) {
6355
+ curData.data = jQuery.extend( {}, curData.data );
6356
+ }
6357
+ }
6358
+
6359
+ function fixCloneNodeIssues( src, dest ) {
6360
+ var nodeName, e, data;
6361
+
6362
+ // We do not need to do anything for non-Elements
6363
+ if ( dest.nodeType !== 1 ) {
6364
+ return;
6365
+ }
6366
+
6367
+ nodeName = dest.nodeName.toLowerCase();
6368
+
6369
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
6370
+ if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
6371
+ data = jQuery._data( dest );
6372
+
6373
+ for ( e in data.events ) {
6374
+ jQuery.removeEvent( dest, e, data.handle );
6375
+ }
6376
+
6377
+ // Event data gets referenced instead of copied if the expando gets copied too
6378
+ dest.removeAttribute( jQuery.expando );
6379
+ }
6380
+
6381
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
6382
+ if ( nodeName === "script" && dest.text !== src.text ) {
6383
+ disableScript( dest ).text = src.text;
6384
+ restoreScript( dest );
6385
+
6386
+ // IE6-10 improperly clones children of object elements using classid.
6387
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
6388
+ } else if ( nodeName === "object" ) {
6389
+ if ( dest.parentNode ) {
6390
+ dest.outerHTML = src.outerHTML;
6391
+ }
6392
+
6393
+ // This path appears unavoidable for IE9. When cloning an object
6394
+ // element in IE9, the outerHTML strategy above is not sufficient.
6395
+ // If the src has innerHTML and the destination does not,
6396
+ // copy the src.innerHTML into the dest.innerHTML. #10324
6397
+ if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
6398
+ dest.innerHTML = src.innerHTML;
6399
+ }
6400
+
6401
+ } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
6402
+ // IE6-8 fails to persist the checked state of a cloned checkbox
6403
+ // or radio button. Worse, IE6-7 fail to give the cloned element
6404
+ // a checked appearance if the defaultChecked value isn't also set
6405
+
6406
+ dest.defaultChecked = dest.checked = src.checked;
6407
+
6408
+ // IE6-7 get confused and end up setting the value of a cloned
6409
+ // checkbox/radio button to an empty string instead of "on"
6410
+ if ( dest.value !== src.value ) {
6411
+ dest.value = src.value;
6412
+ }
6413
+
6414
+ // IE6-8 fails to return the selected option to the default selected
6415
+ // state when cloning options
6416
+ } else if ( nodeName === "option" ) {
6417
+ dest.defaultSelected = dest.selected = src.defaultSelected;
6418
+
6419
+ // IE6-8 fails to set the defaultValue to the correct value when
6420
+ // cloning other types of input fields
6421
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
6422
+ dest.defaultValue = src.defaultValue;
6423
+ }
6424
+ }
6425
+
6426
+ jQuery.each({
6427
+ appendTo: "append",
6428
+ prependTo: "prepend",
6429
+ insertBefore: "before",
6430
+ insertAfter: "after",
6431
+ replaceAll: "replaceWith"
6432
+ }, function( name, original ) {
6433
+ jQuery.fn[ name ] = function( selector ) {
6434
+ var elems,
6435
+ i = 0,
6436
+ ret = [],
6437
+ insert = jQuery( selector ),
6438
+ last = insert.length - 1;
6439
+
6440
+ for ( ; i <= last; i++ ) {
6441
+ elems = i === last ? this : this.clone(true);
6442
+ jQuery( insert[i] )[ original ]( elems );
6443
+
6444
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
6445
+ core_push.apply( ret, elems.get() );
6446
+ }
6447
+
6448
+ return this.pushStack( ret );
6449
+ };
6450
+ });
6451
+
6452
+ function getAll( context, tag ) {
6453
+ var elems, elem,
6454
+ i = 0,
6455
+ found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
6456
+ typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
6457
+ undefined;
6458
+
6459
+ if ( !found ) {
6460
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
6461
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
6462
+ found.push( elem );
6463
+ } else {
6464
+ jQuery.merge( found, getAll( elem, tag ) );
6465
+ }
6466
+ }
6467
+ }
6468
+
6469
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
6470
+ jQuery.merge( [ context ], found ) :
6471
+ found;
6472
+ }
6473
+
6474
+ // Used in buildFragment, fixes the defaultChecked property
6475
+ function fixDefaultChecked( elem ) {
6476
+ if ( manipulation_rcheckableType.test( elem.type ) ) {
6477
+ elem.defaultChecked = elem.checked;
6478
+ }
6479
+ }
6480
+
6481
+ jQuery.extend({
6482
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
6483
+ var destElements, node, clone, i, srcElements,
6484
+ inPage = jQuery.contains( elem.ownerDocument, elem );
6485
+
6486
+ if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
6487
+ clone = elem.cloneNode( true );
6488
+
6489
+ // IE<=8 does not properly clone detached, unknown element nodes
6490
+ } else {
6491
+ fragmentDiv.innerHTML = elem.outerHTML;
6492
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
6493
+ }
6494
+
6495
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
6496
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
6497
+
6498
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
6499
+ destElements = getAll( clone );
6500
+ srcElements = getAll( elem );
6501
+
6502
+ // Fix all IE cloning issues
6503
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
6504
+ // Ensure that the destination node is not null; Fixes #9587
6505
+ if ( destElements[i] ) {
6506
+ fixCloneNodeIssues( node, destElements[i] );
6507
+ }
6508
+ }
6509
+ }
6510
+
6511
+ // Copy the events from the original to the clone
6512
+ if ( dataAndEvents ) {
6513
+ if ( deepDataAndEvents ) {
6514
+ srcElements = srcElements || getAll( elem );
6515
+ destElements = destElements || getAll( clone );
6516
+
6517
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
6518
+ cloneCopyEvent( node, destElements[i] );
6519
+ }
6520
+ } else {
6521
+ cloneCopyEvent( elem, clone );
6522
+ }
6523
+ }
6524
+
6525
+ // Preserve script evaluation history
6526
+ destElements = getAll( clone, "script" );
6527
+ if ( destElements.length > 0 ) {
6528
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
6529
+ }
6530
+
6531
+ destElements = srcElements = node = null;
6532
+
6533
+ // Return the cloned set
6534
+ return clone;
6535
+ },
6536
+
6537
+ buildFragment: function( elems, context, scripts, selection ) {
6538
+ var j, elem, contains,
6539
+ tmp, tag, tbody, wrap,
6540
+ l = elems.length,
6541
+
6542
+ // Ensure a safe fragment
6543
+ safe = createSafeFragment( context ),
6544
+
6545
+ nodes = [],
6546
+ i = 0;
6547
+
6548
+ for ( ; i < l; i++ ) {
6549
+ elem = elems[ i ];
6550
+
6551
+ if ( elem || elem === 0 ) {
6552
+
6553
+ // Add nodes directly
6554
+ if ( jQuery.type( elem ) === "object" ) {
6555
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
6556
+
6557
+ // Convert non-html into a text node
6558
+ } else if ( !rhtml.test( elem ) ) {
6559
+ nodes.push( context.createTextNode( elem ) );
6560
+
6561
+ // Convert html into DOM nodes
6562
+ } else {
6563
+ tmp = tmp || safe.appendChild( context.createElement("div") );
6564
+
6565
+ // Deserialize a standard representation
6566
+ tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
6567
+ wrap = wrapMap[ tag ] || wrapMap._default;
6568
+
6569
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
6570
+
6571
+ // Descend through wrappers to the right content
6572
+ j = wrap[0];
6573
+ while ( j-- ) {
6574
+ tmp = tmp.lastChild;
6575
+ }
6576
+
6577
+ // Manually add leading whitespace removed by IE
6578
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
6579
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
6580
+ }
6581
+
6582
+ // Remove IE's autoinserted <tbody> from table fragments
6583
+ if ( !jQuery.support.tbody ) {
6584
+
6585
+ // String was a <table>, *may* have spurious <tbody>
6586
+ elem = tag === "table" && !rtbody.test( elem ) ?
6587
+ tmp.firstChild :
6588
+
6589
+ // String was a bare <thead> or <tfoot>
6590
+ wrap[1] === "<table>" && !rtbody.test( elem ) ?
6591
+ tmp :
6592
+ 0;
6593
+
6594
+ j = elem && elem.childNodes.length;
6595
+ while ( j-- ) {
6596
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
6597
+ elem.removeChild( tbody );
6598
+ }
6599
+ }
6600
+ }
6601
+
6602
+ jQuery.merge( nodes, tmp.childNodes );
6603
+
6604
+ // Fix #12392 for WebKit and IE > 9
6605
+ tmp.textContent = "";
6606
+
6607
+ // Fix #12392 for oldIE
6608
+ while ( tmp.firstChild ) {
6609
+ tmp.removeChild( tmp.firstChild );
6610
+ }
6611
+
6612
+ // Remember the top-level container for proper cleanup
6613
+ tmp = safe.lastChild;
6614
+ }
6615
+ }
6616
+ }
6617
+
6618
+ // Fix #11356: Clear elements from fragment
6619
+ if ( tmp ) {
6620
+ safe.removeChild( tmp );
6621
+ }
6622
+
6623
+ // Reset defaultChecked for any radios and checkboxes
6624
+ // about to be appended to the DOM in IE 6/7 (#8060)
6625
+ if ( !jQuery.support.appendChecked ) {
6626
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
6627
+ }
6628
+
6629
+ i = 0;
6630
+ while ( (elem = nodes[ i++ ]) ) {
6631
+
6632
+ // #4087 - If origin and destination elements are the same, and this is
6633
+ // that element, do not do anything
6634
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
6635
+ continue;
6636
+ }
6637
+
6638
+ contains = jQuery.contains( elem.ownerDocument, elem );
6639
+
6640
+ // Append to fragment
6641
+ tmp = getAll( safe.appendChild( elem ), "script" );
6642
+
6643
+ // Preserve script evaluation history
6644
+ if ( contains ) {
6645
+ setGlobalEval( tmp );
6646
+ }
6647
+
6648
+ // Capture executables
6649
+ if ( scripts ) {
6650
+ j = 0;
6651
+ while ( (elem = tmp[ j++ ]) ) {
6652
+ if ( rscriptType.test( elem.type || "" ) ) {
6653
+ scripts.push( elem );
6654
+ }
6655
+ }
6656
+ }
6657
+ }
6658
+
6659
+ tmp = null;
6660
+
6661
+ return safe;
6662
+ },
6663
+
6664
+ cleanData: function( elems, /* internal */ acceptData ) {
6665
+ var elem, type, id, data,
6666
+ i = 0,
6667
+ internalKey = jQuery.expando,
6668
+ cache = jQuery.cache,
6669
+ deleteExpando = jQuery.support.deleteExpando,
6670
+ special = jQuery.event.special;
6671
+
6672
+ for ( ; (elem = elems[i]) != null; i++ ) {
6673
+
6674
+ if ( acceptData || jQuery.acceptData( elem ) ) {
6675
+
6676
+ id = elem[ internalKey ];
6677
+ data = id && cache[ id ];
6678
+
6679
+ if ( data ) {
6680
+ if ( data.events ) {
6681
+ for ( type in data.events ) {
6682
+ if ( special[ type ] ) {
6683
+ jQuery.event.remove( elem, type );
6684
+
6685
+ // This is a shortcut to avoid jQuery.event.remove's overhead
6686
+ } else {
6687
+ jQuery.removeEvent( elem, type, data.handle );
6688
+ }
6689
+ }
6690
+ }
6691
+
6692
+ // Remove cache only if it was not already removed by jQuery.event.remove
6693
+ if ( cache[ id ] ) {
6694
+
6695
+ delete cache[ id ];
6696
+
6697
+ // IE does not allow us to delete expando properties from nodes,
6698
+ // nor does it have a removeAttribute function on Document nodes;
6699
+ // we must handle all of these cases
6700
+ if ( deleteExpando ) {
6701
+ delete elem[ internalKey ];
6702
+
6703
+ } else if ( typeof elem.removeAttribute !== core_strundefined ) {
6704
+ elem.removeAttribute( internalKey );
6705
+
6706
+ } else {
6707
+ elem[ internalKey ] = null;
6708
+ }
6709
+
6710
+ core_deletedIds.push( id );
6711
+ }
6712
+ }
6713
+ }
6714
+ }
6715
+ },
6716
+
6717
+ _evalUrl: function( url ) {
6718
+ return jQuery.ajax({
6719
+ url: url,
6720
+ type: "GET",
6721
+ dataType: "script",
6722
+ async: false,
6723
+ global: false,
6724
+ "throws": true
6725
+ });
6726
+ }
6727
+ });
6728
+ jQuery.fn.extend({
6729
+ wrapAll: function( html ) {
6730
+ if ( jQuery.isFunction( html ) ) {
6731
+ return this.each(function(i) {
6732
+ jQuery(this).wrapAll( html.call(this, i) );
6733
+ });
6734
+ }
6735
+
6736
+ if ( this[0] ) {
6737
+ // The elements to wrap the target around
6738
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
6739
+
6740
+ if ( this[0].parentNode ) {
6741
+ wrap.insertBefore( this[0] );
6742
+ }
6743
+
6744
+ wrap.map(function() {
6745
+ var elem = this;
6746
+
6747
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
6748
+ elem = elem.firstChild;
6749
+ }
6750
+
6751
+ return elem;
6752
+ }).append( this );
6753
+ }
6754
+
6755
+ return this;
6756
+ },
6757
+
6758
+ wrapInner: function( html ) {
6759
+ if ( jQuery.isFunction( html ) ) {
6760
+ return this.each(function(i) {
6761
+ jQuery(this).wrapInner( html.call(this, i) );
6762
+ });
6763
+ }
6764
+
6765
+ return this.each(function() {
6766
+ var self = jQuery( this ),
6767
+ contents = self.contents();
6768
+
6769
+ if ( contents.length ) {
6770
+ contents.wrapAll( html );
6771
+
6772
+ } else {
6773
+ self.append( html );
6774
+ }
6775
+ });
6776
+ },
6777
+
6778
+ wrap: function( html ) {
6779
+ var isFunction = jQuery.isFunction( html );
6780
+
6781
+ return this.each(function(i) {
6782
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
6783
+ });
6784
+ },
6785
+
6786
+ unwrap: function() {
6787
+ return this.parent().each(function() {
6788
+ if ( !jQuery.nodeName( this, "body" ) ) {
6789
+ jQuery( this ).replaceWith( this.childNodes );
6790
+ }
6791
+ }).end();
6792
+ }
6793
+ });
6794
+ var iframe, getStyles, curCSS,
6795
+ ralpha = /alpha\([^)]*\)/i,
6796
+ ropacity = /opacity\s*=\s*([^)]*)/,
6797
+ rposition = /^(top|right|bottom|left)$/,
6798
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
6799
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6800
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6801
+ rmargin = /^margin/,
6802
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
6803
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
6804
+ rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
6805
+ elemdisplay = { BODY: "block" },
6806
+
6807
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6808
+ cssNormalTransform = {
6809
+ letterSpacing: 0,
6810
+ fontWeight: 400
6811
+ },
6812
+
6813
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
6814
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
6815
+
6816
+ // return a css property mapped to a potentially vendor prefixed property
6817
+ function vendorPropName( style, name ) {
6818
+
6819
+ // shortcut for names that are not vendor prefixed
6820
+ if ( name in style ) {
6821
+ return name;
6822
+ }
6823
+
6824
+ // check for vendor prefixed names
6825
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
6826
+ origName = name,
6827
+ i = cssPrefixes.length;
6828
+
6829
+ while ( i-- ) {
6830
+ name = cssPrefixes[ i ] + capName;
6831
+ if ( name in style ) {
6832
+ return name;
6833
+ }
6834
+ }
6835
+
6836
+ return origName;
6837
+ }
6838
+
6839
+ function isHidden( elem, el ) {
6840
+ // isHidden might be called from jQuery#filter function;
6841
+ // in that case, element will be second argument
6842
+ elem = el || elem;
6843
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
6844
+ }
6845
+
6846
+ function showHide( elements, show ) {
6847
+ var display, elem, hidden,
6848
+ values = [],
6849
+ index = 0,
6850
+ length = elements.length;
6851
+
6852
+ for ( ; index < length; index++ ) {
6853
+ elem = elements[ index ];
6854
+ if ( !elem.style ) {
6855
+ continue;
6856
+ }
6857
+
6858
+ values[ index ] = jQuery._data( elem, "olddisplay" );
6859
+ display = elem.style.display;
6860
+ if ( show ) {
6861
+ // Reset the inline display of this element to learn if it is
6862
+ // being hidden by cascaded rules or not
6863
+ if ( !values[ index ] && display === "none" ) {
6864
+ elem.style.display = "";
6865
+ }
6866
+
6867
+ // Set elements which have been overridden with display: none
6868
+ // in a stylesheet to whatever the default browser style is
6869
+ // for such an element
6870
+ if ( elem.style.display === "" && isHidden( elem ) ) {
6871
+ values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
6872
+ }
6873
+ } else {
6874
+
6875
+ if ( !values[ index ] ) {
6876
+ hidden = isHidden( elem );
6877
+
6878
+ if ( display && display !== "none" || !hidden ) {
6879
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
6880
+ }
6881
+ }
6882
+ }
6883
+ }
6884
+
6885
+ // Set the display of most of the elements in a second loop
6886
+ // to avoid the constant reflow
6887
+ for ( index = 0; index < length; index++ ) {
6888
+ elem = elements[ index ];
6889
+ if ( !elem.style ) {
6890
+ continue;
6891
+ }
6892
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6893
+ elem.style.display = show ? values[ index ] || "" : "none";
6894
+ }
6895
+ }
6896
+
6897
+ return elements;
6898
+ }
6899
+
6900
+ jQuery.fn.extend({
6901
+ css: function( name, value ) {
6902
+ return jQuery.access( this, function( elem, name, value ) {
6903
+ var len, styles,
6904
+ map = {},
6905
+ i = 0;
6906
+
6907
+ if ( jQuery.isArray( name ) ) {
6908
+ styles = getStyles( elem );
6909
+ len = name.length;
6910
+
6911
+ for ( ; i < len; i++ ) {
6912
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6913
+ }
6914
+
6915
+ return map;
6916
+ }
6917
+
6918
+ return value !== undefined ?
6919
+ jQuery.style( elem, name, value ) :
6920
+ jQuery.css( elem, name );
6921
+ }, name, value, arguments.length > 1 );
6922
+ },
6923
+ show: function() {
6924
+ return showHide( this, true );
6925
+ },
6926
+ hide: function() {
6927
+ return showHide( this );
6928
+ },
6929
+ toggle: function( state ) {
6930
+ if ( typeof state === "boolean" ) {
6931
+ return state ? this.show() : this.hide();
6932
+ }
6933
+
6934
+ return this.each(function() {
6935
+ if ( isHidden( this ) ) {
6936
+ jQuery( this ).show();
6937
+ } else {
6938
+ jQuery( this ).hide();
6939
+ }
6940
+ });
6941
+ }
6942
+ });
6943
+
6944
+ jQuery.extend({
6945
+ // Add in style property hooks for overriding the default
6946
+ // behavior of getting and setting a style property
6947
+ cssHooks: {
6948
+ opacity: {
6949
+ get: function( elem, computed ) {
6950
+ if ( computed ) {
6951
+ // We should always get a number back from opacity
6952
+ var ret = curCSS( elem, "opacity" );
6953
+ return ret === "" ? "1" : ret;
6954
+ }
6955
+ }
6956
+ }
6957
+ },
6958
+
6959
+ // Don't automatically add "px" to these possibly-unitless properties
6960
+ cssNumber: {
6961
+ "columnCount": true,
6962
+ "fillOpacity": true,
6963
+ "fontWeight": true,
6964
+ "lineHeight": true,
6965
+ "opacity": true,
6966
+ "order": true,
6967
+ "orphans": true,
6968
+ "widows": true,
6969
+ "zIndex": true,
6970
+ "zoom": true
6971
+ },
6972
+
6973
+ // Add in properties whose names you wish to fix before
6974
+ // setting or getting the value
6975
+ cssProps: {
6976
+ // normalize float css property
6977
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
6978
+ },
6979
+
6980
+ // Get and set the style property on a DOM Node
6981
+ style: function( elem, name, value, extra ) {
6982
+ // Don't set styles on text and comment nodes
6983
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6984
+ return;
6985
+ }
6986
+
6987
+ // Make sure that we're working with the right name
6988
+ var ret, type, hooks,
6989
+ origName = jQuery.camelCase( name ),
6990
+ style = elem.style;
6991
+
6992
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
6993
+
6994
+ // gets hook for the prefixed version
6995
+ // followed by the unprefixed version
6996
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6997
+
6998
+ // Check if we're setting a value
6999
+ if ( value !== undefined ) {
7000
+ type = typeof value;
7001
+
7002
+ // convert relative number strings (+= or -=) to relative numbers. #7345
7003
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
7004
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
7005
+ // Fixes bug #9237
7006
+ type = "number";
7007
+ }
7008
+
7009
+ // Make sure that NaN and null values aren't set. See: #7116
7010
+ if ( value == null || type === "number" && isNaN( value ) ) {
7011
+ return;
7012
+ }
7013
+
7014
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
7015
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
7016
+ value += "px";
7017
+ }
7018
+
7019
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
7020
+ // but it would mean to define eight (for every problematic property) identical functions
7021
+ if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
7022
+ style[ name ] = "inherit";
7023
+ }
7024
+
7025
+ // If a hook was provided, use that value, otherwise just set the specified value
7026
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
7027
+
7028
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
7029
+ // Fixes bug #5509
7030
+ try {
7031
+ style[ name ] = value;
7032
+ } catch(e) {}
7033
+ }
7034
+
7035
+ } else {
7036
+ // If a hook was provided get the non-computed value from there
7037
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
7038
+ return ret;
7039
+ }
7040
+
7041
+ // Otherwise just get the value from the style object
7042
+ return style[ name ];
7043
+ }
7044
+ },
7045
+
7046
+ css: function( elem, name, extra, styles ) {
7047
+ var num, val, hooks,
7048
+ origName = jQuery.camelCase( name );
7049
+
7050
+ // Make sure that we're working with the right name
7051
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
7052
+
7053
+ // gets hook for the prefixed version
7054
+ // followed by the unprefixed version
7055
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
7056
+
7057
+ // If a hook was provided get the computed value from there
7058
+ if ( hooks && "get" in hooks ) {
7059
+ val = hooks.get( elem, true, extra );
7060
+ }
7061
+
7062
+ // Otherwise, if a way to get the computed value exists, use that
7063
+ if ( val === undefined ) {
7064
+ val = curCSS( elem, name, styles );
7065
+ }
7066
+
7067
+ //convert "normal" to computed value
7068
+ if ( val === "normal" && name in cssNormalTransform ) {
7069
+ val = cssNormalTransform[ name ];
7070
+ }
7071
+
7072
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
7073
+ if ( extra === "" || extra ) {
7074
+ num = parseFloat( val );
7075
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
7076
+ }
7077
+ return val;
7078
+ }
7079
+ });
7080
+
7081
+ // NOTE: we've included the "window" in window.getComputedStyle
7082
+ // because jsdom on node.js will break without it.
7083
+ if ( window.getComputedStyle ) {
7084
+ getStyles = function( elem ) {
7085
+ return window.getComputedStyle( elem, null );
7086
+ };
7087
+
7088
+ curCSS = function( elem, name, _computed ) {
7089
+ var width, minWidth, maxWidth,
7090
+ computed = _computed || getStyles( elem ),
7091
+
7092
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
7093
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
7094
+ style = elem.style;
7095
+
7096
+ if ( computed ) {
7097
+
7098
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
7099
+ ret = jQuery.style( elem, name );
7100
+ }
7101
+
7102
+ // A tribute to the "awesome hack by Dean Edwards"
7103
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
7104
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
7105
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
7106
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
7107
+
7108
+ // Remember the original values
7109
+ width = style.width;
7110
+ minWidth = style.minWidth;
7111
+ maxWidth = style.maxWidth;
7112
+
7113
+ // Put in the new values to get a computed value out
7114
+ style.minWidth = style.maxWidth = style.width = ret;
7115
+ ret = computed.width;
7116
+
7117
+ // Revert the changed values
7118
+ style.width = width;
7119
+ style.minWidth = minWidth;
7120
+ style.maxWidth = maxWidth;
7121
+ }
7122
+ }
7123
+
7124
+ return ret;
7125
+ };
7126
+ } else if ( document.documentElement.currentStyle ) {
7127
+ getStyles = function( elem ) {
7128
+ return elem.currentStyle;
7129
+ };
7130
+
7131
+ curCSS = function( elem, name, _computed ) {
7132
+ var left, rs, rsLeft,
7133
+ computed = _computed || getStyles( elem ),
7134
+ ret = computed ? computed[ name ] : undefined,
7135
+ style = elem.style;
7136
+
7137
+ // Avoid setting ret to empty string here
7138
+ // so we don't default to auto
7139
+ if ( ret == null && style && style[ name ] ) {
7140
+ ret = style[ name ];
7141
+ }
7142
+
7143
+ // From the awesome hack by Dean Edwards
7144
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
7145
+
7146
+ // If we're not dealing with a regular pixel number
7147
+ // but a number that has a weird ending, we need to convert it to pixels
7148
+ // but not position css attributes, as those are proportional to the parent element instead
7149
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
7150
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
7151
+
7152
+ // Remember the original values
7153
+ left = style.left;
7154
+ rs = elem.runtimeStyle;
7155
+ rsLeft = rs && rs.left;
7156
+
7157
+ // Put in the new values to get a computed value out
7158
+ if ( rsLeft ) {
7159
+ rs.left = elem.currentStyle.left;
7160
+ }
7161
+ style.left = name === "fontSize" ? "1em" : ret;
7162
+ ret = style.pixelLeft + "px";
7163
+
7164
+ // Revert the changed values
7165
+ style.left = left;
7166
+ if ( rsLeft ) {
7167
+ rs.left = rsLeft;
7168
+ }
7169
+ }
7170
+
7171
+ return ret === "" ? "auto" : ret;
7172
+ };
7173
+ }
7174
+
7175
+ function setPositiveNumber( elem, value, subtract ) {
7176
+ var matches = rnumsplit.exec( value );
7177
+ return matches ?
7178
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
7179
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
7180
+ value;
7181
+ }
7182
+
7183
+ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
7184
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
7185
+ // If we already have the right measurement, avoid augmentation
7186
+ 4 :
7187
+ // Otherwise initialize for horizontal or vertical properties
7188
+ name === "width" ? 1 : 0,
7189
+
7190
+ val = 0;
7191
+
7192
+ for ( ; i < 4; i += 2 ) {
7193
+ // both box models exclude margin, so add it if we want it
7194
+ if ( extra === "margin" ) {
7195
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
7196
+ }
7197
+
7198
+ if ( isBorderBox ) {
7199
+ // border-box includes padding, so remove it if we want content
7200
+ if ( extra === "content" ) {
7201
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7202
+ }
7203
+
7204
+ // at this point, extra isn't border nor margin, so remove border
7205
+ if ( extra !== "margin" ) {
7206
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7207
+ }
7208
+ } else {
7209
+ // at this point, extra isn't content, so add padding
7210
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7211
+
7212
+ // at this point, extra isn't content nor padding, so add border
7213
+ if ( extra !== "padding" ) {
7214
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7215
+ }
7216
+ }
7217
+ }
7218
+
7219
+ return val;
7220
+ }
7221
+
7222
+ function getWidthOrHeight( elem, name, extra ) {
7223
+
7224
+ // Start with offset property, which is equivalent to the border-box value
7225
+ var valueIsBorderBox = true,
7226
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
7227
+ styles = getStyles( elem ),
7228
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
7229
+
7230
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
7231
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
7232
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
7233
+ if ( val <= 0 || val == null ) {
7234
+ // Fall back to computed then uncomputed css if necessary
7235
+ val = curCSS( elem, name, styles );
7236
+ if ( val < 0 || val == null ) {
7237
+ val = elem.style[ name ];
7238
+ }
7239
+
7240
+ // Computed unit is not pixels. Stop here and return.
7241
+ if ( rnumnonpx.test(val) ) {
7242
+ return val;
7243
+ }
7244
+
7245
+ // we need the check for style in case a browser which returns unreliable values
7246
+ // for getComputedStyle silently falls back to the reliable elem.style
7247
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
7248
+
7249
+ // Normalize "", auto, and prepare for extra
7250
+ val = parseFloat( val ) || 0;
7251
+ }
7252
+
7253
+ // use the active box-sizing model to add/subtract irrelevant styles
7254
+ return ( val +
7255
+ augmentWidthOrHeight(
7256
+ elem,
7257
+ name,
7258
+ extra || ( isBorderBox ? "border" : "content" ),
7259
+ valueIsBorderBox,
7260
+ styles
7261
+ )
7262
+ ) + "px";
7263
+ }
7264
+
7265
+ // Try to determine the default display value of an element
7266
+ function css_defaultDisplay( nodeName ) {
7267
+ var doc = document,
7268
+ display = elemdisplay[ nodeName ];
7269
+
7270
+ if ( !display ) {
7271
+ display = actualDisplay( nodeName, doc );
7272
+
7273
+ // If the simple way fails, read from inside an iframe
7274
+ if ( display === "none" || !display ) {
7275
+ // Use the already-created iframe if possible
7276
+ iframe = ( iframe ||
7277
+ jQuery("<iframe frameborder='0' width='0' height='0'/>")
7278
+ .css( "cssText", "display:block !important" )
7279
+ ).appendTo( doc.documentElement );
7280
+
7281
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
7282
+ doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
7283
+ doc.write("<!doctype html><html><body>");
7284
+ doc.close();
7285
+
7286
+ display = actualDisplay( nodeName, doc );
7287
+ iframe.detach();
7288
+ }
7289
+
7290
+ // Store the correct default display
7291
+ elemdisplay[ nodeName ] = display;
7292
+ }
7293
+
7294
+ return display;
7295
+ }
7296
+
7297
+ // Called ONLY from within css_defaultDisplay
7298
+ function actualDisplay( name, doc ) {
7299
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
7300
+ display = jQuery.css( elem[0], "display" );
7301
+ elem.remove();
7302
+ return display;
7303
+ }
7304
+
7305
+ jQuery.each([ "height", "width" ], function( i, name ) {
7306
+ jQuery.cssHooks[ name ] = {
7307
+ get: function( elem, computed, extra ) {
7308
+ if ( computed ) {
7309
+ // certain elements can have dimension info if we invisibly show them
7310
+ // however, it must have a current display style that would benefit from this
7311
+ return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
7312
+ jQuery.swap( elem, cssShow, function() {
7313
+ return getWidthOrHeight( elem, name, extra );
7314
+ }) :
7315
+ getWidthOrHeight( elem, name, extra );
7316
+ }
7317
+ },
7318
+
7319
+ set: function( elem, value, extra ) {
7320
+ var styles = extra && getStyles( elem );
7321
+ return setPositiveNumber( elem, value, extra ?
7322
+ augmentWidthOrHeight(
7323
+ elem,
7324
+ name,
7325
+ extra,
7326
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
7327
+ styles
7328
+ ) : 0
7329
+ );
7330
+ }
7331
+ };
7332
+ });
7333
+
7334
+ if ( !jQuery.support.opacity ) {
7335
+ jQuery.cssHooks.opacity = {
7336
+ get: function( elem, computed ) {
7337
+ // IE uses filters for opacity
7338
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
7339
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
7340
+ computed ? "1" : "";
7341
+ },
7342
+
7343
+ set: function( elem, value ) {
7344
+ var style = elem.style,
7345
+ currentStyle = elem.currentStyle,
7346
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
7347
+ filter = currentStyle && currentStyle.filter || style.filter || "";
7348
+
7349
+ // IE has trouble with opacity if it does not have layout
7350
+ // Force it by setting the zoom level
7351
+ style.zoom = 1;
7352
+
7353
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
7354
+ // if value === "", then remove inline opacity #12685
7355
+ if ( ( value >= 1 || value === "" ) &&
7356
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
7357
+ style.removeAttribute ) {
7358
+
7359
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
7360
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
7361
+ // style.removeAttribute is IE Only, but so apparently is this code path...
7362
+ style.removeAttribute( "filter" );
7363
+
7364
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
7365
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
7366
+ return;
7367
+ }
7368
+ }
7369
+
7370
+ // otherwise, set new filter values
7371
+ style.filter = ralpha.test( filter ) ?
7372
+ filter.replace( ralpha, opacity ) :
7373
+ filter + " " + opacity;
7374
+ }
7375
+ };
7376
+ }
7377
+
7378
+ // These hooks cannot be added until DOM ready because the support test
7379
+ // for it is not run until after DOM ready
7380
+ jQuery(function() {
7381
+ if ( !jQuery.support.reliableMarginRight ) {
7382
+ jQuery.cssHooks.marginRight = {
7383
+ get: function( elem, computed ) {
7384
+ if ( computed ) {
7385
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
7386
+ // Work around by temporarily setting element display to inline-block
7387
+ return jQuery.swap( elem, { "display": "inline-block" },
7388
+ curCSS, [ elem, "marginRight" ] );
7389
+ }
7390
+ }
7391
+ };
7392
+ }
7393
+
7394
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
7395
+ // getComputedStyle returns percent when specified for top/left/bottom/right
7396
+ // rather than make the css module depend on the offset module, we just check for it here
7397
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
7398
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
7399
+ jQuery.cssHooks[ prop ] = {
7400
+ get: function( elem, computed ) {
7401
+ if ( computed ) {
7402
+ computed = curCSS( elem, prop );
7403
+ // if curCSS returns percentage, fallback to offset
7404
+ return rnumnonpx.test( computed ) ?
7405
+ jQuery( elem ).position()[ prop ] + "px" :
7406
+ computed;
7407
+ }
7408
+ }
7409
+ };
7410
+ });
7411
+ }
7412
+
7413
+ });
7414
+
7415
+ if ( jQuery.expr && jQuery.expr.filters ) {
7416
+ jQuery.expr.filters.hidden = function( elem ) {
7417
+ // Support: Opera <= 12.12
7418
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
7419
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
7420
+ (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
7421
+ };
7422
+
7423
+ jQuery.expr.filters.visible = function( elem ) {
7424
+ return !jQuery.expr.filters.hidden( elem );
7425
+ };
7426
+ }
7427
+
7428
+ // These hooks are used by animate to expand properties
7429
+ jQuery.each({
7430
+ margin: "",
7431
+ padding: "",
7432
+ border: "Width"
7433
+ }, function( prefix, suffix ) {
7434
+ jQuery.cssHooks[ prefix + suffix ] = {
7435
+ expand: function( value ) {
7436
+ var i = 0,
7437
+ expanded = {},
7438
+
7439
+ // assumes a single number if not a string
7440
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
7441
+
7442
+ for ( ; i < 4; i++ ) {
7443
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
7444
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
7445
+ }
7446
+
7447
+ return expanded;
7448
+ }
7449
+ };
7450
+
7451
+ if ( !rmargin.test( prefix ) ) {
7452
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
7453
+ }
7454
+ });
7455
+ var r20 = /%20/g,
7456
+ rbracket = /\[\]$/,
7457
+ rCRLF = /\r?\n/g,
7458
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
7459
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
7460
+
7461
+ jQuery.fn.extend({
7462
+ serialize: function() {
7463
+ return jQuery.param( this.serializeArray() );
7464
+ },
7465
+ serializeArray: function() {
7466
+ return this.map(function(){
7467
+ // Can add propHook for "elements" to filter or add form elements
7468
+ var elements = jQuery.prop( this, "elements" );
7469
+ return elements ? jQuery.makeArray( elements ) : this;
7470
+ })
7471
+ .filter(function(){
7472
+ var type = this.type;
7473
+ // Use .is(":disabled") so that fieldset[disabled] works
7474
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
7475
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
7476
+ ( this.checked || !manipulation_rcheckableType.test( type ) );
7477
+ })
7478
+ .map(function( i, elem ){
7479
+ var val = jQuery( this ).val();
7480
+
7481
+ return val == null ?
7482
+ null :
7483
+ jQuery.isArray( val ) ?
7484
+ jQuery.map( val, function( val ){
7485
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7486
+ }) :
7487
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7488
+ }).get();
7489
+ }
7490
+ });
7491
+
7492
+ //Serialize an array of form elements or a set of
7493
+ //key/values into a query string
7494
+ jQuery.param = function( a, traditional ) {
7495
+ var prefix,
7496
+ s = [],
7497
+ add = function( key, value ) {
7498
+ // If value is a function, invoke it and return its value
7499
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
7500
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
7501
+ };
7502
+
7503
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
7504
+ if ( traditional === undefined ) {
7505
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
7506
+ }
7507
+
7508
+ // If an array was passed in, assume that it is an array of form elements.
7509
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
7510
+ // Serialize the form elements
7511
+ jQuery.each( a, function() {
7512
+ add( this.name, this.value );
7513
+ });
7514
+
7515
+ } else {
7516
+ // If traditional, encode the "old" way (the way 1.3.2 or older
7517
+ // did it), otherwise encode params recursively.
7518
+ for ( prefix in a ) {
7519
+ buildParams( prefix, a[ prefix ], traditional, add );
7520
+ }
7521
+ }
7522
+
7523
+ // Return the resulting serialization
7524
+ return s.join( "&" ).replace( r20, "+" );
7525
+ };
7526
+
7527
+ function buildParams( prefix, obj, traditional, add ) {
7528
+ var name;
7529
+
7530
+ if ( jQuery.isArray( obj ) ) {
7531
+ // Serialize array item.
7532
+ jQuery.each( obj, function( i, v ) {
7533
+ if ( traditional || rbracket.test( prefix ) ) {
7534
+ // Treat each array item as a scalar.
7535
+ add( prefix, v );
7536
+
7537
+ } else {
7538
+ // Item is non-scalar (array or object), encode its numeric index.
7539
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
7540
+ }
7541
+ });
7542
+
7543
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
7544
+ // Serialize object item.
7545
+ for ( name in obj ) {
7546
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
7547
+ }
7548
+
7549
+ } else {
7550
+ // Serialize scalar item.
7551
+ add( prefix, obj );
7552
+ }
7553
+ }
7554
+ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
7555
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
7556
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
7557
+
7558
+ // Handle event binding
7559
+ jQuery.fn[ name ] = function( data, fn ) {
7560
+ return arguments.length > 0 ?
7561
+ this.on( name, null, data, fn ) :
7562
+ this.trigger( name );
7563
+ };
7564
+ });
7565
+
7566
+ jQuery.fn.extend({
7567
+ hover: function( fnOver, fnOut ) {
7568
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
7569
+ },
7570
+
7571
+ bind: function( types, data, fn ) {
7572
+ return this.on( types, null, data, fn );
7573
+ },
7574
+ unbind: function( types, fn ) {
7575
+ return this.off( types, null, fn );
7576
+ },
7577
+
7578
+ delegate: function( selector, types, data, fn ) {
7579
+ return this.on( types, selector, data, fn );
7580
+ },
7581
+ undelegate: function( selector, types, fn ) {
7582
+ // ( namespace ) or ( selector, types [, fn] )
7583
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
7584
+ }
7585
+ });
7586
+ var
7587
+ // Document location
7588
+ ajaxLocParts,
7589
+ ajaxLocation,
7590
+ ajax_nonce = jQuery.now(),
7591
+
7592
+ ajax_rquery = /\?/,
7593
+ rhash = /#.*$/,
7594
+ rts = /([?&])_=[^&]*/,
7595
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
7596
+ // #7653, #8125, #8152: local protocol detection
7597
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
7598
+ rnoContent = /^(?:GET|HEAD)$/,
7599
+ rprotocol = /^\/\//,
7600
+ rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
7601
+
7602
+ // Keep a copy of the old load method
7603
+ _load = jQuery.fn.load,
7604
+
7605
+ /* Prefilters
7606
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7607
+ * 2) These are called:
7608
+ * - BEFORE asking for a transport
7609
+ * - AFTER param serialization (s.data is a string if s.processData is true)
7610
+ * 3) key is the dataType
7611
+ * 4) the catchall symbol "*" can be used
7612
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7613
+ */
7614
+ prefilters = {},
7615
+
7616
+ /* Transports bindings
7617
+ * 1) key is the dataType
7618
+ * 2) the catchall symbol "*" can be used
7619
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
7620
+ */
7621
+ transports = {},
7622
+
7623
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7624
+ allTypes = "*/".concat("*");
7625
+
7626
+ // #8138, IE may throw an exception when accessing
7627
+ // a field from window.location if document.domain has been set
7628
+ try {
7629
+ ajaxLocation = location.href;
7630
+ } catch( e ) {
7631
+ // Use the href attribute of an A element
7632
+ // since IE will modify it given document.location
7633
+ ajaxLocation = document.createElement( "a" );
7634
+ ajaxLocation.href = "";
7635
+ ajaxLocation = ajaxLocation.href;
7636
+ }
7637
+
7638
+ // Segment location into parts
7639
+ ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7640
+
7641
+ // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7642
+ function addToPrefiltersOrTransports( structure ) {
7643
+
7644
+ // dataTypeExpression is optional and defaults to "*"
7645
+ return function( dataTypeExpression, func ) {
7646
+
7647
+ if ( typeof dataTypeExpression !== "string" ) {
7648
+ func = dataTypeExpression;
7649
+ dataTypeExpression = "*";
7650
+ }
7651
+
7652
+ var dataType,
7653
+ i = 0,
7654
+ dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
7655
+
7656
+ if ( jQuery.isFunction( func ) ) {
7657
+ // For each dataType in the dataTypeExpression
7658
+ while ( (dataType = dataTypes[i++]) ) {
7659
+ // Prepend if requested
7660
+ if ( dataType[0] === "+" ) {
7661
+ dataType = dataType.slice( 1 ) || "*";
7662
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
7663
+
7664
+ // Otherwise append
7665
+ } else {
7666
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
7667
+ }
7668
+ }
7669
+ }
7670
+ };
7671
+ }
7672
+
7673
+ // Base inspection function for prefilters and transports
7674
+ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
7675
+
7676
+ var inspected = {},
7677
+ seekingTransport = ( structure === transports );
7678
+
7679
+ function inspect( dataType ) {
7680
+ var selected;
7681
+ inspected[ dataType ] = true;
7682
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
7683
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
7684
+ if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
7685
+ options.dataTypes.unshift( dataTypeOrTransport );
7686
+ inspect( dataTypeOrTransport );
7687
+ return false;
7688
+ } else if ( seekingTransport ) {
7689
+ return !( selected = dataTypeOrTransport );
7690
+ }
7691
+ });
7692
+ return selected;
7693
+ }
7694
+
7695
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
7696
+ }
7697
+
7698
+ // A special extend for ajax options
7699
+ // that takes "flat" options (not to be deep extended)
7700
+ // Fixes #9887
7701
+ function ajaxExtend( target, src ) {
7702
+ var deep, key,
7703
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
7704
+
7705
+ for ( key in src ) {
7706
+ if ( src[ key ] !== undefined ) {
7707
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
7708
+ }
7709
+ }
7710
+ if ( deep ) {
7711
+ jQuery.extend( true, target, deep );
7712
+ }
7713
+
7714
+ return target;
7715
+ }
7716
+
7717
+ jQuery.fn.load = function( url, params, callback ) {
7718
+ if ( typeof url !== "string" && _load ) {
7719
+ return _load.apply( this, arguments );
7720
+ }
7721
+
7722
+ var selector, response, type,
7723
+ self = this,
7724
+ off = url.indexOf(" ");
7725
+
7726
+ if ( off >= 0 ) {
7727
+ selector = url.slice( off, url.length );
7728
+ url = url.slice( 0, off );
7729
+ }
7730
+
7731
+ // If it's a function
7732
+ if ( jQuery.isFunction( params ) ) {
7733
+
7734
+ // We assume that it's the callback
7735
+ callback = params;
7736
+ params = undefined;
7737
+
7738
+ // Otherwise, build a param string
7739
+ } else if ( params && typeof params === "object" ) {
7740
+ type = "POST";
7741
+ }
7742
+
7743
+ // If we have elements to modify, make the request
7744
+ if ( self.length > 0 ) {
7745
+ jQuery.ajax({
7746
+ url: url,
7747
+
7748
+ // if "type" variable is undefined, then "GET" method will be used
7749
+ type: type,
7750
+ dataType: "html",
7751
+ data: params
7752
+ }).done(function( responseText ) {
7753
+
7754
+ // Save response for use in complete callback
7755
+ response = arguments;
7756
+
7757
+ self.html( selector ?
7758
+
7759
+ // If a selector was specified, locate the right elements in a dummy div
7760
+ // Exclude scripts to avoid IE 'Permission Denied' errors
7761
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
7762
+
7763
+ // Otherwise use the full result
7764
+ responseText );
7765
+
7766
+ }).complete( callback && function( jqXHR, status ) {
7767
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
7768
+ });
7769
+ }
7770
+
7771
+ return this;
7772
+ };
7773
+
7774
+ // Attach a bunch of functions for handling common AJAX events
7775
+ jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
7776
+ jQuery.fn[ type ] = function( fn ){
7777
+ return this.on( type, fn );
7778
+ };
7779
+ });
7780
+
7781
+ jQuery.extend({
7782
+
7783
+ // Counter for holding the number of active queries
7784
+ active: 0,
7785
+
7786
+ // Last-Modified header cache for next request
7787
+ lastModified: {},
7788
+ etag: {},
7789
+
7790
+ ajaxSettings: {
7791
+ url: ajaxLocation,
7792
+ type: "GET",
7793
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7794
+ global: true,
7795
+ processData: true,
7796
+ async: true,
7797
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
7798
+ /*
7799
+ timeout: 0,
7800
+ data: null,
7801
+ dataType: null,
7802
+ username: null,
7803
+ password: null,
7804
+ cache: null,
7805
+ throws: false,
7806
+ traditional: false,
7807
+ headers: {},
7808
+ */
7809
+
7810
+ accepts: {
7811
+ "*": allTypes,
7812
+ text: "text/plain",
7813
+ html: "text/html",
7814
+ xml: "application/xml, text/xml",
7815
+ json: "application/json, text/javascript"
7816
+ },
7817
+
7818
+ contents: {
7819
+ xml: /xml/,
7820
+ html: /html/,
7821
+ json: /json/
7822
+ },
7823
+
7824
+ responseFields: {
7825
+ xml: "responseXML",
7826
+ text: "responseText",
7827
+ json: "responseJSON"
7828
+ },
7829
+
7830
+ // Data converters
7831
+ // Keys separate source (or catchall "*") and destination types with a single space
7832
+ converters: {
7833
+
7834
+ // Convert anything to text
7835
+ "* text": String,
7836
+
7837
+ // Text to html (true = no transformation)
7838
+ "text html": true,
7839
+
7840
+ // Evaluate text as a json expression
7841
+ "text json": jQuery.parseJSON,
7842
+
7843
+ // Parse text as xml
7844
+ "text xml": jQuery.parseXML
7845
+ },
7846
+
7847
+ // For options that shouldn't be deep extended:
7848
+ // you can add your own custom options here if
7849
+ // and when you create one that shouldn't be
7850
+ // deep extended (see ajaxExtend)
7851
+ flatOptions: {
7852
+ url: true,
7853
+ context: true
7854
+ }
7855
+ },
7856
+
7857
+ // Creates a full fledged settings object into target
7858
+ // with both ajaxSettings and settings fields.
7859
+ // If target is omitted, writes into ajaxSettings.
7860
+ ajaxSetup: function( target, settings ) {
7861
+ return settings ?
7862
+
7863
+ // Building a settings object
7864
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7865
+
7866
+ // Extending ajaxSettings
7867
+ ajaxExtend( jQuery.ajaxSettings, target );
7868
+ },
7869
+
7870
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7871
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
7872
+
7873
+ // Main method
7874
+ ajax: function( url, options ) {
7875
+
7876
+ // If url is an object, simulate pre-1.5 signature
7877
+ if ( typeof url === "object" ) {
7878
+ options = url;
7879
+ url = undefined;
7880
+ }
7881
+
7882
+ // Force options to be an object
7883
+ options = options || {};
7884
+
7885
+ var // Cross-domain detection vars
7886
+ parts,
7887
+ // Loop variable
7888
+ i,
7889
+ // URL without anti-cache param
7890
+ cacheURL,
7891
+ // Response headers as string
7892
+ responseHeadersString,
7893
+ // timeout handle
7894
+ timeoutTimer,
7895
+
7896
+ // To know if global events are to be dispatched
7897
+ fireGlobals,
7898
+
7899
+ transport,
7900
+ // Response headers
7901
+ responseHeaders,
7902
+ // Create the final options object
7903
+ s = jQuery.ajaxSetup( {}, options ),
7904
+ // Callbacks context
7905
+ callbackContext = s.context || s,
7906
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
7907
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7908
+ jQuery( callbackContext ) :
7909
+ jQuery.event,
7910
+ // Deferreds
7911
+ deferred = jQuery.Deferred(),
7912
+ completeDeferred = jQuery.Callbacks("once memory"),
7913
+ // Status-dependent callbacks
7914
+ statusCode = s.statusCode || {},
7915
+ // Headers (they are sent all at once)
7916
+ requestHeaders = {},
7917
+ requestHeadersNames = {},
7918
+ // The jqXHR state
7919
+ state = 0,
7920
+ // Default abort message
7921
+ strAbort = "canceled",
7922
+ // Fake xhr
7923
+ jqXHR = {
7924
+ readyState: 0,
7925
+
7926
+ // Builds headers hashtable if needed
7927
+ getResponseHeader: function( key ) {
7928
+ var match;
7929
+ if ( state === 2 ) {
7930
+ if ( !responseHeaders ) {
7931
+ responseHeaders = {};
7932
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
7933
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7934
+ }
7935
+ }
7936
+ match = responseHeaders[ key.toLowerCase() ];
7937
+ }
7938
+ return match == null ? null : match;
7939
+ },
7940
+
7941
+ // Raw string
7942
+ getAllResponseHeaders: function() {
7943
+ return state === 2 ? responseHeadersString : null;
7944
+ },
7945
+
7946
+ // Caches the header
7947
+ setRequestHeader: function( name, value ) {
7948
+ var lname = name.toLowerCase();
7949
+ if ( !state ) {
7950
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7951
+ requestHeaders[ name ] = value;
7952
+ }
7953
+ return this;
7954
+ },
7955
+
7956
+ // Overrides response content-type header
7957
+ overrideMimeType: function( type ) {
7958
+ if ( !state ) {
7959
+ s.mimeType = type;
7960
+ }
7961
+ return this;
7962
+ },
7963
+
7964
+ // Status-dependent callbacks
7965
+ statusCode: function( map ) {
7966
+ var code;
7967
+ if ( map ) {
7968
+ if ( state < 2 ) {
7969
+ for ( code in map ) {
7970
+ // Lazy-add the new callback in a way that preserves old ones
7971
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7972
+ }
7973
+ } else {
7974
+ // Execute the appropriate callbacks
7975
+ jqXHR.always( map[ jqXHR.status ] );
7976
+ }
7977
+ }
7978
+ return this;
7979
+ },
7980
+
7981
+ // Cancel the request
7982
+ abort: function( statusText ) {
7983
+ var finalText = statusText || strAbort;
7984
+ if ( transport ) {
7985
+ transport.abort( finalText );
7986
+ }
7987
+ done( 0, finalText );
7988
+ return this;
7989
+ }
7990
+ };
7991
+
7992
+ // Attach deferreds
7993
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
7994
+ jqXHR.success = jqXHR.done;
7995
+ jqXHR.error = jqXHR.fail;
7996
+
7997
+ // Remove hash character (#7531: and string promotion)
7998
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
7999
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
8000
+ // We also use the url parameter if available
8001
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
8002
+
8003
+ // Alias method option to type as per ticket #12004
8004
+ s.type = options.method || options.type || s.method || s.type;
8005
+
8006
+ // Extract dataTypes list
8007
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
8008
+
8009
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
8010
+ if ( s.crossDomain == null ) {
8011
+ parts = rurl.exec( s.url.toLowerCase() );
8012
+ s.crossDomain = !!( parts &&
8013
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
8014
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
8015
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
8016
+ );
8017
+ }
8018
+
8019
+ // Convert data if not already a string
8020
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
8021
+ s.data = jQuery.param( s.data, s.traditional );
8022
+ }
8023
+
8024
+ // Apply prefilters
8025
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
8026
+
8027
+ // If request was aborted inside a prefilter, stop there
8028
+ if ( state === 2 ) {
8029
+ return jqXHR;
8030
+ }
8031
+
8032
+ // We can fire global events as of now if asked to
8033
+ fireGlobals = s.global;
8034
+
8035
+ // Watch for a new set of requests
8036
+ if ( fireGlobals && jQuery.active++ === 0 ) {
8037
+ jQuery.event.trigger("ajaxStart");
8038
+ }
8039
+
8040
+ // Uppercase the type
8041
+ s.type = s.type.toUpperCase();
8042
+
8043
+ // Determine if request has content
8044
+ s.hasContent = !rnoContent.test( s.type );
8045
+
8046
+ // Save the URL in case we're toying with the If-Modified-Since
8047
+ // and/or If-None-Match header later on
8048
+ cacheURL = s.url;
8049
+
8050
+ // More options handling for requests with no content
8051
+ if ( !s.hasContent ) {
8052
+
8053
+ // If data is available, append data to url
8054
+ if ( s.data ) {
8055
+ cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
8056
+ // #9682: remove data so that it's not used in an eventual retry
8057
+ delete s.data;
8058
+ }
8059
+
8060
+ // Add anti-cache in url if needed
8061
+ if ( s.cache === false ) {
8062
+ s.url = rts.test( cacheURL ) ?
8063
+
8064
+ // If there is already a '_' parameter, set its value
8065
+ cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
8066
+
8067
+ // Otherwise add one to the end
8068
+ cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
8069
+ }
8070
+ }
8071
+
8072
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8073
+ if ( s.ifModified ) {
8074
+ if ( jQuery.lastModified[ cacheURL ] ) {
8075
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
8076
+ }
8077
+ if ( jQuery.etag[ cacheURL ] ) {
8078
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
8079
+ }
8080
+ }
8081
+
8082
+ // Set the correct header, if data is being sent
8083
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
8084
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
8085
+ }
8086
+
8087
+ // Set the Accepts header for the server, depending on the dataType
8088
+ jqXHR.setRequestHeader(
8089
+ "Accept",
8090
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
8091
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
8092
+ s.accepts[ "*" ]
8093
+ );
8094
+
8095
+ // Check for headers option
8096
+ for ( i in s.headers ) {
8097
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
8098
+ }
8099
+
8100
+ // Allow custom headers/mimetypes and early abort
8101
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
8102
+ // Abort if not done already and return
8103
+ return jqXHR.abort();
8104
+ }
8105
+
8106
+ // aborting is no longer a cancellation
8107
+ strAbort = "abort";
8108
+
8109
+ // Install callbacks on deferreds
8110
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
8111
+ jqXHR[ i ]( s[ i ] );
8112
+ }
8113
+
8114
+ // Get transport
8115
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
8116
+
8117
+ // If no transport, we auto-abort
8118
+ if ( !transport ) {
8119
+ done( -1, "No Transport" );
8120
+ } else {
8121
+ jqXHR.readyState = 1;
8122
+
8123
+ // Send global event
8124
+ if ( fireGlobals ) {
8125
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
8126
+ }
8127
+ // Timeout
8128
+ if ( s.async && s.timeout > 0 ) {
8129
+ timeoutTimer = setTimeout(function() {
8130
+ jqXHR.abort("timeout");
8131
+ }, s.timeout );
8132
+ }
8133
+
8134
+ try {
8135
+ state = 1;
8136
+ transport.send( requestHeaders, done );
8137
+ } catch ( e ) {
8138
+ // Propagate exception as error if not done
8139
+ if ( state < 2 ) {
8140
+ done( -1, e );
8141
+ // Simply rethrow otherwise
8142
+ } else {
8143
+ throw e;
8144
+ }
8145
+ }
8146
+ }
8147
+
8148
+ // Callback for when everything is done
8149
+ function done( status, nativeStatusText, responses, headers ) {
8150
+ var isSuccess, success, error, response, modified,
8151
+ statusText = nativeStatusText;
8152
+
8153
+ // Called once
8154
+ if ( state === 2 ) {
8155
+ return;
8156
+ }
8157
+
8158
+ // State is "done" now
8159
+ state = 2;
8160
+
8161
+ // Clear timeout if it exists
8162
+ if ( timeoutTimer ) {
8163
+ clearTimeout( timeoutTimer );
8164
+ }
8165
+
8166
+ // Dereference transport for early garbage collection
8167
+ // (no matter how long the jqXHR object will be used)
8168
+ transport = undefined;
8169
+
8170
+ // Cache response headers
8171
+ responseHeadersString = headers || "";
8172
+
8173
+ // Set readyState
8174
+ jqXHR.readyState = status > 0 ? 4 : 0;
8175
+
8176
+ // Determine if successful
8177
+ isSuccess = status >= 200 && status < 300 || status === 304;
8178
+
8179
+ // Get response data
8180
+ if ( responses ) {
8181
+ response = ajaxHandleResponses( s, jqXHR, responses );
8182
+ }
8183
+
8184
+ // Convert no matter what (that way responseXXX fields are always set)
8185
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
8186
+
8187
+ // If successful, handle type chaining
8188
+ if ( isSuccess ) {
8189
+
8190
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8191
+ if ( s.ifModified ) {
8192
+ modified = jqXHR.getResponseHeader("Last-Modified");
8193
+ if ( modified ) {
8194
+ jQuery.lastModified[ cacheURL ] = modified;
8195
+ }
8196
+ modified = jqXHR.getResponseHeader("etag");
8197
+ if ( modified ) {
8198
+ jQuery.etag[ cacheURL ] = modified;
8199
+ }
8200
+ }
8201
+
8202
+ // if no content
8203
+ if ( status === 204 || s.type === "HEAD" ) {
8204
+ statusText = "nocontent";
8205
+
8206
+ // if not modified
8207
+ } else if ( status === 304 ) {
8208
+ statusText = "notmodified";
8209
+
8210
+ // If we have data, let's convert it
8211
+ } else {
8212
+ statusText = response.state;
8213
+ success = response.data;
8214
+ error = response.error;
8215
+ isSuccess = !error;
8216
+ }
8217
+ } else {
8218
+ // We extract error from statusText
8219
+ // then normalize statusText and status for non-aborts
8220
+ error = statusText;
8221
+ if ( status || !statusText ) {
8222
+ statusText = "error";
8223
+ if ( status < 0 ) {
8224
+ status = 0;
8225
+ }
8226
+ }
8227
+ }
8228
+
8229
+ // Set data for the fake xhr object
8230
+ jqXHR.status = status;
8231
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
8232
+
8233
+ // Success/Error
8234
+ if ( isSuccess ) {
8235
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8236
+ } else {
8237
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8238
+ }
8239
+
8240
+ // Status-dependent callbacks
8241
+ jqXHR.statusCode( statusCode );
8242
+ statusCode = undefined;
8243
+
8244
+ if ( fireGlobals ) {
8245
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
8246
+ [ jqXHR, s, isSuccess ? success : error ] );
8247
+ }
8248
+
8249
+ // Complete
8250
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8251
+
8252
+ if ( fireGlobals ) {
8253
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8254
+ // Handle the global AJAX counter
8255
+ if ( !( --jQuery.active ) ) {
8256
+ jQuery.event.trigger("ajaxStop");
8257
+ }
8258
+ }
8259
+ }
8260
+
8261
+ return jqXHR;
8262
+ },
8263
+
8264
+ getJSON: function( url, data, callback ) {
8265
+ return jQuery.get( url, data, callback, "json" );
8266
+ },
8267
+
8268
+ getScript: function( url, callback ) {
8269
+ return jQuery.get( url, undefined, callback, "script" );
8270
+ }
8271
+ });
8272
+
8273
+ jQuery.each( [ "get", "post" ], function( i, method ) {
8274
+ jQuery[ method ] = function( url, data, callback, type ) {
8275
+ // shift arguments if data argument was omitted
8276
+ if ( jQuery.isFunction( data ) ) {
8277
+ type = type || callback;
8278
+ callback = data;
8279
+ data = undefined;
8280
+ }
8281
+
8282
+ return jQuery.ajax({
8283
+ url: url,
8284
+ type: method,
8285
+ dataType: type,
8286
+ data: data,
8287
+ success: callback
8288
+ });
8289
+ };
8290
+ });
8291
+
8292
+ /* Handles responses to an ajax request:
8293
+ * - finds the right dataType (mediates between content-type and expected dataType)
8294
+ * - returns the corresponding response
8295
+ */
8296
+ function ajaxHandleResponses( s, jqXHR, responses ) {
8297
+ var firstDataType, ct, finalDataType, type,
8298
+ contents = s.contents,
8299
+ dataTypes = s.dataTypes;
8300
+
8301
+ // Remove auto dataType and get content-type in the process
8302
+ while( dataTypes[ 0 ] === "*" ) {
8303
+ dataTypes.shift();
8304
+ if ( ct === undefined ) {
8305
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
8306
+ }
8307
+ }
8308
+
8309
+ // Check if we're dealing with a known content-type
8310
+ if ( ct ) {
8311
+ for ( type in contents ) {
8312
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
8313
+ dataTypes.unshift( type );
8314
+ break;
8315
+ }
8316
+ }
8317
+ }
8318
+
8319
+ // Check to see if we have a response for the expected dataType
8320
+ if ( dataTypes[ 0 ] in responses ) {
8321
+ finalDataType = dataTypes[ 0 ];
8322
+ } else {
8323
+ // Try convertible dataTypes
8324
+ for ( type in responses ) {
8325
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
8326
+ finalDataType = type;
8327
+ break;
8328
+ }
8329
+ if ( !firstDataType ) {
8330
+ firstDataType = type;
8331
+ }
8332
+ }
8333
+ // Or just use first one
8334
+ finalDataType = finalDataType || firstDataType;
8335
+ }
8336
+
8337
+ // If we found a dataType
8338
+ // We add the dataType to the list if needed
8339
+ // and return the corresponding response
8340
+ if ( finalDataType ) {
8341
+ if ( finalDataType !== dataTypes[ 0 ] ) {
8342
+ dataTypes.unshift( finalDataType );
8343
+ }
8344
+ return responses[ finalDataType ];
8345
+ }
8346
+ }
8347
+
8348
+ /* Chain conversions given the request and the original response
8349
+ * Also sets the responseXXX fields on the jqXHR instance
8350
+ */
8351
+ function ajaxConvert( s, response, jqXHR, isSuccess ) {
8352
+ var conv2, current, conv, tmp, prev,
8353
+ converters = {},
8354
+ // Work with a copy of dataTypes in case we need to modify it for conversion
8355
+ dataTypes = s.dataTypes.slice();
8356
+
8357
+ // Create converters map with lowercased keys
8358
+ if ( dataTypes[ 1 ] ) {
8359
+ for ( conv in s.converters ) {
8360
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
8361
+ }
8362
+ }
8363
+
8364
+ current = dataTypes.shift();
8365
+
8366
+ // Convert to each sequential dataType
8367
+ while ( current ) {
8368
+
8369
+ if ( s.responseFields[ current ] ) {
8370
+ jqXHR[ s.responseFields[ current ] ] = response;
8371
+ }
8372
+
8373
+ // Apply the dataFilter if provided
8374
+ if ( !prev && isSuccess && s.dataFilter ) {
8375
+ response = s.dataFilter( response, s.dataType );
8376
+ }
8377
+
8378
+ prev = current;
8379
+ current = dataTypes.shift();
8380
+
8381
+ if ( current ) {
8382
+
8383
+ // There's only work to do if current dataType is non-auto
8384
+ if ( current === "*" ) {
8385
+
8386
+ current = prev;
8387
+
8388
+ // Convert response if prev dataType is non-auto and differs from current
8389
+ } else if ( prev !== "*" && prev !== current ) {
8390
+
8391
+ // Seek a direct converter
8392
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
8393
+
8394
+ // If none found, seek a pair
8395
+ if ( !conv ) {
8396
+ for ( conv2 in converters ) {
8397
+
8398
+ // If conv2 outputs current
8399
+ tmp = conv2.split( " " );
8400
+ if ( tmp[ 1 ] === current ) {
8401
+
8402
+ // If prev can be converted to accepted input
8403
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
8404
+ converters[ "* " + tmp[ 0 ] ];
8405
+ if ( conv ) {
8406
+ // Condense equivalence converters
8407
+ if ( conv === true ) {
8408
+ conv = converters[ conv2 ];
8409
+
8410
+ // Otherwise, insert the intermediate dataType
8411
+ } else if ( converters[ conv2 ] !== true ) {
8412
+ current = tmp[ 0 ];
8413
+ dataTypes.unshift( tmp[ 1 ] );
8414
+ }
8415
+ break;
8416
+ }
8417
+ }
8418
+ }
8419
+ }
8420
+
8421
+ // Apply converter (if not an equivalence)
8422
+ if ( conv !== true ) {
8423
+
8424
+ // Unless errors are allowed to bubble, catch and return them
8425
+ if ( conv && s[ "throws" ] ) {
8426
+ response = conv( response );
8427
+ } else {
8428
+ try {
8429
+ response = conv( response );
8430
+ } catch ( e ) {
8431
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
8432
+ }
8433
+ }
8434
+ }
8435
+ }
8436
+ }
8437
+ }
8438
+
8439
+ return { state: "success", data: response };
8440
+ }
8441
+ // Install script dataType
8442
+ jQuery.ajaxSetup({
8443
+ accepts: {
8444
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8445
+ },
8446
+ contents: {
8447
+ script: /(?:java|ecma)script/
8448
+ },
8449
+ converters: {
8450
+ "text script": function( text ) {
8451
+ jQuery.globalEval( text );
8452
+ return text;
8453
+ }
8454
+ }
8455
+ });
8456
+
8457
+ // Handle cache's special case and global
8458
+ jQuery.ajaxPrefilter( "script", function( s ) {
8459
+ if ( s.cache === undefined ) {
8460
+ s.cache = false;
8461
+ }
8462
+ if ( s.crossDomain ) {
8463
+ s.type = "GET";
8464
+ s.global = false;
8465
+ }
8466
+ });
8467
+
8468
+ // Bind script tag hack transport
8469
+ jQuery.ajaxTransport( "script", function(s) {
8470
+
8471
+ // This transport only deals with cross domain requests
8472
+ if ( s.crossDomain ) {
8473
+
8474
+ var script,
8475
+ head = document.head || jQuery("head")[0] || document.documentElement;
8476
+
8477
+ return {
8478
+
8479
+ send: function( _, callback ) {
8480
+
8481
+ script = document.createElement("script");
8482
+
8483
+ script.async = true;
8484
+
8485
+ if ( s.scriptCharset ) {
8486
+ script.charset = s.scriptCharset;
8487
+ }
8488
+
8489
+ script.src = s.url;
8490
+
8491
+ // Attach handlers for all browsers
8492
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
8493
+
8494
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
8495
+
8496
+ // Handle memory leak in IE
8497
+ script.onload = script.onreadystatechange = null;
8498
+
8499
+ // Remove the script
8500
+ if ( script.parentNode ) {
8501
+ script.parentNode.removeChild( script );
8502
+ }
8503
+
8504
+ // Dereference the script
8505
+ script = null;
8506
+
8507
+ // Callback if not abort
8508
+ if ( !isAbort ) {
8509
+ callback( 200, "success" );
8510
+ }
8511
+ }
8512
+ };
8513
+
8514
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
8515
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
8516
+ head.insertBefore( script, head.firstChild );
8517
+ },
8518
+
8519
+ abort: function() {
8520
+ if ( script ) {
8521
+ script.onload( undefined, true );
8522
+ }
8523
+ }
8524
+ };
8525
+ }
8526
+ });
8527
+ var oldCallbacks = [],
8528
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
8529
+
8530
+ // Default jsonp settings
8531
+ jQuery.ajaxSetup({
8532
+ jsonp: "callback",
8533
+ jsonpCallback: function() {
8534
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
8535
+ this[ callback ] = true;
8536
+ return callback;
8537
+ }
8538
+ });
8539
+
8540
+ // Detect, normalize options and install callbacks for jsonp requests
8541
+ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8542
+
8543
+ var callbackName, overwritten, responseContainer,
8544
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
8545
+ "url" :
8546
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
8547
+ );
8548
+
8549
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
8550
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
8551
+
8552
+ // Get callback name, remembering preexisting value associated with it
8553
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
8554
+ s.jsonpCallback() :
8555
+ s.jsonpCallback;
8556
+
8557
+ // Insert callback into url or form data
8558
+ if ( jsonProp ) {
8559
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
8560
+ } else if ( s.jsonp !== false ) {
8561
+ s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
8562
+ }
8563
+
8564
+ // Use data converter to retrieve json after script execution
8565
+ s.converters["script json"] = function() {
8566
+ if ( !responseContainer ) {
8567
+ jQuery.error( callbackName + " was not called" );
8568
+ }
8569
+ return responseContainer[ 0 ];
8570
+ };
8571
+
8572
+ // force json dataType
8573
+ s.dataTypes[ 0 ] = "json";
8574
+
8575
+ // Install callback
8576
+ overwritten = window[ callbackName ];
8577
+ window[ callbackName ] = function() {
8578
+ responseContainer = arguments;
8579
+ };
8580
+
8581
+ // Clean-up function (fires after converters)
8582
+ jqXHR.always(function() {
8583
+ // Restore preexisting value
8584
+ window[ callbackName ] = overwritten;
8585
+
8586
+ // Save back as free
8587
+ if ( s[ callbackName ] ) {
8588
+ // make sure that re-using the options doesn't screw things around
8589
+ s.jsonpCallback = originalSettings.jsonpCallback;
8590
+
8591
+ // save the callback name for future use
8592
+ oldCallbacks.push( callbackName );
8593
+ }
8594
+
8595
+ // Call if it was a function and we have a response
8596
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
8597
+ overwritten( responseContainer[ 0 ] );
8598
+ }
8599
+
8600
+ responseContainer = overwritten = undefined;
8601
+ });
8602
+
8603
+ // Delegate to script
8604
+ return "script";
8605
+ }
8606
+ });
8607
+ var xhrCallbacks, xhrSupported,
8608
+ xhrId = 0,
8609
+ // #5280: Internet Explorer will keep connections alive if we don't abort on unload
8610
+ xhrOnUnloadAbort = window.ActiveXObject && function() {
8611
+ // Abort all pending requests
8612
+ var key;
8613
+ for ( key in xhrCallbacks ) {
8614
+ xhrCallbacks[ key ]( undefined, true );
8615
+ }
8616
+ };
8617
+
8618
+ // Functions to create xhrs
8619
+ function createStandardXHR() {
8620
+ try {
8621
+ return new window.XMLHttpRequest();
8622
+ } catch( e ) {}
8623
+ }
8624
+
8625
+ function createActiveXHR() {
8626
+ try {
8627
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
8628
+ } catch( e ) {}
8629
+ }
8630
+
8631
+ // Create the request object
8632
+ // (This is still attached to ajaxSettings for backward compatibility)
8633
+ jQuery.ajaxSettings.xhr = window.ActiveXObject ?
8634
+ /* Microsoft failed to properly
8635
+ * implement the XMLHttpRequest in IE7 (can't request local files),
8636
+ * so we use the ActiveXObject when it is available
8637
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
8638
+ * we need a fallback.
8639
+ */
8640
+ function() {
8641
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
8642
+ } :
8643
+ // For all other browsers, use the standard XMLHttpRequest object
8644
+ createStandardXHR;
8645
+
8646
+ // Determine support properties
8647
+ xhrSupported = jQuery.ajaxSettings.xhr();
8648
+ jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
8649
+ xhrSupported = jQuery.support.ajax = !!xhrSupported;
8650
+
8651
+ // Create transport if the browser can provide an xhr
8652
+ if ( xhrSupported ) {
8653
+
8654
+ jQuery.ajaxTransport(function( s ) {
8655
+ // Cross domain only allowed if supported through XMLHttpRequest
8656
+ if ( !s.crossDomain || jQuery.support.cors ) {
8657
+
8658
+ var callback;
8659
+
8660
+ return {
8661
+ send: function( headers, complete ) {
8662
+
8663
+ // Get a new xhr
8664
+ var handle, i,
8665
+ xhr = s.xhr();
8666
+
8667
+ // Open the socket
8668
+ // Passing null username, generates a login popup on Opera (#2865)
8669
+ if ( s.username ) {
8670
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
8671
+ } else {
8672
+ xhr.open( s.type, s.url, s.async );
8673
+ }
8674
+
8675
+ // Apply custom fields if provided
8676
+ if ( s.xhrFields ) {
8677
+ for ( i in s.xhrFields ) {
8678
+ xhr[ i ] = s.xhrFields[ i ];
8679
+ }
8680
+ }
8681
+
8682
+ // Override mime type if needed
8683
+ if ( s.mimeType && xhr.overrideMimeType ) {
8684
+ xhr.overrideMimeType( s.mimeType );
8685
+ }
8686
+
8687
+ // X-Requested-With header
8688
+ // For cross-domain requests, seeing as conditions for a preflight are
8689
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
8690
+ // (it can always be set on a per-request basis or even using ajaxSetup)
8691
+ // For same-domain requests, won't change header if already provided.
8692
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
8693
+ headers["X-Requested-With"] = "XMLHttpRequest";
8694
+ }
8695
+
8696
+ // Need an extra try/catch for cross domain requests in Firefox 3
8697
+ try {
8698
+ for ( i in headers ) {
8699
+ xhr.setRequestHeader( i, headers[ i ] );
8700
+ }
8701
+ } catch( err ) {}
8702
+
8703
+ // Do send the request
8704
+ // This may raise an exception which is actually
8705
+ // handled in jQuery.ajax (so no try/catch here)
8706
+ xhr.send( ( s.hasContent && s.data ) || null );
8707
+
8708
+ // Listener
8709
+ callback = function( _, isAbort ) {
8710
+ var status, responseHeaders, statusText, responses;
8711
+
8712
+ // Firefox throws exceptions when accessing properties
8713
+ // of an xhr when a network error occurred
8714
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
8715
+ try {
8716
+
8717
+ // Was never called and is aborted or complete
8718
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
8719
+
8720
+ // Only called once
8721
+ callback = undefined;
8722
+
8723
+ // Do not keep as active anymore
8724
+ if ( handle ) {
8725
+ xhr.onreadystatechange = jQuery.noop;
8726
+ if ( xhrOnUnloadAbort ) {
8727
+ delete xhrCallbacks[ handle ];
8728
+ }
8729
+ }
8730
+
8731
+ // If it's an abort
8732
+ if ( isAbort ) {
8733
+ // Abort it manually if needed
8734
+ if ( xhr.readyState !== 4 ) {
8735
+ xhr.abort();
8736
+ }
8737
+ } else {
8738
+ responses = {};
8739
+ status = xhr.status;
8740
+ responseHeaders = xhr.getAllResponseHeaders();
8741
+
8742
+ // When requesting binary data, IE6-9 will throw an exception
8743
+ // on any attempt to access responseText (#11426)
8744
+ if ( typeof xhr.responseText === "string" ) {
8745
+ responses.text = xhr.responseText;
8746
+ }
8747
+
8748
+ // Firefox throws an exception when accessing
8749
+ // statusText for faulty cross-domain requests
8750
+ try {
8751
+ statusText = xhr.statusText;
8752
+ } catch( e ) {
8753
+ // We normalize with Webkit giving an empty statusText
8754
+ statusText = "";
8755
+ }
8756
+
8757
+ // Filter status for non standard behaviors
8758
+
8759
+ // If the request is local and we have data: assume a success
8760
+ // (success with no data won't get notified, that's the best we
8761
+ // can do given current implementations)
8762
+ if ( !status && s.isLocal && !s.crossDomain ) {
8763
+ status = responses.text ? 200 : 404;
8764
+ // IE - #1450: sometimes returns 1223 when it should be 204
8765
+ } else if ( status === 1223 ) {
8766
+ status = 204;
8767
+ }
8768
+ }
8769
+ }
8770
+ } catch( firefoxAccessException ) {
8771
+ if ( !isAbort ) {
8772
+ complete( -1, firefoxAccessException );
8773
+ }
8774
+ }
8775
+
8776
+ // Call complete if needed
8777
+ if ( responses ) {
8778
+ complete( status, statusText, responses, responseHeaders );
8779
+ }
8780
+ };
8781
+
8782
+ if ( !s.async ) {
8783
+ // if we're in sync mode we fire the callback
8784
+ callback();
8785
+ } else if ( xhr.readyState === 4 ) {
8786
+ // (IE6 & IE7) if it's in cache and has been
8787
+ // retrieved directly we need to fire the callback
8788
+ setTimeout( callback );
8789
+ } else {
8790
+ handle = ++xhrId;
8791
+ if ( xhrOnUnloadAbort ) {
8792
+ // Create the active xhrs callbacks list if needed
8793
+ // and attach the unload handler
8794
+ if ( !xhrCallbacks ) {
8795
+ xhrCallbacks = {};
8796
+ jQuery( window ).unload( xhrOnUnloadAbort );
8797
+ }
8798
+ // Add to list of active xhrs callbacks
8799
+ xhrCallbacks[ handle ] = callback;
8800
+ }
8801
+ xhr.onreadystatechange = callback;
8802
+ }
8803
+ },
8804
+
8805
+ abort: function() {
8806
+ if ( callback ) {
8807
+ callback( undefined, true );
8808
+ }
8809
+ }
8810
+ };
8811
+ }
8812
+ });
8813
+ }
8814
+ var fxNow, timerId,
8815
+ rfxtypes = /^(?:toggle|show|hide)$/,
8816
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
8817
+ rrun = /queueHooks$/,
8818
+ animationPrefilters = [ defaultPrefilter ],
8819
+ tweeners = {
8820
+ "*": [function( prop, value ) {
8821
+ var tween = this.createTween( prop, value ),
8822
+ target = tween.cur(),
8823
+ parts = rfxnum.exec( value ),
8824
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
8825
+
8826
+ // Starting value computation is required for potential unit mismatches
8827
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
8828
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
8829
+ scale = 1,
8830
+ maxIterations = 20;
8831
+
8832
+ if ( start && start[ 3 ] !== unit ) {
8833
+ // Trust units reported by jQuery.css
8834
+ unit = unit || start[ 3 ];
8835
+
8836
+ // Make sure we update the tween properties later on
8837
+ parts = parts || [];
8838
+
8839
+ // Iteratively approximate from a nonzero starting point
8840
+ start = +target || 1;
8841
+
8842
+ do {
8843
+ // If previous iteration zeroed out, double until we get *something*
8844
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
8845
+ scale = scale || ".5";
8846
+
8847
+ // Adjust and apply
8848
+ start = start / scale;
8849
+ jQuery.style( tween.elem, prop, start + unit );
8850
+
8851
+ // Update scale, tolerating zero or NaN from tween.cur()
8852
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
8853
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
8854
+ }
8855
+
8856
+ // Update tween properties
8857
+ if ( parts ) {
8858
+ start = tween.start = +start || +target || 0;
8859
+ tween.unit = unit;
8860
+ // If a +=/-= token was provided, we're doing a relative animation
8861
+ tween.end = parts[ 1 ] ?
8862
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
8863
+ +parts[ 2 ];
8864
+ }
8865
+
8866
+ return tween;
8867
+ }]
8868
+ };
8869
+
8870
+ // Animations created synchronously will run synchronously
8871
+ function createFxNow() {
8872
+ setTimeout(function() {
8873
+ fxNow = undefined;
8874
+ });
8875
+ return ( fxNow = jQuery.now() );
8876
+ }
8877
+
8878
+ function createTween( value, prop, animation ) {
8879
+ var tween,
8880
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
8881
+ index = 0,
8882
+ length = collection.length;
8883
+ for ( ; index < length; index++ ) {
8884
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
8885
+
8886
+ // we're done with this property
8887
+ return tween;
8888
+ }
8889
+ }
8890
+ }
8891
+
8892
+ function Animation( elem, properties, options ) {
8893
+ var result,
8894
+ stopped,
8895
+ index = 0,
8896
+ length = animationPrefilters.length,
8897
+ deferred = jQuery.Deferred().always( function() {
8898
+ // don't match elem in the :animated selector
8899
+ delete tick.elem;
8900
+ }),
8901
+ tick = function() {
8902
+ if ( stopped ) {
8903
+ return false;
8904
+ }
8905
+ var currentTime = fxNow || createFxNow(),
8906
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
8907
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
8908
+ temp = remaining / animation.duration || 0,
8909
+ percent = 1 - temp,
8910
+ index = 0,
8911
+ length = animation.tweens.length;
8912
+
8913
+ for ( ; index < length ; index++ ) {
8914
+ animation.tweens[ index ].run( percent );
8915
+ }
8916
+
8917
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
8918
+
8919
+ if ( percent < 1 && length ) {
8920
+ return remaining;
8921
+ } else {
8922
+ deferred.resolveWith( elem, [ animation ] );
8923
+ return false;
8924
+ }
8925
+ },
8926
+ animation = deferred.promise({
8927
+ elem: elem,
8928
+ props: jQuery.extend( {}, properties ),
8929
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
8930
+ originalProperties: properties,
8931
+ originalOptions: options,
8932
+ startTime: fxNow || createFxNow(),
8933
+ duration: options.duration,
8934
+ tweens: [],
8935
+ createTween: function( prop, end ) {
8936
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
8937
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
8938
+ animation.tweens.push( tween );
8939
+ return tween;
8940
+ },
8941
+ stop: function( gotoEnd ) {
8942
+ var index = 0,
8943
+ // if we are going to the end, we want to run all the tweens
8944
+ // otherwise we skip this part
8945
+ length = gotoEnd ? animation.tweens.length : 0;
8946
+ if ( stopped ) {
8947
+ return this;
8948
+ }
8949
+ stopped = true;
8950
+ for ( ; index < length ; index++ ) {
8951
+ animation.tweens[ index ].run( 1 );
8952
+ }
8953
+
8954
+ // resolve when we played the last frame
8955
+ // otherwise, reject
8956
+ if ( gotoEnd ) {
8957
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
8958
+ } else {
8959
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
8960
+ }
8961
+ return this;
8962
+ }
8963
+ }),
8964
+ props = animation.props;
8965
+
8966
+ propFilter( props, animation.opts.specialEasing );
8967
+
8968
+ for ( ; index < length ; index++ ) {
8969
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
8970
+ if ( result ) {
8971
+ return result;
8972
+ }
8973
+ }
8974
+
8975
+ jQuery.map( props, createTween, animation );
8976
+
8977
+ if ( jQuery.isFunction( animation.opts.start ) ) {
8978
+ animation.opts.start.call( elem, animation );
8979
+ }
8980
+
8981
+ jQuery.fx.timer(
8982
+ jQuery.extend( tick, {
8983
+ elem: elem,
8984
+ anim: animation,
8985
+ queue: animation.opts.queue
8986
+ })
8987
+ );
8988
+
8989
+ // attach callbacks from options
8990
+ return animation.progress( animation.opts.progress )
8991
+ .done( animation.opts.done, animation.opts.complete )
8992
+ .fail( animation.opts.fail )
8993
+ .always( animation.opts.always );
8994
+ }
8995
+
8996
+ function propFilter( props, specialEasing ) {
8997
+ var index, name, easing, value, hooks;
8998
+
8999
+ // camelCase, specialEasing and expand cssHook pass
9000
+ for ( index in props ) {
9001
+ name = jQuery.camelCase( index );
9002
+ easing = specialEasing[ name ];
9003
+ value = props[ index ];
9004
+ if ( jQuery.isArray( value ) ) {
9005
+ easing = value[ 1 ];
9006
+ value = props[ index ] = value[ 0 ];
9007
+ }
9008
+
9009
+ if ( index !== name ) {
9010
+ props[ name ] = value;
9011
+ delete props[ index ];
9012
+ }
9013
+
9014
+ hooks = jQuery.cssHooks[ name ];
9015
+ if ( hooks && "expand" in hooks ) {
9016
+ value = hooks.expand( value );
9017
+ delete props[ name ];
9018
+
9019
+ // not quite $.extend, this wont overwrite keys already present.
9020
+ // also - reusing 'index' from above because we have the correct "name"
9021
+ for ( index in value ) {
9022
+ if ( !( index in props ) ) {
9023
+ props[ index ] = value[ index ];
9024
+ specialEasing[ index ] = easing;
9025
+ }
9026
+ }
9027
+ } else {
9028
+ specialEasing[ name ] = easing;
9029
+ }
9030
+ }
9031
+ }
9032
+
9033
+ jQuery.Animation = jQuery.extend( Animation, {
9034
+
9035
+ tweener: function( props, callback ) {
9036
+ if ( jQuery.isFunction( props ) ) {
9037
+ callback = props;
9038
+ props = [ "*" ];
9039
+ } else {
9040
+ props = props.split(" ");
9041
+ }
9042
+
9043
+ var prop,
9044
+ index = 0,
9045
+ length = props.length;
9046
+
9047
+ for ( ; index < length ; index++ ) {
9048
+ prop = props[ index ];
9049
+ tweeners[ prop ] = tweeners[ prop ] || [];
9050
+ tweeners[ prop ].unshift( callback );
9051
+ }
9052
+ },
9053
+
9054
+ prefilter: function( callback, prepend ) {
9055
+ if ( prepend ) {
9056
+ animationPrefilters.unshift( callback );
9057
+ } else {
9058
+ animationPrefilters.push( callback );
9059
+ }
9060
+ }
9061
+ });
9062
+
9063
+ function defaultPrefilter( elem, props, opts ) {
9064
+ /* jshint validthis: true */
9065
+ var prop, value, toggle, tween, hooks, oldfire,
9066
+ anim = this,
9067
+ orig = {},
9068
+ style = elem.style,
9069
+ hidden = elem.nodeType && isHidden( elem ),
9070
+ dataShow = jQuery._data( elem, "fxshow" );
9071
+
9072
+ // handle queue: false promises
9073
+ if ( !opts.queue ) {
9074
+ hooks = jQuery._queueHooks( elem, "fx" );
9075
+ if ( hooks.unqueued == null ) {
9076
+ hooks.unqueued = 0;
9077
+ oldfire = hooks.empty.fire;
9078
+ hooks.empty.fire = function() {
9079
+ if ( !hooks.unqueued ) {
9080
+ oldfire();
9081
+ }
9082
+ };
9083
+ }
9084
+ hooks.unqueued++;
9085
+
9086
+ anim.always(function() {
9087
+ // doing this makes sure that the complete handler will be called
9088
+ // before this completes
9089
+ anim.always(function() {
9090
+ hooks.unqueued--;
9091
+ if ( !jQuery.queue( elem, "fx" ).length ) {
9092
+ hooks.empty.fire();
9093
+ }
9094
+ });
9095
+ });
9096
+ }
9097
+
9098
+ // height/width overflow pass
9099
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
9100
+ // Make sure that nothing sneaks out
9101
+ // Record all 3 overflow attributes because IE does not
9102
+ // change the overflow attribute when overflowX and
9103
+ // overflowY are set to the same value
9104
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
9105
+
9106
+ // Set display property to inline-block for height/width
9107
+ // animations on inline elements that are having width/height animated
9108
+ if ( jQuery.css( elem, "display" ) === "inline" &&
9109
+ jQuery.css( elem, "float" ) === "none" ) {
9110
+
9111
+ // inline-level elements accept inline-block;
9112
+ // block-level elements need to be inline with layout
9113
+ if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
9114
+ style.display = "inline-block";
9115
+
9116
+ } else {
9117
+ style.zoom = 1;
9118
+ }
9119
+ }
9120
+ }
9121
+
9122
+ if ( opts.overflow ) {
9123
+ style.overflow = "hidden";
9124
+ if ( !jQuery.support.shrinkWrapBlocks ) {
9125
+ anim.always(function() {
9126
+ style.overflow = opts.overflow[ 0 ];
9127
+ style.overflowX = opts.overflow[ 1 ];
9128
+ style.overflowY = opts.overflow[ 2 ];
9129
+ });
9130
+ }
9131
+ }
9132
+
9133
+
9134
+ // show/hide pass
9135
+ for ( prop in props ) {
9136
+ value = props[ prop ];
9137
+ if ( rfxtypes.exec( value ) ) {
9138
+ delete props[ prop ];
9139
+ toggle = toggle || value === "toggle";
9140
+ if ( value === ( hidden ? "hide" : "show" ) ) {
9141
+ continue;
9142
+ }
9143
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
9144
+ }
9145
+ }
9146
+
9147
+ if ( !jQuery.isEmptyObject( orig ) ) {
9148
+ if ( dataShow ) {
9149
+ if ( "hidden" in dataShow ) {
9150
+ hidden = dataShow.hidden;
9151
+ }
9152
+ } else {
9153
+ dataShow = jQuery._data( elem, "fxshow", {} );
9154
+ }
9155
+
9156
+ // store state if its toggle - enables .stop().toggle() to "reverse"
9157
+ if ( toggle ) {
9158
+ dataShow.hidden = !hidden;
9159
+ }
9160
+ if ( hidden ) {
9161
+ jQuery( elem ).show();
9162
+ } else {
9163
+ anim.done(function() {
9164
+ jQuery( elem ).hide();
9165
+ });
9166
+ }
9167
+ anim.done(function() {
9168
+ var prop;
9169
+ jQuery._removeData( elem, "fxshow" );
9170
+ for ( prop in orig ) {
9171
+ jQuery.style( elem, prop, orig[ prop ] );
9172
+ }
9173
+ });
9174
+ for ( prop in orig ) {
9175
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
9176
+
9177
+ if ( !( prop in dataShow ) ) {
9178
+ dataShow[ prop ] = tween.start;
9179
+ if ( hidden ) {
9180
+ tween.end = tween.start;
9181
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
9182
+ }
9183
+ }
9184
+ }
9185
+ }
9186
+ }
9187
+
9188
+ function Tween( elem, options, prop, end, easing ) {
9189
+ return new Tween.prototype.init( elem, options, prop, end, easing );
9190
+ }
9191
+ jQuery.Tween = Tween;
9192
+
9193
+ Tween.prototype = {
9194
+ constructor: Tween,
9195
+ init: function( elem, options, prop, end, easing, unit ) {
9196
+ this.elem = elem;
9197
+ this.prop = prop;
9198
+ this.easing = easing || "swing";
9199
+ this.options = options;
9200
+ this.start = this.now = this.cur();
9201
+ this.end = end;
9202
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
9203
+ },
9204
+ cur: function() {
9205
+ var hooks = Tween.propHooks[ this.prop ];
9206
+
9207
+ return hooks && hooks.get ?
9208
+ hooks.get( this ) :
9209
+ Tween.propHooks._default.get( this );
9210
+ },
9211
+ run: function( percent ) {
9212
+ var eased,
9213
+ hooks = Tween.propHooks[ this.prop ];
9214
+
9215
+ if ( this.options.duration ) {
9216
+ this.pos = eased = jQuery.easing[ this.easing ](
9217
+ percent, this.options.duration * percent, 0, 1, this.options.duration
9218
+ );
9219
+ } else {
9220
+ this.pos = eased = percent;
9221
+ }
9222
+ this.now = ( this.end - this.start ) * eased + this.start;
9223
+
9224
+ if ( this.options.step ) {
9225
+ this.options.step.call( this.elem, this.now, this );
9226
+ }
9227
+
9228
+ if ( hooks && hooks.set ) {
9229
+ hooks.set( this );
9230
+ } else {
9231
+ Tween.propHooks._default.set( this );
9232
+ }
9233
+ return this;
9234
+ }
9235
+ };
9236
+
9237
+ Tween.prototype.init.prototype = Tween.prototype;
9238
+
9239
+ Tween.propHooks = {
9240
+ _default: {
9241
+ get: function( tween ) {
9242
+ var result;
9243
+
9244
+ if ( tween.elem[ tween.prop ] != null &&
9245
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
9246
+ return tween.elem[ tween.prop ];
9247
+ }
9248
+
9249
+ // passing an empty string as a 3rd parameter to .css will automatically
9250
+ // attempt a parseFloat and fallback to a string if the parse fails
9251
+ // so, simple values such as "10px" are parsed to Float.
9252
+ // complex values such as "rotate(1rad)" are returned as is.
9253
+ result = jQuery.css( tween.elem, tween.prop, "" );
9254
+ // Empty strings, null, undefined and "auto" are converted to 0.
9255
+ return !result || result === "auto" ? 0 : result;
9256
+ },
9257
+ set: function( tween ) {
9258
+ // use step hook for back compat - use cssHook if its there - use .style if its
9259
+ // available and use plain properties where available
9260
+ if ( jQuery.fx.step[ tween.prop ] ) {
9261
+ jQuery.fx.step[ tween.prop ]( tween );
9262
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
9263
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
9264
+ } else {
9265
+ tween.elem[ tween.prop ] = tween.now;
9266
+ }
9267
+ }
9268
+ }
9269
+ };
9270
+
9271
+ // Support: IE <=9
9272
+ // Panic based approach to setting things on disconnected nodes
9273
+
9274
+ Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
9275
+ set: function( tween ) {
9276
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
9277
+ tween.elem[ tween.prop ] = tween.now;
9278
+ }
9279
+ }
9280
+ };
9281
+
9282
+ jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
9283
+ var cssFn = jQuery.fn[ name ];
9284
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
9285
+ return speed == null || typeof speed === "boolean" ?
9286
+ cssFn.apply( this, arguments ) :
9287
+ this.animate( genFx( name, true ), speed, easing, callback );
9288
+ };
9289
+ });
9290
+
9291
+ jQuery.fn.extend({
9292
+ fadeTo: function( speed, to, easing, callback ) {
9293
+
9294
+ // show any hidden elements after setting opacity to 0
9295
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
9296
+
9297
+ // animate to the value specified
9298
+ .end().animate({ opacity: to }, speed, easing, callback );
9299
+ },
9300
+ animate: function( prop, speed, easing, callback ) {
9301
+ var empty = jQuery.isEmptyObject( prop ),
9302
+ optall = jQuery.speed( speed, easing, callback ),
9303
+ doAnimation = function() {
9304
+ // Operate on a copy of prop so per-property easing won't be lost
9305
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
9306
+
9307
+ // Empty animations, or finishing resolves immediately
9308
+ if ( empty || jQuery._data( this, "finish" ) ) {
9309
+ anim.stop( true );
9310
+ }
9311
+ };
9312
+ doAnimation.finish = doAnimation;
9313
+
9314
+ return empty || optall.queue === false ?
9315
+ this.each( doAnimation ) :
9316
+ this.queue( optall.queue, doAnimation );
9317
+ },
9318
+ stop: function( type, clearQueue, gotoEnd ) {
9319
+ var stopQueue = function( hooks ) {
9320
+ var stop = hooks.stop;
9321
+ delete hooks.stop;
9322
+ stop( gotoEnd );
9323
+ };
9324
+
9325
+ if ( typeof type !== "string" ) {
9326
+ gotoEnd = clearQueue;
9327
+ clearQueue = type;
9328
+ type = undefined;
9329
+ }
9330
+ if ( clearQueue && type !== false ) {
9331
+ this.queue( type || "fx", [] );
9332
+ }
9333
+
9334
+ return this.each(function() {
9335
+ var dequeue = true,
9336
+ index = type != null && type + "queueHooks",
9337
+ timers = jQuery.timers,
9338
+ data = jQuery._data( this );
9339
+
9340
+ if ( index ) {
9341
+ if ( data[ index ] && data[ index ].stop ) {
9342
+ stopQueue( data[ index ] );
9343
+ }
9344
+ } else {
9345
+ for ( index in data ) {
9346
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
9347
+ stopQueue( data[ index ] );
9348
+ }
9349
+ }
9350
+ }
9351
+
9352
+ for ( index = timers.length; index--; ) {
9353
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
9354
+ timers[ index ].anim.stop( gotoEnd );
9355
+ dequeue = false;
9356
+ timers.splice( index, 1 );
9357
+ }
9358
+ }
9359
+
9360
+ // start the next in the queue if the last step wasn't forced
9361
+ // timers currently will call their complete callbacks, which will dequeue
9362
+ // but only if they were gotoEnd
9363
+ if ( dequeue || !gotoEnd ) {
9364
+ jQuery.dequeue( this, type );
9365
+ }
9366
+ });
9367
+ },
9368
+ finish: function( type ) {
9369
+ if ( type !== false ) {
9370
+ type = type || "fx";
9371
+ }
9372
+ return this.each(function() {
9373
+ var index,
9374
+ data = jQuery._data( this ),
9375
+ queue = data[ type + "queue" ],
9376
+ hooks = data[ type + "queueHooks" ],
9377
+ timers = jQuery.timers,
9378
+ length = queue ? queue.length : 0;
9379
+
9380
+ // enable finishing flag on private data
9381
+ data.finish = true;
9382
+
9383
+ // empty the queue first
9384
+ jQuery.queue( this, type, [] );
9385
+
9386
+ if ( hooks && hooks.stop ) {
9387
+ hooks.stop.call( this, true );
9388
+ }
9389
+
9390
+ // look for any active animations, and finish them
9391
+ for ( index = timers.length; index--; ) {
9392
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
9393
+ timers[ index ].anim.stop( true );
9394
+ timers.splice( index, 1 );
9395
+ }
9396
+ }
9397
+
9398
+ // look for any animations in the old queue and finish them
9399
+ for ( index = 0; index < length; index++ ) {
9400
+ if ( queue[ index ] && queue[ index ].finish ) {
9401
+ queue[ index ].finish.call( this );
9402
+ }
9403
+ }
9404
+
9405
+ // turn off finishing flag
9406
+ delete data.finish;
9407
+ });
9408
+ }
9409
+ });
9410
+
9411
+ // Generate parameters to create a standard animation
9412
+ function genFx( type, includeWidth ) {
9413
+ var which,
9414
+ attrs = { height: type },
9415
+ i = 0;
9416
+
9417
+ // if we include width, step value is 1 to do all cssExpand values,
9418
+ // if we don't include width, step value is 2 to skip over Left and Right
9419
+ includeWidth = includeWidth? 1 : 0;
9420
+ for( ; i < 4 ; i += 2 - includeWidth ) {
9421
+ which = cssExpand[ i ];
9422
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
9423
+ }
9424
+
9425
+ if ( includeWidth ) {
9426
+ attrs.opacity = attrs.width = type;
9427
+ }
9428
+
9429
+ return attrs;
9430
+ }
9431
+
9432
+ // Generate shortcuts for custom animations
9433
+ jQuery.each({
9434
+ slideDown: genFx("show"),
9435
+ slideUp: genFx("hide"),
9436
+ slideToggle: genFx("toggle"),
9437
+ fadeIn: { opacity: "show" },
9438
+ fadeOut: { opacity: "hide" },
9439
+ fadeToggle: { opacity: "toggle" }
9440
+ }, function( name, props ) {
9441
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
9442
+ return this.animate( props, speed, easing, callback );
9443
+ };
9444
+ });
9445
+
9446
+ jQuery.speed = function( speed, easing, fn ) {
9447
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
9448
+ complete: fn || !fn && easing ||
9449
+ jQuery.isFunction( speed ) && speed,
9450
+ duration: speed,
9451
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
9452
+ };
9453
+
9454
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
9455
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
9456
+
9457
+ // normalize opt.queue - true/undefined/null -> "fx"
9458
+ if ( opt.queue == null || opt.queue === true ) {
9459
+ opt.queue = "fx";
9460
+ }
9461
+
9462
+ // Queueing
9463
+ opt.old = opt.complete;
9464
+
9465
+ opt.complete = function() {
9466
+ if ( jQuery.isFunction( opt.old ) ) {
9467
+ opt.old.call( this );
9468
+ }
9469
+
9470
+ if ( opt.queue ) {
9471
+ jQuery.dequeue( this, opt.queue );
9472
+ }
9473
+ };
9474
+
9475
+ return opt;
9476
+ };
9477
+
9478
+ jQuery.easing = {
9479
+ linear: function( p ) {
9480
+ return p;
9481
+ },
9482
+ swing: function( p ) {
9483
+ return 0.5 - Math.cos( p*Math.PI ) / 2;
9484
+ }
9485
+ };
9486
+
9487
+ jQuery.timers = [];
9488
+ jQuery.fx = Tween.prototype.init;
9489
+ jQuery.fx.tick = function() {
9490
+ var timer,
9491
+ timers = jQuery.timers,
9492
+ i = 0;
9493
+
9494
+ fxNow = jQuery.now();
9495
+
9496
+ for ( ; i < timers.length; i++ ) {
9497
+ timer = timers[ i ];
9498
+ // Checks the timer has not already been removed
9499
+ if ( !timer() && timers[ i ] === timer ) {
9500
+ timers.splice( i--, 1 );
9501
+ }
9502
+ }
9503
+
9504
+ if ( !timers.length ) {
9505
+ jQuery.fx.stop();
9506
+ }
9507
+ fxNow = undefined;
9508
+ };
9509
+
9510
+ jQuery.fx.timer = function( timer ) {
9511
+ if ( timer() && jQuery.timers.push( timer ) ) {
9512
+ jQuery.fx.start();
9513
+ }
9514
+ };
9515
+
9516
+ jQuery.fx.interval = 13;
9517
+
9518
+ jQuery.fx.start = function() {
9519
+ if ( !timerId ) {
9520
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
9521
+ }
9522
+ };
9523
+
9524
+ jQuery.fx.stop = function() {
9525
+ clearInterval( timerId );
9526
+ timerId = null;
9527
+ };
9528
+
9529
+ jQuery.fx.speeds = {
9530
+ slow: 600,
9531
+ fast: 200,
9532
+ // Default speed
9533
+ _default: 400
9534
+ };
9535
+
9536
+ // Back Compat <1.8 extension point
9537
+ jQuery.fx.step = {};
9538
+
9539
+ if ( jQuery.expr && jQuery.expr.filters ) {
9540
+ jQuery.expr.filters.animated = function( elem ) {
9541
+ return jQuery.grep(jQuery.timers, function( fn ) {
9542
+ return elem === fn.elem;
9543
+ }).length;
9544
+ };
9545
+ }
9546
+ jQuery.fn.offset = function( options ) {
9547
+ if ( arguments.length ) {
9548
+ return options === undefined ?
9549
+ this :
9550
+ this.each(function( i ) {
9551
+ jQuery.offset.setOffset( this, options, i );
9552
+ });
9553
+ }
9554
+
9555
+ var docElem, win,
9556
+ box = { top: 0, left: 0 },
9557
+ elem = this[ 0 ],
9558
+ doc = elem && elem.ownerDocument;
9559
+
9560
+ if ( !doc ) {
9561
+ return;
9562
+ }
9563
+
9564
+ docElem = doc.documentElement;
9565
+
9566
+ // Make sure it's not a disconnected DOM node
9567
+ if ( !jQuery.contains( docElem, elem ) ) {
9568
+ return box;
9569
+ }
9570
+
9571
+ // If we don't have gBCR, just use 0,0 rather than error
9572
+ // BlackBerry 5, iOS 3 (original iPhone)
9573
+ if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
9574
+ box = elem.getBoundingClientRect();
9575
+ }
9576
+ win = getWindow( doc );
9577
+ return {
9578
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
9579
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
9580
+ };
9581
+ };
9582
+
9583
+ jQuery.offset = {
9584
+
9585
+ setOffset: function( elem, options, i ) {
9586
+ var position = jQuery.css( elem, "position" );
9587
+
9588
+ // set position first, in-case top/left are set even on static elem
9589
+ if ( position === "static" ) {
9590
+ elem.style.position = "relative";
9591
+ }
9592
+
9593
+ var curElem = jQuery( elem ),
9594
+ curOffset = curElem.offset(),
9595
+ curCSSTop = jQuery.css( elem, "top" ),
9596
+ curCSSLeft = jQuery.css( elem, "left" ),
9597
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
9598
+ props = {}, curPosition = {}, curTop, curLeft;
9599
+
9600
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
9601
+ if ( calculatePosition ) {
9602
+ curPosition = curElem.position();
9603
+ curTop = curPosition.top;
9604
+ curLeft = curPosition.left;
9605
+ } else {
9606
+ curTop = parseFloat( curCSSTop ) || 0;
9607
+ curLeft = parseFloat( curCSSLeft ) || 0;
9608
+ }
9609
+
9610
+ if ( jQuery.isFunction( options ) ) {
9611
+ options = options.call( elem, i, curOffset );
9612
+ }
9613
+
9614
+ if ( options.top != null ) {
9615
+ props.top = ( options.top - curOffset.top ) + curTop;
9616
+ }
9617
+ if ( options.left != null ) {
9618
+ props.left = ( options.left - curOffset.left ) + curLeft;
9619
+ }
9620
+
9621
+ if ( "using" in options ) {
9622
+ options.using.call( elem, props );
9623
+ } else {
9624
+ curElem.css( props );
9625
+ }
9626
+ }
9627
+ };
9628
+
9629
+
9630
+ jQuery.fn.extend({
9631
+
9632
+ position: function() {
9633
+ if ( !this[ 0 ] ) {
9634
+ return;
9635
+ }
9636
+
9637
+ var offsetParent, offset,
9638
+ parentOffset = { top: 0, left: 0 },
9639
+ elem = this[ 0 ];
9640
+
9641
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
9642
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
9643
+ // we assume that getBoundingClientRect is available when computed position is fixed
9644
+ offset = elem.getBoundingClientRect();
9645
+ } else {
9646
+ // Get *real* offsetParent
9647
+ offsetParent = this.offsetParent();
9648
+
9649
+ // Get correct offsets
9650
+ offset = this.offset();
9651
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
9652
+ parentOffset = offsetParent.offset();
9653
+ }
9654
+
9655
+ // Add offsetParent borders
9656
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
9657
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
9658
+ }
9659
+
9660
+ // Subtract parent offsets and element margins
9661
+ // note: when an element has margin: auto the offsetLeft and marginLeft
9662
+ // are the same in Safari causing offset.left to incorrectly be 0
9663
+ return {
9664
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
9665
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
9666
+ };
9667
+ },
9668
+
9669
+ offsetParent: function() {
9670
+ return this.map(function() {
9671
+ var offsetParent = this.offsetParent || docElem;
9672
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
9673
+ offsetParent = offsetParent.offsetParent;
9674
+ }
9675
+ return offsetParent || docElem;
9676
+ });
9677
+ }
9678
+ });
9679
+
9680
+
9681
+ // Create scrollLeft and scrollTop methods
9682
+ jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
9683
+ var top = /Y/.test( prop );
9684
+
9685
+ jQuery.fn[ method ] = function( val ) {
9686
+ return jQuery.access( this, function( elem, method, val ) {
9687
+ var win = getWindow( elem );
9688
+
9689
+ if ( val === undefined ) {
9690
+ return win ? (prop in win) ? win[ prop ] :
9691
+ win.document.documentElement[ method ] :
9692
+ elem[ method ];
9693
+ }
9694
+
9695
+ if ( win ) {
9696
+ win.scrollTo(
9697
+ !top ? val : jQuery( win ).scrollLeft(),
9698
+ top ? val : jQuery( win ).scrollTop()
9699
+ );
9700
+
9701
+ } else {
9702
+ elem[ method ] = val;
9703
+ }
9704
+ }, method, val, arguments.length, null );
9705
+ };
9706
+ });
9707
+
9708
+ function getWindow( elem ) {
9709
+ return jQuery.isWindow( elem ) ?
9710
+ elem :
9711
+ elem.nodeType === 9 ?
9712
+ elem.defaultView || elem.parentWindow :
9713
+ false;
9714
+ }
9715
+ // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
9716
+ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
9717
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
9718
+ // margin is only for outerHeight, outerWidth
9719
+ jQuery.fn[ funcName ] = function( margin, value ) {
9720
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
9721
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
9722
+
9723
+ return jQuery.access( this, function( elem, type, value ) {
9724
+ var doc;
9725
+
9726
+ if ( jQuery.isWindow( elem ) ) {
9727
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
9728
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
9729
+ // https://github.com/jquery/jquery/pull/764
9730
+ return elem.document.documentElement[ "client" + name ];
9731
+ }
9732
+
9733
+ // Get document width or height
9734
+ if ( elem.nodeType === 9 ) {
9735
+ doc = elem.documentElement;
9736
+
9737
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
9738
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
9739
+ return Math.max(
9740
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
9741
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
9742
+ doc[ "client" + name ]
9743
+ );
9744
+ }
9745
+
9746
+ return value === undefined ?
9747
+ // Get width or height on the element, requesting but not forcing parseFloat
9748
+ jQuery.css( elem, type, extra ) :
9749
+
9750
+ // Set width or height on the element
9751
+ jQuery.style( elem, type, value, extra );
9752
+ }, type, chainable ? margin : undefined, chainable, null );
9753
+ };
9754
+ });
9755
+ });
9756
+ // Limit scope pollution from any deprecated API
9757
+ // (function() {
9758
+
9759
+ // The number of elements contained in the matched element set
9760
+ jQuery.fn.size = function() {
9761
+ return this.length;
9762
+ };
9763
+
9764
+ jQuery.fn.andSelf = jQuery.fn.addBack;
9765
+
9766
+ // })();
9767
+ if ( typeof module === "object" && module && typeof module.exports === "object" ) {
9768
+ // Expose jQuery as module.exports in loaders that implement the Node
9769
+ // module pattern (including browserify). Do not create the global, since
9770
+ // the user will be storing it themselves locally, and globals are frowned
9771
+ // upon in the Node module world.
9772
+ module.exports = jQuery;
9773
+ } else {
9774
+ // Otherwise expose jQuery to the global object as usual
9775
+ window.jQuery = window.$ = jQuery;
9776
+
9777
+ // Register as a named AMD module, since jQuery can be concatenated with other
9778
+ // files that may use define, but not via a proper concatenation script that
9779
+ // understands anonymous AMD modules. A named AMD is safest and most robust
9780
+ // way to register. Lowercase jquery is used because AMD module names are
9781
+ // derived from file names, and jQuery is normally delivered in a lowercase
9782
+ // file name. Do this after creating the global so that if an AMD module wants
9783
+ // to call noConflict to hide this version of jQuery, it will work.
9784
+ if ( typeof define === "function" && define.amd ) {
9785
+ define( "jquery", [], function () { return jQuery; } );
9786
+ }
9787
+ }
9788
+
9789
+ })( window );
9790
+ aejQuery = jQuery.noConflict( true );
9791
+