Version Notes
Google Analytics code for related, crosssells, upsells
Download this release
Release Info
Developer | 4Tell Inc |
Extension | FourTell_Recommend_S |
Version | 1.2.8 |
Comparing to | |
See all releases |
Version 1.2.8
- app/code/community/FourTell/Recommend/Block/Catalog/Product/List/Related.php +141 -0
- app/code/community/FourTell/Recommend/Block/Catalog/Product/List/Upsell.php +132 -0
- app/code/community/FourTell/Recommend/Block/Checkout/Cart/Crosssell.php +70 -0
- app/code/community/FourTell/Recommend/Block/Checkout/Cart/Crosssellcommunity.php +75 -0
- app/code/community/FourTell/Recommend/Block/Checkout/Cart/Crosssellenterprise.php +65 -0
- app/code/community/FourTell/Recommend/Block/System/Config/Form/Field/Upload.php +19 -0
- app/code/community/FourTell/Recommend/Block/System/Config/Google/Analytics/Change.php +8 -0
- app/code/community/FourTell/Recommend/Block/System/Config/Google/Analytics/Code.php +10 -0
- app/code/community/FourTell/Recommend/Block/System/Config/Google/Analytics/Status.php +13 -0
- app/code/community/FourTell/Recommend/Block/Widget.php +366 -0
- app/code/community/FourTell/Recommend/Helper/Data.php +293 -0
- app/code/community/FourTell/Recommend/Model/Adminhtml/Uploadform.php +403 -0
- app/code/community/FourTell/Recommend/Model/DataProcess.php +22 -0
- app/code/community/FourTell/Recommend/Model/Observer.php +54 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Source/Crosssell.php +22 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Source/Enabled.php +22 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Source/Mode.php +22 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Source/Related.php +22 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Source/Reportlevel.php +25 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Source/Resell.php +22 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Source/Resultformat.php +24 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Source/Upsell.php +22 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Clientid.php +24 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Email.php +26 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Maxsalesdataageinmonths.php +24 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Mincommon.php +24 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Minlikelihood.php +24 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Numcrosssell.php +24 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Numrelated.php +24 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Numupsell.php +24 -0
- app/code/community/FourTell/Recommend/Model/System/Config/Validation/Owner.php +24 -0
- app/code/community/FourTell/Recommend/Model/Upload/Frequency.php +14 -0
- app/code/community/FourTell/Recommend/Model/UploadSetting.php +348 -0
- app/code/community/FourTell/Recommend/controllers/Adminhtml/UploadformController.php +908 -0
- app/code/community/FourTell/Recommend/etc/config.xml +172 -0
- app/code/community/FourTell/Recommend/etc/system.xml +304 -0
- app/code/community/FourTell/Recommend/etc/upload.xml +12 -0
- app/code/community/FourTell/Recommend/etc/widget.xml +111 -0
- app/design/adminhtml/default/default/layout/recommend.xml +10 -0
- app/design/adminhtml/default/default/template/recommend/uploadform.phtml +625 -0
- app/design/frontend/base/default/layout/recommend.xml +28 -0
- app/design/frontend/base/default/template/recommend/catalog/product/list/related.phtml +123 -0
- app/design/frontend/base/default/template/recommend/catalog/product/list/upsell.phtml +79 -0
- app/design/frontend/base/default/template/recommend/checkout/cart/crosssell.phtml +86 -0
- app/etc/modules/FourTell_Recommend.xml +9 -0
- app/locale/en_US/FourTell_Recommend.csv +1 -0
- js/jquery.tools.min.js +21 -0
- package.xml +18 -0
- skin/frontend/base/default/images/hori_large.png +0 -0
app/code/community/FourTell/Recommend/Block/Catalog/Product/List/Related.php
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Used to override Mage_Catalog_Block_Product_List_Related
|
8 |
+
* Automatically replaces the functionality to get related products
|
9 |
+
*
|
10 |
+
* @package FourTell_Recommend
|
11 |
+
* @copyright 4-Tell, Inc.
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
class FourTell_Recommend_Block_Catalog_Product_List_Related extends Mage_Catalog_Block_Product_List_Related {
|
15 |
+
|
16 |
+
const CACHE_LIFETIME = 86400;
|
17 |
+
|
18 |
+
protected $_itemCollection;
|
19 |
+
|
20 |
+
protected function _construct(){
|
21 |
+
//parent::__construct();
|
22 |
+
//$this->setTemplate('recommend/catalog/product/list/related.phtml');
|
23 |
+
$this->setRecommendationType('related');
|
24 |
+
}
|
25 |
+
|
26 |
+
public function getCacheKeyInfo(){
|
27 |
+
$cacheInfo = parent::getCacheKeyInfo();
|
28 |
+
$cacheInfo[] = Mage::registry('product')->getData('entity_id');
|
29 |
+
$cacheInfo[] = implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds());
|
30 |
+
$cacheInfo[] = implode(",", Mage::registry('previous_products'));
|
31 |
+
$cacheInfo[] = Mage::getSingleton('customer/session')->getCustomerId();
|
32 |
+
$cacheInfo[] = "Related";
|
33 |
+
$cacheInfo[] = Mage::helper('recommend')->displayNumrelatedEnabled();
|
34 |
+
return $cacheInfo;
|
35 |
+
}
|
36 |
+
|
37 |
+
protected function _prepareData() {
|
38 |
+
// If extension is not enabled use default functionality
|
39 |
+
if (!Mage::helper('recommend')->isEnabled()){
|
40 |
+
Mage::Log('recommend module is disabled');
|
41 |
+
return parent::_prepareData();
|
42 |
+
}
|
43 |
+
|
44 |
+
// If related recommendations is off the use default functionality
|
45 |
+
if (!Mage::helper('recommend')->isDisplayRelatedEnabled()){
|
46 |
+
Mage::Log('displaying related recommendations is disabled');
|
47 |
+
return parent::_prepareData();
|
48 |
+
}
|
49 |
+
// Get current product being viewed
|
50 |
+
$product = Mage::registry('product');
|
51 |
+
|
52 |
+
if (!Mage::registry('previous_products')) {
|
53 |
+
$previous_products='';
|
54 |
+
}
|
55 |
+
else{
|
56 |
+
$previous_products=implode(",", Mage::registry('previous_products'));
|
57 |
+
}
|
58 |
+
|
59 |
+
// Call the web service to get recommended products
|
60 |
+
$ids = Mage::helper('recommend')->getRecommendations(
|
61 |
+
$product->getData('entity_id'),
|
62 |
+
implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds()),
|
63 |
+
$previous_products,
|
64 |
+
Mage::getSingleton('customer/session')->getCustomerId(),
|
65 |
+
"Related",
|
66 |
+
Mage::helper('recommend')->displayNumrelatedEnabled()
|
67 |
+
);
|
68 |
+
//Mage::Log('related');
|
69 |
+
//Mage::Log($ids);
|
70 |
+
|
71 |
+
if (!Mage::registry('previous_products')) {
|
72 |
+
Mage::register('previous_products', $ids);
|
73 |
+
}
|
74 |
+
|
75 |
+
$this->_itemCollection = Mage::getModel('catalog/product')->getCollection()->addAttributeToFilter('entity_id', array('in' => $ids,));
|
76 |
+
|
77 |
+
Mage::getResourceSingleton('checkout/cart')->addExcludeProductFilter($this->_itemCollection,
|
78 |
+
Mage::getSingleton('checkout/session')->getQuoteId()
|
79 |
+
);
|
80 |
+
$this->_addProductAttributesAndPrices($this->_itemCollection);
|
81 |
+
|
82 |
+
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($this->_itemCollection);
|
83 |
+
//arrange final collection
|
84 |
+
if(is_array($ids) && count($ids)>0){
|
85 |
+
$final_collection=Mage::getModel('catalog/product')->getCollection()->addAttributeToFilter('entity_id', -1);
|
86 |
+
foreach($ids as $id){
|
87 |
+
$item=Mage::getModel('catalog/product')->load($id);
|
88 |
+
if($item->getId()){
|
89 |
+
$final_collection->addItem($item);
|
90 |
+
Mage::log('related_item_id: '.$item->getId());
|
91 |
+
}
|
92 |
+
else{
|
93 |
+
Mage::Log('no related items found in db; id: '.$id);
|
94 |
+
}
|
95 |
+
}
|
96 |
+
$this->_itemCollection=$final_collection;
|
97 |
+
}
|
98 |
+
///arrange final collection
|
99 |
+
$this->_itemCollection->load();
|
100 |
+
|
101 |
+
foreach ($this->_itemCollection as $product) {
|
102 |
+
$product->setDoNotUseCategoryId(true);
|
103 |
+
}
|
104 |
+
|
105 |
+
return $this;
|
106 |
+
}
|
107 |
+
|
108 |
+
protected function _beforeToHtml() {
|
109 |
+
$this->_prepareData();
|
110 |
+
return parent::_beforeToHtml();
|
111 |
+
}
|
112 |
+
|
113 |
+
public function getItems() {
|
114 |
+
return $this->_itemCollection;
|
115 |
+
}
|
116 |
+
|
117 |
+
public function hasItems() {
|
118 |
+
return True;
|
119 |
+
}
|
120 |
+
|
121 |
+
public function getItemCollection() {
|
122 |
+
return $this->_itemCollection;
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Return true if at least one of the related products can be selected by checkbox, othervise
|
127 |
+
false
|
128 |
+
*
|
129 |
+
* @return bool
|
130 |
+
*/
|
131 |
+
public function isSelectableProductsExist()
|
132 |
+
{
|
133 |
+
foreach ($this->getItems() as $_item) {
|
134 |
+
if(!$_item->isComposite() && $_item->isSaleable() && !$_item->getRequiredOptions()) {
|
135 |
+
return true;
|
136 |
+
}
|
137 |
+
}
|
138 |
+
return false;
|
139 |
+
}
|
140 |
+
|
141 |
+
}
|
app/code/community/FourTell/Recommend/Block/Catalog/Product/List/Upsell.php
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Used to override Mage_Catalog_Block_Product_List_Upsell
|
8 |
+
* Automatically replaces the functionality to get upsell products
|
9 |
+
*
|
10 |
+
* @package FourTell_Recommend
|
11 |
+
* @copyright 4-Tell, Inc.
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
class FourTell_Recommend_Block_Catalog_Product_List_Upsell extends Mage_Catalog_Block_Product_List_Upsell {
|
15 |
+
|
16 |
+
const CACHE_LIFETIME=86400;
|
17 |
+
|
18 |
+
protected $_itemCollection;
|
19 |
+
|
20 |
+
public function __construct(){
|
21 |
+
//parent::__construct();
|
22 |
+
//$this->setTemplate('fourtell/product/list/upsell.phtml');
|
23 |
+
$this->setRecommendationType('upsell');
|
24 |
+
}
|
25 |
+
|
26 |
+
public function getCacheKeyInfo(){
|
27 |
+
$cacheInfo = parent::getCacheKeyInfo();
|
28 |
+
$cacheInfo[] = Mage::registry('product')->getData('entity_id');
|
29 |
+
$cacheInfo[] = implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds());
|
30 |
+
$cacheInfo[] = implode(",", Mage::registry('previous_products'));
|
31 |
+
$cacheInfo[] = Mage::getSingleton('customer/session')->getCustomerId();
|
32 |
+
$cacheInfo[] = "Upsell";
|
33 |
+
$cacheInfo[] = Mage::getStoreConfig('recommend/display_recommendation/numupsell');
|
34 |
+
return $cacheInfo;
|
35 |
+
}
|
36 |
+
|
37 |
+
protected function _prepareData() {
|
38 |
+
// If extension is not enabled use default functionality
|
39 |
+
if (!Mage::helper('recommend')->isEnabled()){
|
40 |
+
return parent::_prepareData();
|
41 |
+
}
|
42 |
+
|
43 |
+
// If upsell recommendations is off the use default functionality
|
44 |
+
if (!Mage::helper('recommend')->isDisplayUpsellEnabled()){
|
45 |
+
return parent::_prepareData();
|
46 |
+
}
|
47 |
+
|
48 |
+
// Get current product being viewed
|
49 |
+
$product = Mage::registry('product');
|
50 |
+
|
51 |
+
if (!Mage::registry('previous_products')) {
|
52 |
+
$previous_products='';
|
53 |
+
}
|
54 |
+
else{
|
55 |
+
$previous_products=implode(",", Mage::registry('previous_products'));
|
56 |
+
}
|
57 |
+
// Call the web service to get recommended products
|
58 |
+
$ids = Mage::helper('recommend')->getRecommendations(
|
59 |
+
$product->getData('entity_id'),
|
60 |
+
implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds()),
|
61 |
+
$previous_products,
|
62 |
+
Mage::getSingleton('customer/session')->getCustomerId(),
|
63 |
+
"Upsell",
|
64 |
+
Mage::helper('recommend')->displayNumupsell()
|
65 |
+
);
|
66 |
+
//Mage::Log('Upsell');
|
67 |
+
//Mage::Log($ids);
|
68 |
+
if (!Mage::registry('previous_products')) {
|
69 |
+
Mage::register('previous_products', $ids);
|
70 |
+
}
|
71 |
+
|
72 |
+
$this->_itemCollection = Mage::getModel('catalog/product')->getCollection()
|
73 |
+
->addAttributeToFilter('entity_id', array(
|
74 |
+
'in' => $ids,
|
75 |
+
));
|
76 |
+
Mage::getResourceSingleton('checkout/cart')->addExcludeProductFilter($this->_itemCollection,
|
77 |
+
Mage::getSingleton('checkout/session')->getQuoteId()
|
78 |
+
);
|
79 |
+
$this->_addProductAttributesAndPrices($this->_itemCollection);
|
80 |
+
|
81 |
+
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($this->_itemCollection);
|
82 |
+
//arrange final collection
|
83 |
+
if(is_array($ids) && count($ids)>0){
|
84 |
+
$final_collection=Mage::getModel('catalog/product')->getCollection()->addAttributeToFilter('entity_id', -1);
|
85 |
+
foreach($ids as $id){
|
86 |
+
$item=Mage::getModel('catalog/product')->load($id);
|
87 |
+
if($item->getId()){
|
88 |
+
$final_collection->addItem($item);
|
89 |
+
Mage::log('upsell_item_id: '.$item->getId());
|
90 |
+
}
|
91 |
+
else{
|
92 |
+
Mage::Log('no upsell items found in db; id: '.$id);
|
93 |
+
}
|
94 |
+
}
|
95 |
+
$this->_itemCollection=$final_collection;
|
96 |
+
}
|
97 |
+
///arrange final collection
|
98 |
+
|
99 |
+
$this->_itemCollection->load();
|
100 |
+
$this->_items=$this->_itemCollection;
|
101 |
+
foreach ($this->_itemCollection as $product) {
|
102 |
+
$product->setDoNotUseCategoryId(true);
|
103 |
+
}
|
104 |
+
|
105 |
+
return $this;
|
106 |
+
}
|
107 |
+
/*
|
108 |
+
private function getCacheKeyInfo(){
|
109 |
+
|
110 |
+
}
|
111 |
+
*/
|
112 |
+
protected function _beforeToHtml() {
|
113 |
+
//$this->_prepareData();
|
114 |
+
return parent::_beforeToHtml();
|
115 |
+
}
|
116 |
+
|
117 |
+
public function getItems() {
|
118 |
+
if (true || is_null($this->_items)) {
|
119 |
+
$this->_items = $this->getItemCollection()->getItems();
|
120 |
+
}
|
121 |
+
return $this->_items;
|
122 |
+
}
|
123 |
+
|
124 |
+
public function hasItems() {
|
125 |
+
return true;
|
126 |
+
}
|
127 |
+
/*
|
128 |
+
public function getItemCollection() {
|
129 |
+
return $this->_itemCollection;
|
130 |
+
}
|
131 |
+
*/
|
132 |
+
}
|
app/code/community/FourTell/Recommend/Block/Checkout/Cart/Crosssell.php
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Used to override Mage_Checkout_Block_Cart_Crosssell
|
8 |
+
* Automatically replaces the functionality to get cross sell products
|
9 |
+
*
|
10 |
+
* @package FourTell_Recommend
|
11 |
+
* @copyright 4-Tell, Inc.
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
class FourTell_Recommend_Block_Checkout_Cart_Crosssell extends Mage_Checkout_Block_Cart_Crosssell {
|
15 |
+
|
16 |
+
const CACHE_LIFETIME=86400;
|
17 |
+
|
18 |
+
protected $_items = null;
|
19 |
+
|
20 |
+
public function __construct(){
|
21 |
+
$this->setRecommendationType('crosssell');
|
22 |
+
}
|
23 |
+
|
24 |
+
public function getCacheKeyInfo(){
|
25 |
+
$cacheInfo = parent::getCacheKeyInfo();
|
26 |
+
$cacheInfo[] = implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds());
|
27 |
+
$cacheInfo[] = Mage::getSingleton('customer/session')->getCustomerId();
|
28 |
+
$cacheInfo[] = "Crosssell";
|
29 |
+
$cacheInfo[] = Mage::helper('recommend')->displayNumcrosssell();
|
30 |
+
return $cacheInfo;
|
31 |
+
}
|
32 |
+
|
33 |
+
public function getItems(){
|
34 |
+
if (!$this->_items){
|
35 |
+
$items = array();
|
36 |
+
// If extension is not enabled use default functionality
|
37 |
+
if (!Mage::helper('recommend')->isEnabled()){
|
38 |
+
return parent::getItems();
|
39 |
+
}
|
40 |
+
// Get current product being viewed
|
41 |
+
$product = Mage::registry('product');
|
42 |
+
$productId='';
|
43 |
+
if($product){
|
44 |
+
$productId=$product->getData('entity_id');
|
45 |
+
}
|
46 |
+
// Call the web service to get recommended products
|
47 |
+
$ids = Mage::helper('recommend')->getRecommendations(
|
48 |
+
$productId,
|
49 |
+
implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds()),
|
50 |
+
"",
|
51 |
+
Mage::getSingleton('customer/session')->getCustomerId(),
|
52 |
+
"Crosssell",
|
53 |
+
Mage::helper('recommend')->displayNumcrosssell()
|
54 |
+
);
|
55 |
+
// Load each product and add to the collection
|
56 |
+
foreach ($ids as $id) {
|
57 |
+
$item=Mage::getModel('catalog/product')->load($id);
|
58 |
+
if($item->getId()){
|
59 |
+
$items[] = $item;
|
60 |
+
Mage::log('crosssell_item_id: '.$item->getId());
|
61 |
+
}
|
62 |
+
else{
|
63 |
+
Mage::Log('no crosssell items found in db; id: '.$id);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
$this->_items = $items;
|
67 |
+
}
|
68 |
+
return $this->_items;
|
69 |
+
}
|
70 |
+
}
|
app/code/community/FourTell/Recommend/Block/Checkout/Cart/Crosssellcommunity.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Used to override Mage_Checkout_Block_Cart_Crosssell
|
8 |
+
* Automatically replaces the functionality to get cross sell products
|
9 |
+
*
|
10 |
+
* @package FourTell_Recommend
|
11 |
+
* @copyright 4-Tell, Inc.
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
class FourTell_Recommend_Block_Checkout_Cart_Crosssellcommunity extends Mage_Checkout_Block_Cart_Crosssell {
|
15 |
+
|
16 |
+
const CACHE_LIFETIME=86400;
|
17 |
+
|
18 |
+
protected $_items = null;
|
19 |
+
|
20 |
+
/*
|
21 |
+
public function __construct(){
|
22 |
+
parent::__construct();
|
23 |
+
$this->setTemplate('fourtell/checkout/cart/crosssell.phtml');
|
24 |
+
}
|
25 |
+
*/
|
26 |
+
|
27 |
+
public function getCacheKeyInfo(){
|
28 |
+
$cacheInfo = parent::getCacheKeyInfo();
|
29 |
+
$cacheInfo[] = implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds());
|
30 |
+
$cacheInfo[] = Mage::getSingleton('customer/session')->getCustomerId();
|
31 |
+
$cacheInfo[] = "Crosssell";
|
32 |
+
$cacheInfo[] = Mage::helper('recommend')->displayNumcrosssell();
|
33 |
+
return $cacheInfo;
|
34 |
+
}
|
35 |
+
|
36 |
+
public function getItemCollection() {
|
37 |
+
return $this->getItems();
|
38 |
+
}
|
39 |
+
|
40 |
+
public function getItems() {
|
41 |
+
if (!$this->_items) {
|
42 |
+
$items = array();
|
43 |
+
|
44 |
+
// If extension is not enabled use default functionality
|
45 |
+
if (!Mage::helper('recommend')->isEnabled())
|
46 |
+
return parent::getItems();
|
47 |
+
|
48 |
+
// Get current product being viewed
|
49 |
+
$product = Mage::registry('product');
|
50 |
+
$productId='';
|
51 |
+
if($product){
|
52 |
+
$productId=$product->getData('entity_id');
|
53 |
+
}
|
54 |
+
// Call the web service to get recommended products
|
55 |
+
$ids = Mage::helper('recommend')->getRecommendations(
|
56 |
+
$productId,
|
57 |
+
implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds()),
|
58 |
+
"",
|
59 |
+
Mage::getSingleton('customer/session')->getCustomerId(),
|
60 |
+
"Crosssell",
|
61 |
+
Mage::helper('recommend')->displayNumcrosssell()
|
62 |
+
);
|
63 |
+
Mage::Log("CrosssellCommunity");
|
64 |
+
Mage::Log($ids);
|
65 |
+
// Load each product and add to the collection
|
66 |
+
foreach ($ids as $id) {
|
67 |
+
$items[] = Mage::getModel('catalog/product')->load($id);
|
68 |
+
}
|
69 |
+
$this->_items = $items;
|
70 |
+
return $this->_items;
|
71 |
+
}
|
72 |
+
return $this->_items;
|
73 |
+
}
|
74 |
+
|
75 |
+
}
|
app/code/community/FourTell/Recommend/Block/Checkout/Cart/Crosssellenterprise.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
*
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* Used to override Mage_Checkout_Block_Cart_Crosssell
|
7 |
+
* Automatically replaces the functionality to get cross sell products
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Block_Checkout_Cart_Crosssellenterprise extends Enterprise_TargetRule_Block_Checkout_Cart_Crosssell {
|
14 |
+
|
15 |
+
const CACHE_LIFETIME = 86400;
|
16 |
+
|
17 |
+
protected $_items = null;
|
18 |
+
|
19 |
+
public function getCacheKeyInfo(){
|
20 |
+
$cacheInfo = parent::getCacheKeyInfo();
|
21 |
+
$cacheInfo[] = implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds());
|
22 |
+
$cacheInfo[] = Mage::getSingleton('customer/session')->getCustomerId();
|
23 |
+
$cacheInfo[] = "Crosssell";
|
24 |
+
$cacheInfo[] = Mage::helper('recommend')->displayNumcrosssell();
|
25 |
+
return $cacheInfo;
|
26 |
+
}
|
27 |
+
|
28 |
+
public function getItemCollection() {
|
29 |
+
return $this->getItems();
|
30 |
+
}
|
31 |
+
|
32 |
+
public function getItems() {
|
33 |
+
if (!$this->_items) {
|
34 |
+
$items = array();
|
35 |
+
// If extension is not enabled use default functionality
|
36 |
+
if (!Mage::helper('recommend')->isEnabled())
|
37 |
+
return parent::getItems();
|
38 |
+
|
39 |
+
// Get current product being viewed
|
40 |
+
$product = Mage::registry('product');
|
41 |
+
$productId='';
|
42 |
+
if($product){
|
43 |
+
$productId=$product->getData('entity_id');
|
44 |
+
}
|
45 |
+
// Call the web service to get recommended products
|
46 |
+
$ids = Mage::helper('recommend')->getRecommendations(
|
47 |
+
$productId,
|
48 |
+
implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds()),
|
49 |
+
"",
|
50 |
+
Mage::getSingleton('customer/session')->getCustomerId(),
|
51 |
+
"Crosssell",
|
52 |
+
Mage::helper('recommend')->displayNumcrosssell()
|
53 |
+
);
|
54 |
+
Mage::Log("CrosssellEnterprise");
|
55 |
+
Mage::Log($ids);
|
56 |
+
// Load each product and add to the collection
|
57 |
+
foreach ($ids as $id) {
|
58 |
+
$items[] = Mage::getModel('catalog/product')->load($id);
|
59 |
+
}
|
60 |
+
$this->_items = $items;
|
61 |
+
}
|
62 |
+
return $this->_items;
|
63 |
+
}
|
64 |
+
|
65 |
+
}
|
app/code/community/FourTell/Recommend/Block/System/Config/Form/Field/Upload.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Create a link in system config to the 4-Tell site
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Block_System_Config_Form_Field_Upload extends Mage_Adminhtml_Block_System_Config_Form_Field {
|
14 |
+
|
15 |
+
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) {
|
16 |
+
return "<a href='" . Mage::helper('adminhtml')->getUrl("recommend/adminhtml_uploadform/index/") . "'>".Mage::helper('recommend')->__('Upload Settings and Upload Data')."</a>";
|
17 |
+
}
|
18 |
+
|
19 |
+
}
|
app/code/community/FourTell/Recommend/Block/System/Config/Google/Analytics/Change.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class FourTell_Recommend_Block_System_Config_Google_Analytics_Change extends Mage_Adminhtml_Block_System_Config_Form_Field
|
4 |
+
{
|
5 |
+
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) {
|
6 |
+
return "<a href='" . Mage::helper('adminhtml')->getUrl("adminhtml/system_config/edit/section/google/") . "'>".Mage::helper('recommend')->__('Change')."</a>";
|
7 |
+
}
|
8 |
+
}
|
app/code/community/FourTell/Recommend/Block/System/Config/Google/Analytics/Code.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class FourTell_Recommend_Block_System_Config_Google_Analytics_Code extends Mage_Adminhtml_Block_System_Config_Form_Field
|
4 |
+
{
|
5 |
+
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) {
|
6 |
+
//return "<a href='" . Mage::helper('adminhtml')->getUrl("recommend/adminhtml_uploadform/index/") . "'>".Mage::helper('recommend')->__('Upload Settings and Upload Data')."</a>";
|
7 |
+
//return "Yes";
|
8 |
+
return Mage::getStoreConfig('google/analytics/account');
|
9 |
+
}
|
10 |
+
}
|
app/code/community/FourTell/Recommend/Block/System/Config/Google/Analytics/Status.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class FourTell_Recommend_Block_System_Config_Google_Analytics_Status extends Mage_Adminhtml_Block_System_Config_Form_Field
|
4 |
+
{
|
5 |
+
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) {
|
6 |
+
if(Mage::getStoreConfig('google/analytics/active', null)){
|
7 |
+
return "Yes";
|
8 |
+
}
|
9 |
+
else{
|
10 |
+
return "No";
|
11 |
+
}
|
12 |
+
}
|
13 |
+
}
|
app/code/community/FourTell/Recommend/Block/Widget.php
ADDED
@@ -0,0 +1,366 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*/
|
9 |
+
class FourTell_Recommend_Block_Widget extends Mage_Core_Block_Abstract implements Mage_Widget_Block_Interface {
|
10 |
+
|
11 |
+
protected function _toHtml() {
|
12 |
+
// If extension is not enabled then return
|
13 |
+
if (Mage::getStoreConfig('recommend/config/enabled') != "1")
|
14 |
+
return '';
|
15 |
+
|
16 |
+
$maxProducts = 20;
|
17 |
+
//for js scroller
|
18 |
+
if($this->getData('in_line')){
|
19 |
+
$in_row=$this->getData('in_line');
|
20 |
+
}
|
21 |
+
else{
|
22 |
+
$in_row=3;
|
23 |
+
}
|
24 |
+
|
25 |
+
// Get the current product being viewed from the registry
|
26 |
+
$product = Mage::registry('product');
|
27 |
+
|
28 |
+
$pId = "";
|
29 |
+
if($product){
|
30 |
+
try {
|
31 |
+
$pId = $product->getData('entity_id');
|
32 |
+
} catch (Exception $e) {
|
33 |
+
|
34 |
+
}
|
35 |
+
}
|
36 |
+
$cartIds = implode(",", Mage::helper('checkout/cart')->getCart()->getProductIds());
|
37 |
+
|
38 |
+
$page = "Unknown";
|
39 |
+
|
40 |
+
// Check for search results page
|
41 |
+
if (strtolower(Mage::app()->getRequest()->getRouteName()) == "catalogsearch") {
|
42 |
+
// Get the product currently being viewed, this might not be all
|
43 |
+
// products, it could be the products of the current page
|
44 |
+
$sp = Mage::registry('current_layer')->getProductCollection();
|
45 |
+
|
46 |
+
// Get up to the first 5 products to send to the 4-Tell service
|
47 |
+
$result = array();
|
48 |
+
foreach ($sp as $p) {
|
49 |
+
if (count($result) < $maxProducts) {
|
50 |
+
$result[] = $p->getId();
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
$param1 = implode(",", $result);
|
55 |
+
$param2 = $cartIds;
|
56 |
+
$page = "Search";
|
57 |
+
|
58 |
+
// Check for category pages
|
59 |
+
} else if (strtolower(Mage::app()->getRequest()->getRouteName()) == "catalog") {
|
60 |
+
// Get the product currently being viewed, this might not be all
|
61 |
+
// products, it could be the products of the current page
|
62 |
+
$currentCategory = Mage::registry('current_category');
|
63 |
+
if (is_object($product)) {
|
64 |
+
|
65 |
+
$param1 = $pId;
|
66 |
+
$param2 = $cartIds;
|
67 |
+
$page = "Product";
|
68 |
+
} else if (is_object($currentCategory)) {
|
69 |
+
$collection = $currentCategory->getProductCollection();
|
70 |
+
|
71 |
+
// Get up to the first 5 products to send to the 4-Tell service
|
72 |
+
$result = array();
|
73 |
+
foreach ($collection as $product) {
|
74 |
+
if (count($result) < $maxProducts) {
|
75 |
+
$result[] = $product->getId();
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
$param1 = implode(",", $result);
|
80 |
+
$param2 = $cartIds;
|
81 |
+
$page = "Category";
|
82 |
+
} else {
|
83 |
+
$param1 = "";
|
84 |
+
$param2 = $cartIds;
|
85 |
+
}
|
86 |
+
|
87 |
+
// Check for checkout pages
|
88 |
+
} else if (strtolower(Mage::app()->getRequest()->getRouteName()) != "checkout") {
|
89 |
+
|
90 |
+
$param1 = $cartIds;
|
91 |
+
$param2 = "";
|
92 |
+
$page = "Checkout";
|
93 |
+
|
94 |
+
// Default is a product page
|
95 |
+
} else {
|
96 |
+
|
97 |
+
$param1 = $pId;
|
98 |
+
$param2 = $cartIds;
|
99 |
+
$page = "Product";
|
100 |
+
}
|
101 |
+
|
102 |
+
$ids = Mage::helper('recommend')->getRecommendations(
|
103 |
+
$param1,
|
104 |
+
$param2,
|
105 |
+
"",
|
106 |
+
Mage::getSingleton('customer/session')->getCustomerId(),
|
107 |
+
$this->getData('recommendation_type'),
|
108 |
+
$this->getData('num_recommendations')
|
109 |
+
);
|
110 |
+
|
111 |
+
if (!is_array($ids) || empty($ids)) {
|
112 |
+
return "";
|
113 |
+
}
|
114 |
+
|
115 |
+
// Load each product that came from 4-Tell and add to array
|
116 |
+
$collection = array();
|
117 |
+
foreach ($ids as $id) {
|
118 |
+
$_product = Mage::getModel('catalog/product')->load($id);
|
119 |
+
// Check if this product exists
|
120 |
+
if( $_product->getId() ) {
|
121 |
+
$collection[] = $_product;
|
122 |
+
}
|
123 |
+
}
|
124 |
+
|
125 |
+
// Default 4-Tell CSS styles, the name of this
|
126 |
+
// class can be overridden in the widget options
|
127 |
+
$str = "
|
128 |
+
<style>
|
129 |
+
.fourtell_widget {
|
130 |
+
clear: both;
|
131 |
+
width: ".((147*$in_row)+(($this->getData('slider_enable')==1) ? 102 : ''))."px !important;/*690px*//*470px*//*542*/
|
132 |
+
height: 211px;
|
133 |
+
border: 1px solid #E4E0D5;
|
134 |
+
}
|
135 |
+
|
136 |
+
.fourtell_widget .best-selling {
|
137 |
+
padding-left: 5px;
|
138 |
+
}
|
139 |
+
|
140 |
+
.fourtell_widget .widget_product {
|
141 |
+
float: left;
|
142 |
+
clear: none;
|
143 |
+
width: 135px;
|
144 |
+
height: 195px;
|
145 |
+
padding: 10px 5px 0 5px;
|
146 |
+
border: 1px solid #E5DCC3;
|
147 |
+
background: #ffffff;
|
148 |
+
}
|
149 |
+
|
150 |
+
.fourtell_widget .widget_product a {
|
151 |
+
margin-left: 0px;
|
152 |
+
border-color: #E5DCC3;
|
153 |
+
color: #1E7EC8;
|
154 |
+
text-decoration: underline;
|
155 |
+
}
|
156 |
+
|
157 |
+
.fourtell_widget .widget_product a img {
|
158 |
+
padding: 10px;
|
159 |
+
margin-bottom: 10px;
|
160 |
+
border: 0px solid #E5DCC3;
|
161 |
+
height: 75px;
|
162 |
+
width: 75px;
|
163 |
+
background-color: #ffffff;
|
164 |
+
}
|
165 |
+
|
166 |
+
.fourtell_widget .widget_product h3 {
|
167 |
+
height: 50px;
|
168 |
+
overflow: hidden;
|
169 |
+
}
|
170 |
+
|
171 |
+
.fourtell_widget .widget_product h3 a {
|
172 |
+
color: #0A263C;
|
173 |
+
font-weight: bold;
|
174 |
+
font-size: 12px;
|
175 |
+
}
|
176 |
+
|
177 |
+
.fourtell_widget .powered_by {
|
178 |
+
float: left;
|
179 |
+
clear: both;
|
180 |
+
font-size: smaller;
|
181 |
+
}
|
182 |
+
|
183 |
+
.fourtell_widget .widget_product .powered_by a {
|
184 |
+
color: #000000;
|
185 |
+
}
|
186 |
+
|
187 |
+
|
188 |
+
/*
|
189 |
+
root element for the scrollable.
|
190 |
+
when scrolling occurs this element stays still.
|
191 |
+
*/
|
192 |
+
.scrollable {
|
193 |
+
|
194 |
+
/* required settings */
|
195 |
+
position:relative;
|
196 |
+
overflow:hidden;
|
197 |
+
width: ".(147*$in_row)."px;/*588*/
|
198 |
+
height:210px;
|
199 |
+
}
|
200 |
+
|
201 |
+
/*
|
202 |
+
root element for scrollable items. Must be absolutely positioned
|
203 |
+
and it should have a extremely large width to accommodate scrollable items.
|
204 |
+
it's enough that you set width and height for the root element and
|
205 |
+
not for this element.
|
206 |
+
*/
|
207 |
+
.scrollable .items {
|
208 |
+
/* this cannot be too large */
|
209 |
+
width:20000em;
|
210 |
+
position:absolute;
|
211 |
+
}
|
212 |
+
.scrollable .items div{
|
213 |
+
margin-top:1px;
|
214 |
+
}
|
215 |
+
/*
|
216 |
+
a single item. must be floated in horizontal scrolling.
|
217 |
+
typically, this element is the one that *you* will style
|
218 |
+
the most.
|
219 |
+
*/
|
220 |
+
.items div {
|
221 |
+
float:left;
|
222 |
+
}
|
223 |
+
|
224 |
+
/* this makes it possible to add next button beside scrollable */
|
225 |
+
.scrollable {
|
226 |
+
float:left;
|
227 |
+
}
|
228 |
+
|
229 |
+
/* prev, next, prevPage and nextPage buttons */
|
230 |
+
a.browse {
|
231 |
+
background:url(".'/skin/frontend/base/default/images/hori_large.png'.") no-repeat;
|
232 |
+
display:block;
|
233 |
+
width:30px;
|
234 |
+
height:30px;
|
235 |
+
float:left;
|
236 |
+
margin:40px 10px;
|
237 |
+
cursor:pointer;
|
238 |
+
font-size:1px;
|
239 |
+
}
|
240 |
+
|
241 |
+
/* right */
|
242 |
+
a.right { background-position: 0 -30px; clear:right; margin-right: 10px; margin-top: 80px;}
|
243 |
+
a.right:hover { background-position:-30px -30px; }
|
244 |
+
a.right:active { background-position:-60px -30px; }
|
245 |
+
|
246 |
+
|
247 |
+
/* left */
|
248 |
+
a.left { margin-left: 10px; margin-top: 80px;}
|
249 |
+
a.left:hover { background-position:-30px 0; }
|
250 |
+
a.left:active { background-position:-60px 0; }
|
251 |
+
|
252 |
+
/* up and down */
|
253 |
+
a.up, a.down {
|
254 |
+
background:url(../img/scrollable/arrow/vert_large.png) no-repeat;
|
255 |
+
float: none;
|
256 |
+
margin: 10px 50px;
|
257 |
+
}
|
258 |
+
|
259 |
+
/* up */
|
260 |
+
a.up:hover { background-position:-30px 0; }
|
261 |
+
a.up:active { background-position:-60px 0; }
|
262 |
+
|
263 |
+
/* down */
|
264 |
+
a.down { background-position: 0 -30px; }
|
265 |
+
a.down:hover { background-position:-30px -30px; }
|
266 |
+
a.down:active { background-position:-60px -30px; }
|
267 |
+
|
268 |
+
|
269 |
+
/* disabled navigational button */
|
270 |
+
a.disabled {
|
271 |
+
visibility:hidden !important;
|
272 |
+
}
|
273 |
+
</style>";
|
274 |
+
|
275 |
+
//$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"http://static.flowplayer.org/tools/css/scrollable-horizontal.css\" />";
|
276 |
+
/*$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"http://static.flowplayer.org/tools/css/scrollable-buttons.css\" />";*/
|
277 |
+
|
278 |
+
/*$str.="<script src=\"http://cdn.jquerytools.org/1.2.6/jquery.tools.min.js\"></script>";*/
|
279 |
+
/*$str.="<script>jQuery.noConflict();</script>";*/
|
280 |
+
|
281 |
+
// Check to see if the CSS class was overridden
|
282 |
+
$css_class = "fourtell_widget";
|
283 |
+
if ($this->getData('cssclass') != "")
|
284 |
+
$css_class = $this->getData('cssclass');
|
285 |
+
|
286 |
+
// Generate recommended products html
|
287 |
+
$str .= '<div class="' . $css_class . '">';
|
288 |
+
|
289 |
+
if ($this->getData('heading') != "") {
|
290 |
+
$str .= '<h3 class="best-selling">';
|
291 |
+
$str .= $this->getData('heading');
|
292 |
+
$str .= '</h3>';
|
293 |
+
}
|
294 |
+
|
295 |
+
// Get Google Account ID for events tracking
|
296 |
+
$gaUA = Mage::helper('recommend')->getGoogleAccountId();
|
297 |
+
// Get toutType
|
298 |
+
$toutType = $this->getRecommendationType();
|
299 |
+
|
300 |
+
// Agg Google Tracking JS into this div
|
301 |
+
if( strlen($gaUA) > 0 ) {
|
302 |
+
$str .= '<script type="text/javascript">'
|
303 |
+
.'//<![CDATA['
|
304 |
+
.'(function() {'
|
305 |
+
.' var ga = document.createElement(\'script\'); ga.type = \'text/javascript\'; ga.async = true;'
|
306 |
+
.' ga.src = (\'https:\' == document.location.protocol ? \'https://ssl\' : \'http://www\') + \'.google-analytics.com/ga.js\';'
|
307 |
+
.' (document.getElementsByTagName(\'head\')[0] || document.getElementsByTagName(\'body\')[0]).appendChild(ga);'
|
308 |
+
.'})();'
|
309 |
+
.' var _gaq = _gaq || [];'
|
310 |
+
.' _gaq.push([\'_setAccount\', \''.$gaUA.'\']);'
|
311 |
+
.'//]]>'
|
312 |
+
.'</script>';
|
313 |
+
}
|
314 |
+
if($this->getData('slider_enable')==1){
|
315 |
+
$str.="<!-- \"previous page\" action -->";
|
316 |
+
$str.="<a class=\"prev browse left\"></a>";
|
317 |
+
}
|
318 |
+
$str.="<!-- root element for scrollable -->";
|
319 |
+
$str.="<div class=\"scrollable\">";
|
320 |
+
|
321 |
+
$str.="<!-- root element for the items -->";
|
322 |
+
$str.="<div class=\"items\">";
|
323 |
+
|
324 |
+
$str.="<div>";
|
325 |
+
|
326 |
+
foreach ($collection as $counter=>$product) {
|
327 |
+
|
328 |
+
$gafunction = '';
|
329 |
+
//build onclick handler
|
330 |
+
if( strlen($gaUA) > 0 ) {
|
331 |
+
$gafunction='onclick="_gaq.push([\'_trackEvent\', \'4TellRecs\', \''.$toutType.'\', \''.$product->getEntityId().'\']);"';
|
332 |
+
}
|
333 |
+
if($counter%$in_row==0 && $counter>0){
|
334 |
+
$str.="</div><div>";
|
335 |
+
}
|
336 |
+
$str .= '<div class="widget_product">';
|
337 |
+
$str .= '<a ' . $gafunction . ' href="'.Mage::getUrl('').'' . $product->getUrlPath() . '">'.'<img src="'.$product->getThumbnailUrl().'">'.'</a>';
|
338 |
+
$str .= '<br />'.'<h3 class="product-name">'.'<a '.$gafunction.' href="'.Mage::getUrl('').$product->getUrlPath().'">'.$product->getData("name").'</a>'.'</h3>';
|
339 |
+
$str .= '<div class="price-box">'.'<span class="regular-price">'.'<span class="price">'.Mage::helper('core')->currency($product->getData("price")).'</span>'.'</span>'.'</div>';
|
340 |
+
$str .= '</div>';
|
341 |
+
}
|
342 |
+
|
343 |
+
$str.="</div>";
|
344 |
+
|
345 |
+
$str.="</div>";
|
346 |
+
$str.="</div>";
|
347 |
+
if($this->getData('slider_enable')==1){
|
348 |
+
$str.="<!-- \"next page\" action -->";
|
349 |
+
$str.="<a class=\"next browse right\"></a>";
|
350 |
+
}
|
351 |
+
$str .= '<div class="powered_by">';
|
352 |
+
$str .= '<a href="http://www.4-tell.com" target="_blank">Powered by 4-Tell</a>';
|
353 |
+
$str .= '</div>';
|
354 |
+
$str .= '</div>';
|
355 |
+
if($this->getData('slider_enable')==1){
|
356 |
+
$str.="<script>";
|
357 |
+
$str.="jQuery(function() {";
|
358 |
+
$str.="jQuery(\".scrollable\").scrollable();";
|
359 |
+
$str.="});";
|
360 |
+
$str.="</script>";
|
361 |
+
}
|
362 |
+
// Return the html string
|
363 |
+
return $str;
|
364 |
+
}
|
365 |
+
|
366 |
+
}
|
app/code/community/FourTell/Recommend/Helper/Data.php
ADDED
@@ -0,0 +1,293 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Helper_Data extends Mage_Core_Helper_Abstract {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Get the Client ID from the system configuration
|
14 |
+
*/
|
15 |
+
public function getClientId() {
|
16 |
+
return Mage::getStoreConfig('recommend/config/client_id');
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Get mode (live or test)
|
21 |
+
*/
|
22 |
+
public function getMode() {
|
23 |
+
if (Mage::getStoreConfig('recommend/config/mode') == "Test") {
|
24 |
+
return "biz";
|
25 |
+
}
|
26 |
+
|
27 |
+
return "net";
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Convert type string to type id
|
32 |
+
*
|
33 |
+
* @param type string name of the type
|
34 |
+
*
|
35 |
+
* @return int id of the type
|
36 |
+
*/
|
37 |
+
public function getTypeId($type) {
|
38 |
+
switch (strtolower($type)) {
|
39 |
+
case "upsell":
|
40 |
+
return 3;
|
41 |
+
break;
|
42 |
+
|
43 |
+
case "related":
|
44 |
+
return 0;
|
45 |
+
break;
|
46 |
+
|
47 |
+
case "crosssell":
|
48 |
+
return 0;
|
49 |
+
break;
|
50 |
+
|
51 |
+
case "topsellers":
|
52 |
+
return 4;
|
53 |
+
break;
|
54 |
+
|
55 |
+
case "personalized":
|
56 |
+
return 1;
|
57 |
+
break;
|
58 |
+
|
59 |
+
default:
|
60 |
+
return 3;
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Get the Google Account ID from the system configuration
|
66 |
+
*/
|
67 |
+
public function getGoogleAccountId() {
|
68 |
+
return Mage::getStoreConfig('google/analytics/account');
|
69 |
+
}
|
70 |
+
|
71 |
+
public function getGoogleAccountEnabled() {
|
72 |
+
return Mage::getStoreConfig('google/analytics/active');
|
73 |
+
}
|
74 |
+
|
75 |
+
function recommendTypeStringToId($type) {
|
76 |
+
switch (strtolower($type)) {
|
77 |
+
case 'cross sell':
|
78 |
+
return 0;
|
79 |
+
break;
|
80 |
+
|
81 |
+
case 'related':
|
82 |
+
return 1;
|
83 |
+
break;
|
84 |
+
|
85 |
+
case 'upsell':
|
86 |
+
return 2;
|
87 |
+
break;
|
88 |
+
|
89 |
+
case 'similar':
|
90 |
+
return 3;
|
91 |
+
break;
|
92 |
+
|
93 |
+
case 'top sellers':
|
94 |
+
return 4;
|
95 |
+
break;
|
96 |
+
}
|
97 |
+
|
98 |
+
return 1;
|
99 |
+
}
|
100 |
+
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Convert type string to type id
|
104 |
+
*
|
105 |
+
* @param productIds
|
106 |
+
* @param cartIds
|
107 |
+
* @param customerId
|
108 |
+
* @param type
|
109 |
+
* @param numResults
|
110 |
+
*
|
111 |
+
* @return array recommended products
|
112 |
+
*/
|
113 |
+
function getRecommendations($productIds, $cartIds, $blockIds, $customerId, $type, $numResults) {
|
114 |
+
//Mage::Log('111');
|
115 |
+
try {
|
116 |
+
$mode = $this->getMode();
|
117 |
+
$clientId = $this->getClientId();
|
118 |
+
$typeId = $this->getTypeId($type);
|
119 |
+
|
120 |
+
$service_url = "http://www.4-tell." . $mode .
|
121 |
+
"/Boost2.0/rest/GetRecIDs/string" .
|
122 |
+
"?clientAlias=" . $clientId .
|
123 |
+
"&productIDs=" . $productIds .
|
124 |
+
"&cartIDs=" . $cartIds .
|
125 |
+
"&blockIDs=" . $blockIds .
|
126 |
+
"&customerId=" . $customerId .
|
127 |
+
"&numResults=" . $numResults .
|
128 |
+
"&resultType=" . $typeId .
|
129 |
+
"&format=CommaDelimited";
|
130 |
+
Mage::Log($service_url);
|
131 |
+
$curl = curl_init($service_url);
|
132 |
+
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
133 |
+
$curl_response = curl_exec($curl);
|
134 |
+
$info = curl_getinfo($curl);
|
135 |
+
curl_close($curl);
|
136 |
+
|
137 |
+
if ($curl_response === false || $info['http_code'] != 200) {
|
138 |
+
return array();
|
139 |
+
}
|
140 |
+
|
141 |
+
$IDs = str_ireplace('<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">', '', $curl_response);
|
142 |
+
$IDs = str_ireplace('</string>', '', $IDs);
|
143 |
+
$IDs = str_ireplace(' ', '', $IDs);
|
144 |
+
|
145 |
+
return explode(",", $IDs);
|
146 |
+
} catch (Exception $e) {
|
147 |
+
return array();
|
148 |
+
}
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Get and format CfgLink
|
153 |
+
*
|
154 |
+
* @return string $cfgLink;
|
155 |
+
*/
|
156 |
+
public function getCfgLink() {
|
157 |
+
$cfgLink = Mage::helper("adminhtml")->getUrl("admin/system_config/edit/section/recommend");
|
158 |
+
$cfgLink = str_replace("//system", "/admin/system", $cfgLink);
|
159 |
+
|
160 |
+
return $cfgLink;
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Initialize and return Comps array
|
165 |
+
*
|
166 |
+
* @return array
|
167 |
+
*/
|
168 |
+
public function getCompsArray() {
|
169 |
+
return array(
|
170 |
+
'eq' => 'Equal To',
|
171 |
+
'neq' => 'Not Equal To',
|
172 |
+
'lt' => 'Less Than',
|
173 |
+
'lteq' => 'Less Than or Equal To',
|
174 |
+
'gt' => 'Greater Than',
|
175 |
+
'gteq' => 'Greater Than or Equal To',
|
176 |
+
'like' => 'Contains',
|
177 |
+
'nlike' => 'Does Not Contain',
|
178 |
+
'null' => 'Is Null',
|
179 |
+
'notnull' => 'Is Not Null',
|
180 |
+
'in' => 'In',
|
181 |
+
'nin' => 'Not In'
|
182 |
+
);
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Initialize and return Options array
|
187 |
+
*
|
188 |
+
* @return array
|
189 |
+
*/
|
190 |
+
public function getOptionsArray() {
|
191 |
+
return array(
|
192 |
+
'upload_sales_data' => 'Upload Sales Data',
|
193 |
+
'upload_product_data' => 'Upload Product Data',
|
194 |
+
'upload_replacement_data' => 'Upload Replacement Data',
|
195 |
+
'upload_exclusion_data' => 'Upload Exclusion Data'
|
196 |
+
);
|
197 |
+
}
|
198 |
+
|
199 |
+
public function getNextUploadDate($sf = null) {
|
200 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
201 |
+
$ret = 0;
|
202 |
+
$keys = array_keys($model->salesFiles);
|
203 |
+
|
204 |
+
$getNext = 0;
|
205 |
+
if ($sf == null) {
|
206 |
+
$getNext = 1;
|
207 |
+
}
|
208 |
+
|
209 |
+
foreach ($keys as $idx => $key) {
|
210 |
+
if ($getNext == 1) {
|
211 |
+
return $key;
|
212 |
+
}
|
213 |
+
|
214 |
+
if ($sf === $key) {
|
215 |
+
$getNext = 1;
|
216 |
+
}
|
217 |
+
}
|
218 |
+
return null;
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Compare types $a and $b
|
223 |
+
*
|
224 |
+
* @param array $a
|
225 |
+
* @param array $b
|
226 |
+
* @return numeric
|
227 |
+
*/
|
228 |
+
private function compare_type($a, $b) {
|
229 |
+
return strnatcmp($a['name'], $b['name']);
|
230 |
+
}
|
231 |
+
|
232 |
+
public function isEnabled() {
|
233 |
+
if(Mage::getStoreConfig('recommend/config/enabled') != "1") return false;
|
234 |
+
return true;
|
235 |
+
}
|
236 |
+
|
237 |
+
public function isDisplayRelatedEnabled() {
|
238 |
+
if(Mage::getStoreConfig('recommend/display_recommendation/related') != "1") return false;
|
239 |
+
return true;
|
240 |
+
}
|
241 |
+
|
242 |
+
public function isDisplayUpsellEnabled() {
|
243 |
+
if(Mage::getStoreConfig('recommend/display_recommendation/upsell') != "1") return false;
|
244 |
+
return true;
|
245 |
+
}
|
246 |
+
|
247 |
+
public function displayNumrelatedEnabled() {
|
248 |
+
return Mage::getStoreConfig('recommend/display_recommendation/numrelated');
|
249 |
+
}
|
250 |
+
|
251 |
+
public function displayNumupsell() {
|
252 |
+
return Mage::getStoreConfig('recommend/display_recommendation/numupsell');
|
253 |
+
}
|
254 |
+
|
255 |
+
public function displayNumcrosssell() {
|
256 |
+
return Mage::getStoreConfig('recommend/display_recommendation/numcrosssell');
|
257 |
+
}
|
258 |
+
|
259 |
+
/*
|
260 |
+
* for debugging
|
261 |
+
*/
|
262 |
+
public function draw($txt){
|
263 |
+
ob_start();
|
264 |
+
print_r($txt);
|
265 |
+
$result=ob_get_contents();
|
266 |
+
ob_end_clean();
|
267 |
+
file_put_contents('d:/temp/php/result_'.microtime().'.txt', $result);
|
268 |
+
}
|
269 |
+
|
270 |
+
public function writeLastUploaded($last_data=false){
|
271 |
+
if(!is_dir(Mage::getBaseDir('media').DS.'tmp')){
|
272 |
+
mkdir(Mage::getBaseDir('media').DS.'tmp', 0777);
|
273 |
+
}
|
274 |
+
if(!$last_data) return false;
|
275 |
+
$data=serialize($last_data);
|
276 |
+
return file_put_contents(Mage::getBaseDir('media').DS.'tmp/last_uploaded.txt', $data);
|
277 |
+
}
|
278 |
+
|
279 |
+
public function getLastUploaded(){
|
280 |
+
if(!is_dir(Mage::getBaseDir('media').DS.'tmp')){
|
281 |
+
mkdir(Mage::getBaseDir('media').DS.'tmp', 0777);
|
282 |
+
return false;
|
283 |
+
}
|
284 |
+
if(file_exists(Mage::getBaseDir('media').DS.'tmp/last_uploaded.txt')){
|
285 |
+
$result=file_get_contents(Mage::getBaseDir('media').DS.'tmp/last_uploaded.txt');
|
286 |
+
if(strlen($result)>0){
|
287 |
+
return unserialize($result);
|
288 |
+
}
|
289 |
+
}
|
290 |
+
return false;
|
291 |
+
}
|
292 |
+
|
293 |
+
}
|
app/code/community/FourTell/Recommend/Model/Adminhtml/Uploadform.php
ADDED
@@ -0,0 +1,403 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class FourTell_Recommend_Model_Adminhtml_Uploadform extends Varien_Object
|
3 |
+
{
|
4 |
+
public $salesFiles = null;
|
5 |
+
|
6 |
+
protected function _construct(){
|
7 |
+
$this->getUploadSettings();
|
8 |
+
}
|
9 |
+
|
10 |
+
public function getUploadSettings() {
|
11 |
+
if (!$this->options) {
|
12 |
+
$this->options = Mage::getSingleton('FourTell_Recommend_Model_UploadSetting');
|
13 |
+
}
|
14 |
+
if (!is_object($this->options)) {
|
15 |
+
throw new Exception("Unable to get singleton: FourTell_Recommend_Model_UploadSetting");
|
16 |
+
}
|
17 |
+
|
18 |
+
$this->options->load();
|
19 |
+
return $this->options;
|
20 |
+
}
|
21 |
+
|
22 |
+
public function processData()
|
23 |
+
{
|
24 |
+
$post=$this->getData('post_data');
|
25 |
+
|
26 |
+
if (!is_object($this->options)) {
|
27 |
+
throw new Exception("Unable to get singleton: FourTell_Recommend_Model_UploadSetting");
|
28 |
+
}
|
29 |
+
$this->options->save($post);
|
30 |
+
|
31 |
+
$message = Mage::helper('adminhtml')->__('Settings have been saved successfully');
|
32 |
+
Mage::getSingleton('core/session')->addSuccess($message);
|
33 |
+
|
34 |
+
if ($post['what_data'] == "upload_data") {
|
35 |
+
if (!$this->getEnabled()) {
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
if (strtolower($this->options->getSetting('upload_sales_data')) == "all") {
|
41 |
+
$result=$this->generateAllData(Mage::getStoreConfig('recommend/config/maxsalesdataageinmonths'));
|
42 |
+
} else {
|
43 |
+
$result=$this->generateAllData(1);
|
44 |
+
}
|
45 |
+
//return $result;
|
46 |
+
}
|
47 |
+
|
48 |
+
public function buildSalesFileNames()
|
49 |
+
{
|
50 |
+
$outStr = "";
|
51 |
+
if (strtolower($this->options->getSetting('upload_sales_data')) == "all") {
|
52 |
+
$numMonths = Mage::getStoreConfig('recommend/config/maxsalesdataageinmonths');
|
53 |
+
} else {
|
54 |
+
$numMonths = 1;
|
55 |
+
}
|
56 |
+
|
57 |
+
$outStr = "";
|
58 |
+
|
59 |
+
$newdate = date('Y-m-j');
|
60 |
+
$dp = explode('-', $newdate);
|
61 |
+
|
62 |
+
for ($cd = 0; $cd <= $numMonths + 1; $cd++) {
|
63 |
+
$dp = explode('-', $newdate);
|
64 |
+
|
65 |
+
$newdate = strtotime('-1 month', strtotime($newdate));
|
66 |
+
$newdate = date('Y-m-j', $newdate);
|
67 |
+
|
68 |
+
$fm = $dp[1];
|
69 |
+
$fy = $dp[0];
|
70 |
+
$fn = "sales_" . $fy . "-" . $fm . ".txt";
|
71 |
+
|
72 |
+
$this->salesFiles[$fy . "-" . $fm] = array(
|
73 |
+
'ym' => $fy . "-" . $fm,
|
74 |
+
'last' => ($cd == $numMonths) ? 1 : 0);
|
75 |
+
|
76 |
+
$outStr .= $fn . "\r\n";
|
77 |
+
}
|
78 |
+
|
79 |
+
return $outStr;
|
80 |
+
}
|
81 |
+
|
82 |
+
function generateAllData($howMany) {
|
83 |
+
//return $this;
|
84 |
+
require_once("FourTell/Recommend/controllers/Adminhtml/UploadformController.php");
|
85 |
+
//return $this;
|
86 |
+
$uploadModel=Mage::getSingleton('FourTell_Recommend_Adminhtml_UploadformController');
|
87 |
+
$uploadModel->__construct(Mage::app()->getRequest());
|
88 |
+
try {
|
89 |
+
$last=Mage::helper('recommend')->getLastUploaded();
|
90 |
+
//var_dump($this->options);
|
91 |
+
//exit;
|
92 |
+
$ups = $this->options->getSetting('upload_sales_data');
|
93 |
+
$upr = $this->options->getSetting('upload_replacement_data');
|
94 |
+
$upe = $this->options->getSetting('upload_exclusion_data');
|
95 |
+
$upp = $this->options->getSetting('upload_product_data');
|
96 |
+
|
97 |
+
$this->exportConfiguration();
|
98 |
+
|
99 |
+
$this->exportCategoryData();
|
100 |
+
|
101 |
+
if (strtolower($upr) != "none"){
|
102 |
+
$uploadModel->exportReplacementData();
|
103 |
+
}
|
104 |
+
|
105 |
+
if ($upe == "Yes"){
|
106 |
+
$uploadModel->exportExclusionData();
|
107 |
+
}
|
108 |
+
|
109 |
+
if ($upp == "Yes"){
|
110 |
+
if($last['last_config_catalog']+$last_config_catalog*3600<time()){
|
111 |
+
$this->exportProductData();
|
112 |
+
$last_data['last_config_catalog']=time();
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
if (strtolower($ups) != "none") {
|
117 |
+
if($last['last_config_sales']+$last_config_sales*3600<time()){
|
118 |
+
$this->exportSalesData();
|
119 |
+
$last_data['last_config_sales']=time();
|
120 |
+
}
|
121 |
+
} else {
|
122 |
+
$uploadModel->startGenerator();
|
123 |
+
}
|
124 |
+
//if something was uploaded, write time
|
125 |
+
if($last_data['last_config_catalog'] || $last_data['last_config_sales']){
|
126 |
+
Mage::helper('recommend')->writeLastUploaded($last_data);
|
127 |
+
}
|
128 |
+
|
129 |
+
} catch (Exception $e) {
|
130 |
+
//$this->processException($e, "generateAllData");
|
131 |
+
return $e;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
function exportProductData() {
|
136 |
+
$generate = "create";
|
137 |
+
|
138 |
+
try {
|
139 |
+
// Create file header
|
140 |
+
$today = date("m-d-Y");
|
141 |
+
$this->fileContents = $this->getClientId() . "\tProductDetails.txt\t" . $generate . "\r\nVersion\t2\t" . $today . "\r\nProduct ID\tName\tAtt1 ID\tAtt2 ID\tPrice\tFilter\tLink\tImage Link\tStandard Code\r\n";
|
142 |
+
|
143 |
+
// Get all products with just data needed
|
144 |
+
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect(array('sku', 'name', 'price', 'image', 'url_path', 'type_id'), 'inner')
|
145 |
+
->joinField('stock_status', 'cataloginventory/stock_status', 'stock_status', 'product_id=entity_id', array(
|
146 |
+
'stock_status' => Mage_CatalogInventory_Model_Stock_Status::STATUS_IN_STOCK,
|
147 |
+
//'website_id' => Mage::app()->getWebsite()->getWebsiteId(),
|
148 |
+
));
|
149 |
+
if (!is_object($products)) {
|
150 |
+
throw new Exception("Unable to get model: catalog/product collection");
|
151 |
+
}
|
152 |
+
|
153 |
+
// Use an iterator to loop through the collection
|
154 |
+
$iter = Mage::getSingleton('core/resource_iterator');
|
155 |
+
if (!is_object($iter)) {
|
156 |
+
throw new Exception("Unable to get singleton: core/resource_iterator");
|
157 |
+
}
|
158 |
+
|
159 |
+
$iter->walk($products->getSelect(), array(array($this, 'productDetailsCallback')), array('arg1' => '====['));
|
160 |
+
|
161 |
+
// Upload ProductDetails.txt contents to server
|
162 |
+
$this->exportFile("ProductDetails.txt", $this->fileContents, "create");
|
163 |
+
} catch (Exception $e) {
|
164 |
+
//$this->processException($e, "exportProductData");
|
165 |
+
return $e;
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
/**
|
170 |
+
*
|
171 |
+
* This is the call back function used in the product iterator
|
172 |
+
*
|
173 |
+
*/
|
174 |
+
function productDetailsCallback($args) {
|
175 |
+
try {
|
176 |
+
$product = Mage::getModel('catalog/product');
|
177 |
+
if (!is_object($product)) {
|
178 |
+
throw new Exception("Unable to get model: catalog/product");
|
179 |
+
}
|
180 |
+
$product->setData($args['row']);
|
181 |
+
|
182 |
+
$image = "";
|
183 |
+
|
184 |
+
$cat = implode(",", array_unique($product->getCategoryIds()));
|
185 |
+
|
186 |
+
//$productUrl = "";
|
187 |
+
$productUrl = $product->getProductUrl();
|
188 |
+
|
189 |
+
// Check to see if the product should be included
|
190 |
+
$incProduct = true;
|
191 |
+
//if ($product->type_id == "simple" || $product_type == "") {
|
192 |
+
if ($product->type_id == "simple" ) {
|
193 |
+
// Get product parent ids
|
194 |
+
$configurable_product_model = Mage::getModel('catalog/product_type_configurable');
|
195 |
+
if (!is_object($configurable_product_model)) {
|
196 |
+
throw new Exception("Unable to get model: catalog/product_type_configurable");
|
197 |
+
}
|
198 |
+
$parentIdArray = $configurable_product_model->getParentIdsByChild($product->getEntityId());
|
199 |
+
|
200 |
+
// Don't upload if it has parent ids
|
201 |
+
if (isset($parentIdArray[0])) {
|
202 |
+
$incProduct = false;
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
// Append product data to global variable: fileContents
|
207 |
+
if ($incProduct) {
|
208 |
+
if (!isset($parentIdArray[0])) {
|
209 |
+
$this->fileContents = $this->fileContents . $product->getEntityId() . "\t" . $product->getName() . "[$product->type_id]" . "\t" . $cat . "\t" . "" . "\t" . str_replace(",", "", number_format($product->getPrice(), 2)) . "\t" . "" . "\t" . $productUrl . "\t" . $image . "\t" . $product->getSku() . "\r\n";
|
210 |
+
}
|
211 |
+
}
|
212 |
+
} catch (Exception $e) {
|
213 |
+
$this->processException($e, "productDetailsCallback");
|
214 |
+
}
|
215 |
+
}
|
216 |
+
|
217 |
+
function exportConfiguration() {
|
218 |
+
$generate = "create";
|
219 |
+
|
220 |
+
try {
|
221 |
+
$today = date("m-d-Y");
|
222 |
+
|
223 |
+
if (strtolower($this->options->getSetting('upload_exclusion_data')) == "yes")
|
224 |
+
$upload_exclusion = 1;
|
225 |
+
else
|
226 |
+
$upload_exclusion = 0;
|
227 |
+
|
228 |
+
if (strtolower($this->options->getSetting('upload_replacement_data')) != "none")
|
229 |
+
$upload_replacement = 1;
|
230 |
+
else
|
231 |
+
$upload_replacement = 0;
|
232 |
+
$contents = $this->getClientId() . "\tConfigBoost.txt\t" . "create" . "\r\n" .
|
233 |
+
"Version\t" . "3" . "\r\n" .
|
234 |
+
"Owner\t" . Mage::getStoreConfig('recommend/config/owner') . "\r\n" .
|
235 |
+
"Email\t" . Mage::getStoreConfig('recommend/config/email') . "\r\n" .
|
236 |
+
"ReportLevel\t" . Mage::getStoreConfig('recommend/config/reportlevel') . "\r\n" .
|
237 |
+
"ExclusionsExist\t" . $upload_exclusion . "\r\n" .
|
238 |
+
"ReplacementsExist\t" . $upload_replacement . "\r\n" .
|
239 |
+
"MaxSalesDataAgeInMonths\t" . Mage::getStoreConfig('recommend/config/maxsalesdataageinmonths') . "\r\n";
|
240 |
+
// Upload ConfigBoost.txt contents to server
|
241 |
+
$this->exportFile("ConfigBoost.txt", $contents, "create");
|
242 |
+
} catch (Exception $e) {
|
243 |
+
//$this->processException($e, "exportConfiguration");
|
244 |
+
return $e;
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
function getClientId() {
|
249 |
+
return Mage::getStoreConfig('recommend/config/client_id');
|
250 |
+
}
|
251 |
+
|
252 |
+
private function draw($txt){
|
253 |
+
ob_start();
|
254 |
+
print_r($txt);
|
255 |
+
$result=ob_get_contents();
|
256 |
+
ob_end_clean();
|
257 |
+
if(!is_dir(Mage::getBaseDir('media').DS.'tmp')){
|
258 |
+
mkdir(Mage::getBaseDir('media').DS.'tmp', 0777);
|
259 |
+
}
|
260 |
+
file_put_contents(Mage::getBaseDir('media').DS.'tmp/'.date('Y_m_d_H_i_s').'.txt', $result);
|
261 |
+
}
|
262 |
+
|
263 |
+
function exportFile($fileName, $contents, $mode) {
|
264 |
+
//!!!
|
265 |
+
if (false && Mage::getStoreConfig('recommend/config/mode') == "Test" && $this->options->getSetting('showUploadDetails') == "Yes") {
|
266 |
+
try {
|
267 |
+
if ($mode == "create") {
|
268 |
+
$fmode = "w+";
|
269 |
+
} else {
|
270 |
+
$fmode = "a+";
|
271 |
+
}
|
272 |
+
if(!is_dir(Mage::getBaseDir('media').DS.'export')){
|
273 |
+
mkdir(Mage::getBaseDir('media').DS.'export', 0777);
|
274 |
+
}
|
275 |
+
$sf = fopen(Mage::getBaseDir('media').DS.'export'.DS.$fileName, $fmode);
|
276 |
+
if( $sf ) {
|
277 |
+
fwrite($sf, $contents, strlen($contents));
|
278 |
+
fclose($sf);
|
279 |
+
}
|
280 |
+
} catch (Exception $e) {
|
281 |
+
//$this->processException($e, "exportFile#1");
|
282 |
+
return $e;
|
283 |
+
}
|
284 |
+
}
|
285 |
+
|
286 |
+
try {
|
287 |
+
$mode = Mage::helper('recommend')->getMode();
|
288 |
+
|
289 |
+
// The request URL prefix
|
290 |
+
$request = "http://www.4-tell." . $mode . "/Boost2.0/rest/UploadData/stream";
|
291 |
+
|
292 |
+
$curl = curl_init($request);
|
293 |
+
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
294 |
+
curl_setopt($curl, CURLOPT_HEADER, 1);
|
295 |
+
curl_setopt($curl, CURLOPT_POST, 1);
|
296 |
+
curl_setopt($curl, CURLOPT_POSTFIELDS, $contents);
|
297 |
+
curl_setopt($curl, CURLOPT_VERBOSE, 0);
|
298 |
+
curl_setopt($curl, CURLINFO_HEADER_OUT, 0);
|
299 |
+
$response = curl_exec($curl);
|
300 |
+
$info = curl_getinfo($curl);
|
301 |
+
if(true){
|
302 |
+
$out='request:'."\r\n".$request."\r\n\r\n";
|
303 |
+
$out.='filename:'."\r\n".$fileName."\r\n\r\n";
|
304 |
+
$out.='contents:'."\r\n".$contents."\r\n\r\n";
|
305 |
+
$out.='response:'."\r\n".$response."\r\n\r\n";
|
306 |
+
$this->draw($out);
|
307 |
+
}
|
308 |
+
if ($response === false || $info['http_code'] != 200) {
|
309 |
+
throw new Exception(curl_error($curl));
|
310 |
+
}
|
311 |
+
curl_close($curl);
|
312 |
+
|
313 |
+
if (Mage::getStoreConfig('recommend/config/mode') == "Test" && $this->options->getSetting('showUploadDetails') == "Yes") {
|
314 |
+
//remove file after uploading
|
315 |
+
if(is_dir(Mage::getBaseDir('media').DS.'export') && file_exists(Mage::getBaseDir('media').DS.'export'.DS.$fileName)){
|
316 |
+
try{
|
317 |
+
//!!!unlink(Mage::getBaseDir('media').DS.'export'.DS.$fileName);
|
318 |
+
}
|
319 |
+
catch(Exception $e){
|
320 |
+
echo $e->getMessage();
|
321 |
+
}
|
322 |
+
}
|
323 |
+
Mage::getSingleton('core/session')->addWarning("Uploading data for: " . $fileName);
|
324 |
+
}
|
325 |
+
} catch (Exception $e) {
|
326 |
+
$this->processException($e, "exportFile#2");
|
327 |
+
}
|
328 |
+
}
|
329 |
+
|
330 |
+
/*
|
331 |
+
function getMode() {
|
332 |
+
try {
|
333 |
+
if (Mage::getStoreConfig('recommend/config/mode') == "Test") {
|
334 |
+
return "biz";
|
335 |
+
}
|
336 |
+
|
337 |
+
return "net";
|
338 |
+
} catch (Exception $e) {
|
339 |
+
//$this->processException($e, "getMode");
|
340 |
+
return $e;
|
341 |
+
}
|
342 |
+
}
|
343 |
+
*/
|
344 |
+
|
345 |
+
function exportCategoryData() {
|
346 |
+
$generate = "create";
|
347 |
+
|
348 |
+
try {
|
349 |
+
// Create file header
|
350 |
+
$today = date("m-d-Y");
|
351 |
+
$this->fileContents = $this->getClientId() . "\tAttribute1Names.txt\t" . $generate . "\r\nVersion\t2\t" . $today . "\r\nAttID\tName\r\n";
|
352 |
+
|
353 |
+
// Get all categories
|
354 |
+
$category = Mage::getModel('catalog/category');
|
355 |
+
if (!is_object($category)) {
|
356 |
+
throw new Exception("Unable to get model: catalog/category");
|
357 |
+
}
|
358 |
+
|
359 |
+
$collection = $category->getCollection();
|
360 |
+
if (!is_object($collection)) {
|
361 |
+
throw new Exception("Unable to get category collection");
|
362 |
+
}
|
363 |
+
|
364 |
+
$collection->addAttributeToSelect('*');
|
365 |
+
|
366 |
+
// Loop through all and add to file
|
367 |
+
foreach ($collection as $item) {
|
368 |
+
$this->fileContents = $this->fileContents . $item->getData('entity_id') . "\t" . $item->getData('name') . "\r\n";
|
369 |
+
}
|
370 |
+
|
371 |
+
// Upload Attribute1Names.txt contents to server
|
372 |
+
$this->exportFile("Attribute1Names.txt", $this->fileContents, "create");
|
373 |
+
} catch (Exception $e) {
|
374 |
+
//$this->processException($e, "exportCategoryData");
|
375 |
+
return $e;
|
376 |
+
}
|
377 |
+
}
|
378 |
+
|
379 |
+
function exportSalesData() {
|
380 |
+
try {
|
381 |
+
$newdate = date('Y-m-j');
|
382 |
+
|
383 |
+
// Generate next date string for filename
|
384 |
+
$dp = explode('-', $newdate);
|
385 |
+
$newdate = strtotime('-1 month', strtotime($newdate));
|
386 |
+
$newdate = date('Y-m-j', $newdate);
|
387 |
+
|
388 |
+
$fm = $dp[1];
|
389 |
+
$fy = $dp[0];
|
390 |
+
|
391 |
+
require_once("FourTell/Recommend/controllers/Adminhtml/UploadformController.php");
|
392 |
+
$uploadModel=Mage::getModel('FourTell_Recommend_Adminhtml_UploadformController');
|
393 |
+
$uploadModel->__construct(Mage::app()->getRequest());
|
394 |
+
$uploadModel->uploadYearMonthOrders($fy . "-" . $fm, 0);
|
395 |
+
} catch (Exception $e) {
|
396 |
+
//$this->processException($e, "exportSalesData");
|
397 |
+
return $e;
|
398 |
+
}
|
399 |
+
}
|
400 |
+
|
401 |
+
|
402 |
+
|
403 |
+
}
|
app/code/community/FourTell/Recommend/Model/DataProcess.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Process business logic
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
/*
|
14 |
+
class FourTell_Recommend_Model_Observer {
|
15 |
+
|
16 |
+
public function process($post) {
|
17 |
+
|
18 |
+
}
|
19 |
+
|
20 |
+
}
|
21 |
+
*/
|
22 |
+
?>
|
app/code/community/FourTell/Recommend/Model/Observer.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Test code for observing system events
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
|
14 |
+
class FourTell_Recommend_Model_Observer {
|
15 |
+
|
16 |
+
function uploadData($observer) {
|
17 |
+
|
18 |
+
$last_data=array();
|
19 |
+
// If extension is not enabled then return
|
20 |
+
if (!Mage::helper('recommend')->isEnabled()){
|
21 |
+
return;
|
22 |
+
}
|
23 |
+
//check when the last time process was started
|
24 |
+
$last=Mage::helper('recommend')->getLastUploaded();
|
25 |
+
if($last===false){
|
26 |
+
$last_data['last_config_sales']=time()-3600;
|
27 |
+
$last_data['last_config_catalog']=time()-3600;
|
28 |
+
Mage::helper('recommend')->writeLastUploaded($last_data);
|
29 |
+
}
|
30 |
+
$last_config_sales=Mage::getStoreConfig('recommend/cron_jobs/sales');
|
31 |
+
if(!$last_config_sales) $last_config_sales=1;
|
32 |
+
$last_config_catalog=Mage::getStoreConfig('recommend/cron_jobs/catalog');
|
33 |
+
if(!$last_config_catalog) $last_config_catalog=1;
|
34 |
+
|
35 |
+
if($last['last_config_sales']+$last_config_sales*3600<time() || $last['last_config_catalog']+$last_config_catalog*3600<time()){
|
36 |
+
//it's time to generate a new set of data
|
37 |
+
$processModel=Mage::getModel('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
38 |
+
$processModel->generateAllData(1);
|
39 |
+
//please note, 'generate all data' doesn't generate all files
|
40 |
+
//for some reasons pagination was denied for non-ajax requests
|
41 |
+
//see /app/code/community/FourTell/Recommend/controllers/Adminhtml/UploadformController.php, line 406
|
42 |
+
}
|
43 |
+
else{
|
44 |
+
//no changes needed
|
45 |
+
/*
|
46 |
+
echo ($last['last_config_sales']+$last_config_sales*3600-time());
|
47 |
+
echo '<br>';
|
48 |
+
echo ($last['last_config_catalog']+$last_config_catalog*3600-time());
|
49 |
+
echo '<br>';
|
50 |
+
*/
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Source/Crosssell.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Generate options for Report Level selectbox in system config
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Model_System_Config_Source_Crosssell {
|
14 |
+
|
15 |
+
public function toOptionArray() {
|
16 |
+
return array(
|
17 |
+
'1' => Mage::helper('recommend')->__('Yes'),
|
18 |
+
'0' => Mage::helper('recommend')->__('No'),
|
19 |
+
);
|
20 |
+
}
|
21 |
+
|
22 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Source/Enabled.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Generate options for Report Level selectbox in system config
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Model_System_Config_Source_Enabled {
|
14 |
+
|
15 |
+
public function toOptionArray() {
|
16 |
+
return array(
|
17 |
+
'1' => Mage::helper('recommend')->__('Yes'),
|
18 |
+
'0' => Mage::helper('recommend')->__('No'),
|
19 |
+
);
|
20 |
+
}
|
21 |
+
|
22 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Source/Mode.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Generate options for Mode selectbox in system config
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Model_System_Config_Source_Mode {
|
14 |
+
|
15 |
+
public function toOptionArray() {
|
16 |
+
return array(
|
17 |
+
'Live' => Mage::helper('recommend')->__('Live'),
|
18 |
+
'Test' => Mage::helper('recommend')->__('Test')
|
19 |
+
);
|
20 |
+
}
|
21 |
+
|
22 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Source/Related.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Generate options for Report Level selectbox in system config
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Model_System_Config_Source_Related {
|
14 |
+
|
15 |
+
public function toOptionArray() {
|
16 |
+
return array(
|
17 |
+
'1' => Mage::helper('recommend')->__('Yes'),
|
18 |
+
'0' => Mage::helper('recommend')->__('No'),
|
19 |
+
);
|
20 |
+
}
|
21 |
+
|
22 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Source/Reportlevel.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Generate options for Report Level selectbox in system config
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Model_System_Config_Source_Reportlevel {
|
14 |
+
|
15 |
+
public function toOptionArray() {
|
16 |
+
return array(
|
17 |
+
'Error' => Mage::helper('recommend')->__('Error'),
|
18 |
+
'Warning' => Mage::helper('recommend')->__('Warning'),
|
19 |
+
'Information' => Mage::helper('recommend')->__('Information'),
|
20 |
+
'All' => Mage::helper('recommend')->__('All'),
|
21 |
+
'None' => Mage::helper('recommend')->__('None'),
|
22 |
+
);
|
23 |
+
}
|
24 |
+
|
25 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Source/Resell.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Generate options for Report Level selectbox in system config
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Model_System_Config_Source_Resell {
|
14 |
+
|
15 |
+
public function toOptionArray() {
|
16 |
+
return array(
|
17 |
+
'0' => Mage::helper('recommend')->__('No'),
|
18 |
+
'1' => Mage::helper('recommend')->__('Yes'),
|
19 |
+
);
|
20 |
+
}
|
21 |
+
|
22 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Source/Resultformat.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Generate options for Result Format selectbox in system config
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Model_System_Config_Source_Resultformat {
|
14 |
+
|
15 |
+
public function toOptionArray() {
|
16 |
+
return array(
|
17 |
+
'TabDelimited' => Mage::helper('recommend')->__('Tab Delimited'),
|
18 |
+
'CommaDelimited' => Mage::helper('recommend')->__('Comma Delimited'),
|
19 |
+
'SpaceDelimited' => Mage::helper('recommend')->__('Space Delimited'),
|
20 |
+
'XML' => Mage::helper('recommend')->__('XML'),
|
21 |
+
);
|
22 |
+
}
|
23 |
+
|
24 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Source/Upsell.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* Generate options for Report Level selectbox in system config
|
8 |
+
*
|
9 |
+
* @package FourTell_Recommend
|
10 |
+
* @copyright 4-Tell, Inc.
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class FourTell_Recommend_Model_System_Config_Source_Upsell {
|
14 |
+
|
15 |
+
public function toOptionArray() {
|
16 |
+
return array(
|
17 |
+
'1' => Mage::helper('recommend')->__('Yes'),
|
18 |
+
'0' => Mage::helper('recommend')->__('No'),
|
19 |
+
);
|
20 |
+
}
|
21 |
+
|
22 |
+
}
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Clientid.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Clientid extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$clientid = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (trim($clientid) == "") { // exit if we're less than 10 digits long
|
16 |
+
Mage::throwException("You must enter your Client ID.");
|
17 |
+
}
|
18 |
+
|
19 |
+
return parent::save(); // call original save method so whatever happened
|
20 |
+
// before still happens (the value saves)
|
21 |
+
}
|
22 |
+
|
23 |
+
}
|
24 |
+
?>
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Email.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Email extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$email = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (preg_match("/^[-\w.]+@([A-z0-9][-A-z0-9]+\.)+[A-z]{2,4}$/", $email)) {
|
16 |
+
|
17 |
+
} else {
|
18 |
+
Mage::throwException("Please enter a valid email address.");
|
19 |
+
}
|
20 |
+
|
21 |
+
return parent::save(); // call original save method so whatever happened
|
22 |
+
// before still happens (the value saves)
|
23 |
+
}
|
24 |
+
|
25 |
+
}
|
26 |
+
?>
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Maxsalesdataageinmonths.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Maxsalesdataageinmonths extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$maxsalesdataageinmonths = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (!is_numeric($maxsalesdataageinmonths) || $maxsalesdataageinmonths < 0 || $maxsalesdataageinmonths > 30) {
|
16 |
+
Mage::throwException("Max Sales Data Age In Months must not be less than 1.");
|
17 |
+
}
|
18 |
+
|
19 |
+
return parent::save(); // call original save method so whatever happened
|
20 |
+
// before still happens (the value saves)
|
21 |
+
}
|
22 |
+
|
23 |
+
}
|
24 |
+
?>
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Mincommon.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Mincommon extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$mincommon = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (!is_numeric($mincommon) || $mincommon < 1 || $mincommon > 10) {
|
16 |
+
Mage::throwException("Min Common must be between 1 and 10.");
|
17 |
+
}
|
18 |
+
|
19 |
+
return parent::save(); // call original save method so whatever happened
|
20 |
+
// before still happens (the value saves)
|
21 |
+
}
|
22 |
+
|
23 |
+
}
|
24 |
+
?>
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Minlikelihood.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Minlikelihood extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$minlikelihood = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (!is_numeric($minlikelihood) || $minlikelihood < 1 || $minlikelihood > 30) {
|
16 |
+
Mage::throwException("Min Likelihood must be between 1 and 30.");
|
17 |
+
}
|
18 |
+
|
19 |
+
return parent::save(); // call original save method so whatever happened
|
20 |
+
// before still happens (the value saves)
|
21 |
+
}
|
22 |
+
|
23 |
+
}
|
24 |
+
?>
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Numcrosssell.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Numcrosssell extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$numcrosssell = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (strlen($numcrosssell) && is_numeric($numcrosssell) === false) {
|
16 |
+
Mage::throwException("Please enter a valid number of Cross Sell recommendations.");
|
17 |
+
}
|
18 |
+
|
19 |
+
return parent::save(); // call original save method so whatever happened
|
20 |
+
// before still happens (the value saves)
|
21 |
+
}
|
22 |
+
|
23 |
+
}
|
24 |
+
?>
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Numrelated.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Numrelated extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$numrelated = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (strlen($numrelated) && is_numeric($numrelated) === false) {
|
16 |
+
Mage::throwException("Please enter a valid number of Related recommendations.");
|
17 |
+
}
|
18 |
+
|
19 |
+
return parent::save(); // call original save method so whatever happened
|
20 |
+
// before still happens (the value saves)
|
21 |
+
}
|
22 |
+
|
23 |
+
}
|
24 |
+
?>
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Numupsell.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Numupsell extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$numupsell = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (strlen($numupsell) && is_numeric($numupsell) === false) {
|
16 |
+
Mage::throwException("Please enter a valid number of Upsell recommendations.");
|
17 |
+
}
|
18 |
+
|
19 |
+
return parent::save(); // call original save method so whatever happened
|
20 |
+
// before still happens (the value saves)
|
21 |
+
}
|
22 |
+
|
23 |
+
}
|
24 |
+
?>
|
app/code/community/FourTell/Recommend/Model/System/Config/Validation/Owner.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 4-Tell Product Recommendations
|
5 |
+
*
|
6 |
+
* @package FourTell_Recommend
|
7 |
+
* @copyright 4-Tell, Inc.
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
class FourTell_Recommend_Model_System_Config_Validation_Owner extends Mage_Core_Model_Config_Data {
|
11 |
+
|
12 |
+
public function save() {
|
13 |
+
$owner = $this->getValue(); // get the value from our config
|
14 |
+
|
15 |
+
if (trim($owner) == "") { // exit if we're less than 10 digits long
|
16 |
+
Mage::throwException("You must enter your owner name.");
|
17 |
+
}
|
18 |
+
|
19 |
+
return parent::save(); // call original save method so whatever happened
|
20 |
+
// before still happens (the value saves)
|
21 |
+
}
|
22 |
+
|
23 |
+
}
|
24 |
+
?>
|
app/code/community/FourTell/Recommend/Model/Upload/Frequency.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class FourTell_Recommend_Model_Upload_Frequency
|
3 |
+
{
|
4 |
+
public function toOptionArray()
|
5 |
+
{
|
6 |
+
return array(
|
7 |
+
168 => Mage::helper('adminhtml')->__('Weekly'),
|
8 |
+
24 => Mage::helper('adminhtml')->__('Daily'),
|
9 |
+
12 => Mage::helper('adminhtml')->__('Twice a day'),
|
10 |
+
8 => Mage::helper('adminhtml')->__('Three times a day'),
|
11 |
+
876000 => Mage::helper('adminhtml')->__('Disabled')
|
12 |
+
);
|
13 |
+
}
|
14 |
+
}
|
app/code/community/FourTell/Recommend/Model/UploadSetting.php
ADDED
@@ -0,0 +1,348 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* This is for loading and saving the upload configuration xml file
|
8 |
+
* settings from admin/Catalog/4-Tell Recommendations
|
9 |
+
*
|
10 |
+
* @package FourTell_Recommend
|
11 |
+
* @copyright 4-Tell, Inc.
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
class FourTell_Recommend_Model_UploadSetting extends Varien_Object {
|
15 |
+
|
16 |
+
const XML_PATH_UPLOAD_SETTING = 'default/recommend/upload/setting';
|
17 |
+
|
18 |
+
public $options = null;
|
19 |
+
public $upload_sales_data = "Yes";
|
20 |
+
public $upload_replacement_data = "Yes";
|
21 |
+
public $upload_product_data = "Yes";
|
22 |
+
public $upload_exclusion_data = "Yes";
|
23 |
+
public $replace_catalog_old_field = null;
|
24 |
+
public $replace_catalog_new_field = null;
|
25 |
+
public $product_attributtes = null;
|
26 |
+
public $showUploadDetails = "No";
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Initialize resource model
|
30 |
+
*/
|
31 |
+
protected function loadDefaultConfiguration()
|
32 |
+
{
|
33 |
+
$uploadSettingsDefault = get_object_vars(simplexml_load_file($this->getUploadOptionsPath()));
|
34 |
+
|
35 |
+
$arrSettingsDefault = $this->getSettingsDefaultArray($uploadSettingsDefault);
|
36 |
+
|
37 |
+
return $this->saveSettings(serialize($arrSettingsDefault));
|
38 |
+
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Return an Array of Object settings.
|
43 |
+
*
|
44 |
+
* @param Mixed $data
|
45 |
+
* @return Array
|
46 |
+
*/
|
47 |
+
protected function getSettingsDefaultArray($data){
|
48 |
+
if (is_object($data)) {
|
49 |
+
$arr = get_object_vars($data);
|
50 |
+
foreach ($arr as $key => $value) {
|
51 |
+
$assocArr = array();
|
52 |
+
if (is_array($value)) {
|
53 |
+
foreach ($value as $v) {
|
54 |
+
if (is_object($v) && count(get_object_vars($v))==2
|
55 |
+
&& isset($v->key) && isset($v->value)) {
|
56 |
+
$assocArr[$v->key] = $v->value;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
}
|
60 |
+
if (!empty($assocArr)) {
|
61 |
+
$arr[$key] = $assocArr;
|
62 |
+
}
|
63 |
+
}
|
64 |
+
$arr = $this->getSettingsDefaultArray($arr);
|
65 |
+
return $arr;
|
66 |
+
}
|
67 |
+
if (is_array($data)) {
|
68 |
+
foreach ($data as $key => $value) {
|
69 |
+
if (is_object($value) || is_array($value)) {
|
70 |
+
$data[$key] = $this->getSettingsDefaultArray($value);
|
71 |
+
} else {
|
72 |
+
$data[$key] = $value;
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
return $data;
|
77 |
+
}
|
78 |
+
|
79 |
+
|
80 |
+
|
81 |
+
public function saveSettings($settings)
|
82 |
+
{
|
83 |
+
Mage::getModel('core/config_data')
|
84 |
+
->load(self::XML_PATH_UPLOAD_SETTING, 'path')
|
85 |
+
->setValue($settings)
|
86 |
+
->setPath(self::XML_PATH_UPLOAD_SETTING)
|
87 |
+
->save();
|
88 |
+
Mage::getConfig()->cleanCache();
|
89 |
+
return $this;
|
90 |
+
}
|
91 |
+
|
92 |
+
|
93 |
+
public function getOptions() {
|
94 |
+
return $this->options;
|
95 |
+
}
|
96 |
+
|
97 |
+
public function getSetting($setting) {
|
98 |
+
$opts = $this->getOptions();
|
99 |
+
|
100 |
+
return $opts[$setting];
|
101 |
+
}
|
102 |
+
|
103 |
+
public function getExcludeOptions() {
|
104 |
+
$opts = $this->getOptions();
|
105 |
+
|
106 |
+
return $opts['exclude_options'];
|
107 |
+
}
|
108 |
+
|
109 |
+
public function setOptions($opts) {
|
110 |
+
|
111 |
+
$this->options['exclude_options'] = array();
|
112 |
+
if (isset($opts['exclude_options']['option']) && count($opts['exclude_options']['option'])) {
|
113 |
+
foreach ($opts['exclude_options']['option'] as $opt) {
|
114 |
+
$this->options['exclude_options'][] = $opt;
|
115 |
+
}
|
116 |
+
} else {
|
117 |
+
$this->options['exclude_options'] = array();
|
118 |
+
}
|
119 |
+
|
120 |
+
$this->options['replace_options'] = array();
|
121 |
+
if (isset($opts['replace_options']['option']) && count($opts['replace_options']['option'])) {
|
122 |
+
foreach ($opts['replace_options']['option'] as $opt) {
|
123 |
+
$this->options['replace_options'][] = $opt;
|
124 |
+
}
|
125 |
+
} else {
|
126 |
+
$this->options['replace_options'] = array();
|
127 |
+
}
|
128 |
+
|
129 |
+
if (isset($opts['upload_sales_data'])) {
|
130 |
+
$this->options['upload_sales_data'] = $opts['upload_sales_data'];
|
131 |
+
$this->upload_sales_data = $opts['upload_sales_data'];
|
132 |
+
} else {
|
133 |
+
$this->options['upload_sales_data'] = "Yes";
|
134 |
+
}
|
135 |
+
|
136 |
+
if (isset($opts['upload_replacement_data'])) {
|
137 |
+
$this->options['upload_replacement_data'] = $opts['upload_replacement_data'];
|
138 |
+
$this->upload_replacement_data = $opts['upload_replacement_data'];
|
139 |
+
} else {
|
140 |
+
$this->options['upload_replacement_data'] = "Yes";
|
141 |
+
}
|
142 |
+
|
143 |
+
if (isset($opts['upload_exclusion_data'])) {
|
144 |
+
$this->options['upload_exclusion_data'] = $opts['upload_exclusion_data'];
|
145 |
+
$this->upload_exclusion_data = $opts['upload_exclusion_data'];
|
146 |
+
} else {
|
147 |
+
$this->options['upload_exclusion_data'] = "Yes";
|
148 |
+
}
|
149 |
+
|
150 |
+
if (isset($opts['upload_product_data'])) {
|
151 |
+
$this->options['upload_product_data'] = $opts['upload_product_data'];
|
152 |
+
$this->upload_product_data = $opts['upload_product_data'];
|
153 |
+
} else {
|
154 |
+
$this->options['upload_product_data'] = "Yes";
|
155 |
+
}
|
156 |
+
|
157 |
+
if (isset($opts['replace_catalog_old_field'])) {
|
158 |
+
$this->options['replace_catalog_old_field'] = $opts['replace_catalog_old_field'];
|
159 |
+
$this->replace_catalog_old_field = $opts['replace_catalog_old_field'];
|
160 |
+
} else {
|
161 |
+
$this->options['replace_catalog_old_field'] = null;
|
162 |
+
}
|
163 |
+
|
164 |
+
if (isset($opts['replace_catalog_new_field'])) {
|
165 |
+
$this->options['replace_catalog_new_field'] = $opts['replace_catalog_new_field'];
|
166 |
+
$this->replace_catalog_new_field = $opts['replace_catalog_new_field'];
|
167 |
+
} else {
|
168 |
+
$this->options['replace_catalog_new_field'] = null;
|
169 |
+
}
|
170 |
+
|
171 |
+
if (isset($opts['showUploadDetails'])) {
|
172 |
+
$this->options['showUploadDetails'] = $opts['showUploadDetails'];
|
173 |
+
$this->showExportDetails = $opts['showUploadDetails'];
|
174 |
+
} else {
|
175 |
+
$this->options['showUploadDetails'] = "No";
|
176 |
+
}
|
177 |
+
|
178 |
+
}
|
179 |
+
|
180 |
+
function getUploadOptionsPath() {
|
181 |
+
Mage::Log('UploadSetting->getUploadOptionsPath');
|
182 |
+
return Mage::getModuleDir('etc', 'FourTell_Recommend') . DS . 'upload.xml';
|
183 |
+
}
|
184 |
+
|
185 |
+
public function load() {
|
186 |
+
|
187 |
+
$uploadSetting = Mage::getStoreConfig(self::XML_PATH_UPLOAD_SETTING);
|
188 |
+
|
189 |
+
if (!$uploadSetting) {
|
190 |
+
$uploadSetting = $this->loadDefaultConfiguration();
|
191 |
+
} else {
|
192 |
+
$uploadSetting = unserialize($uploadSetting);
|
193 |
+
}
|
194 |
+
|
195 |
+
$this->setOptions($uploadSetting);
|
196 |
+
|
197 |
+
return $this->getOptions();
|
198 |
+
}
|
199 |
+
|
200 |
+
public function save($post) {
|
201 |
+
$opts = array();
|
202 |
+
|
203 |
+
$ids = $this->getExcludePostIds($post);
|
204 |
+
$fields = array();
|
205 |
+
foreach ($ids as $id) {
|
206 |
+
$fields[] = $this->getExcludePostField($post, $id);
|
207 |
+
}
|
208 |
+
|
209 |
+
foreach ($fields as $field) {
|
210 |
+
$fieldNew = array();
|
211 |
+
$fieldNew['field'] = $field['Name'];
|
212 |
+
$fieldNew['compare'] = $field['Compare'];
|
213 |
+
$fieldNew['value'] = $field['Value'];
|
214 |
+
$opts['exclude_options']['option'][] = $fieldNew;
|
215 |
+
}
|
216 |
+
|
217 |
+
$ids = $this->getReplacePostIds($post);
|
218 |
+
$fields = array();
|
219 |
+
foreach ($ids as $id) {
|
220 |
+
$fields[] = $this->getReplacePostField($post, $id);
|
221 |
+
}
|
222 |
+
|
223 |
+
foreach ($fields as $field) {
|
224 |
+
$fieldNew = array();
|
225 |
+
$fieldNew['oldid'] = $field['oldid'];
|
226 |
+
$fieldNew['newid'] = $field['newid'];
|
227 |
+
$opts['replace_options']['option'][] = $fieldNew;
|
228 |
+
}
|
229 |
+
|
230 |
+
if( isset($post['upload_sales_data']) )
|
231 |
+
$opts['upload_sales_data'] = $post['upload_sales_data'];
|
232 |
+
else
|
233 |
+
$opts['upload_sales_data'] = '';
|
234 |
+
|
235 |
+
if( isset($post['upload_replacement_data']) )
|
236 |
+
$opts['upload_replacement_data'] = $post['upload_replacement_data'];
|
237 |
+
else
|
238 |
+
$opts['upload_replacement_data'] = '';
|
239 |
+
|
240 |
+
if( isset($post['upload_product_data']) )
|
241 |
+
$opts['upload_product_data'] = $post['upload_product_data'];
|
242 |
+
else
|
243 |
+
$opts['upload_product_data'] = '';
|
244 |
+
|
245 |
+
if( isset($post['upload_exclusion_data']) )
|
246 |
+
$opts['upload_exclusion_data'] = $post['upload_exclusion_data'];
|
247 |
+
else
|
248 |
+
$opts['upload_exclusion_data'] = '';
|
249 |
+
|
250 |
+
if( isset($post['replace_catalog_old_field']) )
|
251 |
+
$opts['replace_catalog_old_field'] = $post['replace_catalog_old_field'];
|
252 |
+
else
|
253 |
+
$opts['replace_catalog_old_field'] = '';
|
254 |
+
|
255 |
+
if( isset($post['replace_catalog_new_field']) )
|
256 |
+
$opts['replace_catalog_new_field'] = $post['replace_catalog_new_field'];
|
257 |
+
else
|
258 |
+
$opts['replace_catalog_new_field'] = '';
|
259 |
+
|
260 |
+
if( isset($post['showUploadDetails']) )
|
261 |
+
$opts['showUploadDetails'] = $post['showUploadDetails'];
|
262 |
+
else
|
263 |
+
$opts['showUploadDetails'] = '';
|
264 |
+
|
265 |
+
$this->setOptions ($opts);
|
266 |
+
|
267 |
+
return $this->saveSettings(serialize($opts));
|
268 |
+
}
|
269 |
+
|
270 |
+
function getExcludePostIds($post) {
|
271 |
+
|
272 |
+
$ids = array();
|
273 |
+
|
274 |
+
foreach ($post as $k => $v) {
|
275 |
+
if (strpos($k, "excludeField_Name") !== false && trim($v) != "") {
|
276 |
+
$parts = explode("_", trim($k));
|
277 |
+
$ids[] = $parts[2];
|
278 |
+
}
|
279 |
+
}
|
280 |
+
|
281 |
+
return $ids;
|
282 |
+
}
|
283 |
+
|
284 |
+
function getExcludePostField($post, $id) {
|
285 |
+
|
286 |
+
$data = array();
|
287 |
+
|
288 |
+
foreach ($post as $k => $v) {
|
289 |
+
if (strpos($k, "excludeField_") !== false && trim($v) != "") {
|
290 |
+
$parts = explode("_", trim($k));
|
291 |
+
if ($id == $parts[2]) {
|
292 |
+
$data[$parts[1]] = trim($v);
|
293 |
+
}
|
294 |
+
}
|
295 |
+
}
|
296 |
+
|
297 |
+
return $data;
|
298 |
+
}
|
299 |
+
|
300 |
+
function getReplacePostIds($post) {
|
301 |
+
|
302 |
+
$ids = array();
|
303 |
+
|
304 |
+
foreach ($post as $k => $v) {
|
305 |
+
if (strpos($k, "replaceField_oldid") !== false && trim($v) != "") {
|
306 |
+
$parts = explode("_", trim($k));
|
307 |
+
$ids[] = $parts[2];
|
308 |
+
}
|
309 |
+
}
|
310 |
+
|
311 |
+
return $ids;
|
312 |
+
}
|
313 |
+
|
314 |
+
function getReplacePostField($post, $id) {
|
315 |
+
|
316 |
+
$data = array();
|
317 |
+
|
318 |
+
foreach ($post as $k => $v) {
|
319 |
+
if (strpos($k, "replaceField_") !== false && trim($v) != "") {
|
320 |
+
$parts = explode("_", trim($k));
|
321 |
+
if ($id == $parts[2]) {
|
322 |
+
$data[$parts[1]] = trim($v);
|
323 |
+
}
|
324 |
+
}
|
325 |
+
}
|
326 |
+
|
327 |
+
return $data;
|
328 |
+
}
|
329 |
+
|
330 |
+
function _toArray() {
|
331 |
+
|
332 |
+
$data = array();
|
333 |
+
|
334 |
+
foreach ($this->getExcludeOptions()->getNode() as $opt) {
|
335 |
+
$ex = array(
|
336 |
+
'field' => (string) $opt->field,
|
337 |
+
'compare' => (string) $opt->compare,
|
338 |
+
'value' => (string) $opt->value
|
339 |
+
);
|
340 |
+
|
341 |
+
$data['exclude_options'][] = $ex;
|
342 |
+
}
|
343 |
+
|
344 |
+
return $data;
|
345 |
+
}
|
346 |
+
|
347 |
+
}
|
348 |
+
?>
|
app/code/community/FourTell/Recommend/controllers/Adminhtml/UploadformController.php
ADDED
@@ -0,0 +1,908 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
* 4-Tell Product Recommendations
|
6 |
+
*
|
7 |
+
* This is for processing the form in the admin
|
8 |
+
* Catalog/4-Tell Recommendations
|
9 |
+
*
|
10 |
+
* @package FourTell_Recommend
|
11 |
+
* @copyright 4-Tell, Inc.
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
class FourTell_Recommend_Adminhtml_UploadformController extends Mage_Adminhtml_Controller_Action {
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Show debugging export details
|
18 |
+
*
|
19 |
+
* @var booelan
|
20 |
+
*/
|
21 |
+
public $showUploadDetails = false;
|
22 |
+
/**
|
23 |
+
* Global variable for generating file contents
|
24 |
+
*
|
25 |
+
* @var string
|
26 |
+
*/
|
27 |
+
public $fileContents = "";
|
28 |
+
/**
|
29 |
+
* Exclude product options
|
30 |
+
*
|
31 |
+
* @var array
|
32 |
+
*/
|
33 |
+
public $excludeOptions = array();
|
34 |
+
/**
|
35 |
+
* Options for uploading data (recommend/etc/upload.xml)
|
36 |
+
*
|
37 |
+
* @var class
|
38 |
+
*/
|
39 |
+
//public $uploadSettings = null;
|
40 |
+
/**
|
41 |
+
* An array for holding all the months to upload sales for
|
42 |
+
*
|
43 |
+
* @var array
|
44 |
+
*/
|
45 |
+
public $salesFiles = null;
|
46 |
+
/**
|
47 |
+
* Maximum number of orders to upload at a time
|
48 |
+
*
|
49 |
+
* @var integer
|
50 |
+
*/
|
51 |
+
public $maxOrders = 500;
|
52 |
+
/**
|
53 |
+
* An array for holding url parameters
|
54 |
+
*
|
55 |
+
* @var array
|
56 |
+
*/
|
57 |
+
public $salesAppend = array();
|
58 |
+
/**
|
59 |
+
* An array for holding all the names of sales files to upload
|
60 |
+
*
|
61 |
+
* @var string
|
62 |
+
*/
|
63 |
+
public $options = null;
|
64 |
+
/**
|
65 |
+
* An array for holding all the names of sales files to upload
|
66 |
+
*
|
67 |
+
* @var string
|
68 |
+
*/
|
69 |
+
public $salesFileNames = "";
|
70 |
+
public $isAjax = false;
|
71 |
+
|
72 |
+
protected function _construct(){
|
73 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
74 |
+
$model->buildSalesFileNames();
|
75 |
+
}
|
76 |
+
|
77 |
+
|
78 |
+
/**
|
79 |
+
*
|
80 |
+
* Handler for clicking Catalog/4-Tell Recommendations
|
81 |
+
*
|
82 |
+
*/
|
83 |
+
public function indexAction() {
|
84 |
+
$this->processPostAction();
|
85 |
+
//if(!$this->isAjax){
|
86 |
+
$this->loadLayout()->renderLayout();
|
87 |
+
//}
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
*
|
92 |
+
* Handler for submit button on admin form
|
93 |
+
*
|
94 |
+
*/
|
95 |
+
public function postAction() {
|
96 |
+
$this->processPostAction();
|
97 |
+
|
98 |
+
$this->_redirect('*/*');
|
99 |
+
}
|
100 |
+
|
101 |
+
|
102 |
+
/**
|
103 |
+
*
|
104 |
+
* Handler for submit button on admin form
|
105 |
+
*
|
106 |
+
*/
|
107 |
+
public function processPostAction() {
|
108 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
109 |
+
set_time_limit(3000);
|
110 |
+
|
111 |
+
try {
|
112 |
+
$this->salesFileNames=$model->buildSalesFileNames();
|
113 |
+
|
114 |
+
$this->processGetAction();
|
115 |
+
|
116 |
+
$post = $this->getRequest()->getPost();
|
117 |
+
if (!empty($post)) {
|
118 |
+
$model->setData('post_data', $post);
|
119 |
+
$this->options=$this->getUploadSettings();
|
120 |
+
$this->options->save($post);
|
121 |
+
$resultData=$model->processData();
|
122 |
+
//if(false===$resultData) return false;
|
123 |
+
}
|
124 |
+
} catch (Exception $e) {
|
125 |
+
$this->processException($e, "processPostAction");
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
*
|
131 |
+
* Parse the url parameters from redirections
|
132 |
+
*
|
133 |
+
* If it is a redirecton then get values and upload next sales page orders
|
134 |
+
*
|
135 |
+
* If not a redirection then set default values.
|
136 |
+
*
|
137 |
+
*/
|
138 |
+
public function processGetAction() {
|
139 |
+
$params = $this->getRequest()->getParams();
|
140 |
+
|
141 |
+
if (array_key_exists('key', $params)) {
|
142 |
+
$this->salesAppend['key'] = $params['key'];
|
143 |
+
}
|
144 |
+
|
145 |
+
if (array_key_exists('isajax', $params)) {
|
146 |
+
$this->isAjax = true;
|
147 |
+
}
|
148 |
+
|
149 |
+
if (isset($params['cmd']) && isset($params['ym']) && isset($params['p'])) {
|
150 |
+
$this->salesAppend['cmd'] = $params['cmd'];
|
151 |
+
$this->salesAppend['ym'] = $params['ym'];
|
152 |
+
$this->salesAppend['p'] = intval($params['p']);
|
153 |
+
|
154 |
+
$this->showUploadProgress($this->salesAppend['ym'], $this->salesAppend['p']);
|
155 |
+
|
156 |
+
if ($this->salesAppend['cmd'] == "usf") {
|
157 |
+
$this->uploadYearMonthOrders($this->salesAppend['ym'], $this->salesAppend['p']);
|
158 |
+
}
|
159 |
+
} else if (isset($params['cmd']) && $params['cmd'] == "ucb") {
|
160 |
+
$this->exportConfiguration();
|
161 |
+
} else if (isset($params['cmd']) && $params['cmd'] == "ucd") {
|
162 |
+
$this->exportCategoryData();
|
163 |
+
} else if (isset($params['cmd']) && $params['cmd'] == "urd") {
|
164 |
+
$this->exportReplacementData();
|
165 |
+
} else if (isset($params['cmd']) && $params['cmd'] == "ued") {
|
166 |
+
$this->exportExclusionData();
|
167 |
+
} else if (isset($params['cmd']) && $params['cmd'] == "upd") {
|
168 |
+
//!!!
|
169 |
+
//$this->salesAppend['p'] = 1;
|
170 |
+
$this->exportProductData();
|
171 |
+
} else if (isset($params['cmd']) && $params['cmd'] == "gen") {
|
172 |
+
$this->startGenerator();
|
173 |
+
} else {
|
174 |
+
$this->salesAppend['cmd'] = "usf";
|
175 |
+
$this->salesAppend['ym'] = Mage::helper('recommend')->getNextUploadDate();
|
176 |
+
$this->salesAppend['p'] = 0;
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
*
|
182 |
+
* Display a list of sales files that have been uploaded
|
183 |
+
*
|
184 |
+
*/
|
185 |
+
function showUploadProgress($sf, $p) {
|
186 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
187 |
+
if(!$this->options) $this->options=$this->getUploadSettings();
|
188 |
+
try {
|
189 |
+
if (strtolower($this->options->getSetting('upload_sales_data')) != "none") {
|
190 |
+
$keys = array_keys($model->salesFiles);
|
191 |
+
$cf = $model->salesFiles[$sf];
|
192 |
+
|
193 |
+
Mage::getSingleton('core/session')->addWarning("Uploading sales orders, please wait...");
|
194 |
+
|
195 |
+
foreach ($keys as $idx => $key) {
|
196 |
+
if ($sf === $key) {
|
197 |
+
return;
|
198 |
+
}
|
199 |
+
|
200 |
+
Mage::getSingleton('core/session')->addWarning("Uploaded data for: sales_" . $key . ".txt");
|
201 |
+
}
|
202 |
+
}
|
203 |
+
} catch (Exception $e) {
|
204 |
+
$this->processException($e, "showUploadProgress");
|
205 |
+
}
|
206 |
+
}
|
207 |
+
|
208 |
+
/**
|
209 |
+
*
|
210 |
+
* Display a list of sales files that have been uploaded
|
211 |
+
*
|
212 |
+
*/
|
213 |
+
function showUploadComplete() {
|
214 |
+
try {
|
215 |
+
Mage::getSingleton('core/session')->addWarning("Upload of sales orders complete.");
|
216 |
+
$this->startGenerator();
|
217 |
+
} catch (Exception $e) {
|
218 |
+
$this->processException($e, "showUploadComplete");
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
*
|
224 |
+
* Get upload settings through the upload class
|
225 |
+
*
|
226 |
+
*/
|
227 |
+
public function getUploadSettings() {
|
228 |
+
if (!$this->options) {
|
229 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
230 |
+
try {
|
231 |
+
$this->options=$model->getUploadSettings();
|
232 |
+
} catch (Exception $e) {
|
233 |
+
$this->processException($e, "getUploadSettings");
|
234 |
+
}
|
235 |
+
}
|
236 |
+
return $this->options;
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
*
|
241 |
+
* Shortcut for getting admin setting of client id
|
242 |
+
*
|
243 |
+
*/
|
244 |
+
|
245 |
+
function getClientId() {
|
246 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
247 |
+
try {
|
248 |
+
return $model->getClientId();
|
249 |
+
} catch (Exception $e) {
|
250 |
+
$this->processException($e, "getClientId");
|
251 |
+
}
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
*
|
256 |
+
* Shortcut for getting admin setting of enabled
|
257 |
+
*
|
258 |
+
*/
|
259 |
+
function getEnabled() {
|
260 |
+
try {
|
261 |
+
return intval(Mage::getStoreConfig('recommend/config/enabled'));
|
262 |
+
} catch (Exception $e) {
|
263 |
+
$this->processException($e, "getEnabled");
|
264 |
+
}
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
*
|
269 |
+
* Generate and upload config settings
|
270 |
+
*
|
271 |
+
*/
|
272 |
+
|
273 |
+
function exportConfiguration() {
|
274 |
+
try {
|
275 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
276 |
+
$model->exportConfiguration();
|
277 |
+
} catch (Exception $e) {
|
278 |
+
$this->processException($e, "exportConfiguration");
|
279 |
+
}
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
*
|
284 |
+
* Generate and upload category data
|
285 |
+
*
|
286 |
+
*/
|
287 |
+
|
288 |
+
function exportCategoryData() {
|
289 |
+
try {
|
290 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
291 |
+
$model->exportCategoryData();
|
292 |
+
} catch (Exception $e) {
|
293 |
+
$this->processException($e, "exportCategoryData");
|
294 |
+
}
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
*
|
299 |
+
* Generate sale data for a specified month and export it
|
300 |
+
*
|
301 |
+
*/
|
302 |
+
function uploadYearMonthOrders($sf, $p) {
|
303 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
304 |
+
try {
|
305 |
+
$generate = false;
|
306 |
+
|
307 |
+
$fn = "sales_" . $sf . ".txt";
|
308 |
+
$sp = explode("-", $sf);
|
309 |
+
|
310 |
+
$cf = $model->salesFiles[$sf];
|
311 |
+
$isLastUploadMonth = $cf['last'];
|
312 |
+
//$p=1;//!!!
|
313 |
+
if ($p == 0) {
|
314 |
+
$type = "create";
|
315 |
+
} else {
|
316 |
+
$type = "append";
|
317 |
+
}
|
318 |
+
|
319 |
+
$items = null;
|
320 |
+
$item = null;
|
321 |
+
$data = null;
|
322 |
+
$configurable_product_model = Mage::getModel('catalog/product_type_configurable');
|
323 |
+
|
324 |
+
// Get the sales data for the month as a collection
|
325 |
+
$collection = $this->getSalesOrdersForMonth($sp[0], $sp[1], $p);
|
326 |
+
|
327 |
+
if ($collection->count() < $this->maxOrders && $isLastUploadMonth == 1) {
|
328 |
+
$completed = "uploadComplete";
|
329 |
+
} else if ($collection->count() < $this->maxOrders) {
|
330 |
+
$completed = "monthComplete";
|
331 |
+
} else {
|
332 |
+
$completed = "false";
|
333 |
+
}
|
334 |
+
|
335 |
+
$today = date("m-d-Y");
|
336 |
+
unset($contents);
|
337 |
+
|
338 |
+
if ($type == "create") {
|
339 |
+
$contents = $this->getClientId() . "\t" . $fn . "\t" . $type . "\r\nVersion\t2\t" . $today . "\r\nProduct ID\tCustomer ID\tQuantity\tDate\r\n";
|
340 |
+
} else {
|
341 |
+
$contents = $this->getClientId() . "\t" . $fn . "\t" . $type . "\r\n";
|
342 |
+
}
|
343 |
+
|
344 |
+
// Loop through the collection data
|
345 |
+
foreach ($collection as $order) {
|
346 |
+
// Get customer ID of use who placed the order
|
347 |
+
// if the customer was an account
|
348 |
+
$customerId = $order->getData('customer_id');
|
349 |
+
if ($customerId == '') {
|
350 |
+
// Get email of use who placed the order if
|
351 |
+
// the order was placed with guest checkout
|
352 |
+
$customerId = $order->getData('customer_email');
|
353 |
+
if ($customerId == '') {
|
354 |
+
// Get order ID as last resort to use
|
355 |
+
// as the customer ID
|
356 |
+
$customerId = $order->getData('increment_id');
|
357 |
+
} else {
|
358 |
+
// If we ended up with an email address then
|
359 |
+
// make into a hash so we are not transmitting
|
360 |
+
// or storing readable personal information
|
361 |
+
$customerId = md5($customerId);
|
362 |
+
}
|
363 |
+
}
|
364 |
+
|
365 |
+
// Get all the order items for the current order
|
366 |
+
$items = $order->getAllItems();
|
367 |
+
|
368 |
+
// Loop through the order items
|
369 |
+
foreach ($items as $item) {
|
370 |
+
// Get the data for the current item
|
371 |
+
$product_id = $item->getData('product_id');
|
372 |
+
$product_type = $item->getData('product_type');
|
373 |
+
$created_at = $item->getData('created_at');
|
374 |
+
$qty_ordered = $item->getData('qty_ordered');
|
375 |
+
$created_at = $order->getData('created_at');
|
376 |
+
|
377 |
+
// If the item in not configurable then proceed
|
378 |
+
if ($product_type != "configurable") {
|
379 |
+
$dt = new DateTime($created_at);
|
380 |
+
|
381 |
+
if ($product_type == "simple" || $product_type == "") {
|
382 |
+
//$configurable_product_model = Mage::getModel('catalog/product_type_configurable');
|
383 |
+
if (!is_object($configurable_product_model)) {
|
384 |
+
throw new Exception("Unable to get model: catalog/product_type_configurable");
|
385 |
+
}
|
386 |
+
|
387 |
+
$parentIdArray = $configurable_product_model->getParentIdsByChild($product_id);
|
388 |
+
if (isset($parentIdArray[0])) {
|
389 |
+
$product_id = $parentIdArray[0];
|
390 |
+
}
|
391 |
+
}
|
392 |
+
|
393 |
+
$contents = $contents . $product_id . "\t" . $customerId . "\t" . intval($qty_ordered) . "\t" . $dt->format('Y-m-d') . "\r\n";
|
394 |
+
}
|
395 |
+
|
396 |
+
unset($item);
|
397 |
+
unset($data);
|
398 |
+
}
|
399 |
+
}
|
400 |
+
|
401 |
+
unset($collection);
|
402 |
+
|
403 |
+
$model->exportFile($fn, $contents, $type);
|
404 |
+
|
405 |
+
|
406 |
+
if ($this->isAjax) {
|
407 |
+
$msg = array(
|
408 |
+
'status' => $completed,
|
409 |
+
'month' => "",
|
410 |
+
'page' => ""
|
411 |
+
);
|
412 |
+
|
413 |
+
if ($completed != "uploadComplete") {
|
414 |
+
if ($completed == "monthComplete") {
|
415 |
+
$month = Mage::helper('recommend')->getNextUploadDate($sf);
|
416 |
+
$page = 0;
|
417 |
+
$msg['month'] = $month;
|
418 |
+
$msg['page'] = $page;
|
419 |
+
} else {
|
420 |
+
$page = $p + 1;
|
421 |
+
$msg['month'] = $sf;
|
422 |
+
$msg['page'] = $page;
|
423 |
+
}
|
424 |
+
}
|
425 |
+
$this->getResponse()->setBody(Zend_Json::encode($msg));
|
426 |
+
}
|
427 |
+
|
428 |
+
|
429 |
+
if ($completed != "uploadComplete") {
|
430 |
+
$this->processNextSales($sf, $p, $completed);
|
431 |
+
} else {
|
432 |
+
$this->showUploadComplete();
|
433 |
+
}
|
434 |
+
} catch (Exception $e) {
|
435 |
+
$this->processException($e, "uploadYearMonthOrders");
|
436 |
+
}
|
437 |
+
}
|
438 |
+
|
439 |
+
public function processNextSales($sf, $p, $completed){
|
440 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
441 |
+
/*
|
442 |
+
require_once("FourTell/Recommend/controllers/Adminhtml/UploadformController.php");
|
443 |
+
$uploadModel=Mage::getSingleton('FourTell_Recommend_Adminhtml_UploadformController');
|
444 |
+
$uploadModel->__construct(Mage::app()->getRequest());
|
445 |
+
*/
|
446 |
+
//move back to controller!
|
447 |
+
$cf = $model->salesFiles[$sf];
|
448 |
+
$isLastUploadMonth = $cf['last'];
|
449 |
+
|
450 |
+
if ($completed == "monthComplete") {
|
451 |
+
$this->salesAppend['ym'] = Mage::helper('recommend')->getNextUploadDate($sf);
|
452 |
+
$this->salesAppend['p'] = 0;
|
453 |
+
} else {
|
454 |
+
$this->salesAppend['p']++;
|
455 |
+
}
|
456 |
+
/*
|
457 |
+
$newUrl = Mage::getBaseUrl() .
|
458 |
+
Mage::app()->getRequest()->getModuleName() .
|
459 |
+
"/" . Mage::app()->getRequest()->getControllerName() .
|
460 |
+
"/index";
|
461 |
+
*/
|
462 |
+
$newUrl = Mage::getUrl('*/*/index');
|
463 |
+
|
464 |
+
if (array_key_exists('key', $this->salesAppend) && !empty($this->salesAppend['key'])) {
|
465 |
+
$newUrl .= "/key/" . $this->salesAppend['key'];
|
466 |
+
}
|
467 |
+
elseif($admin_html_key=Mage::getSingleton('adminhtml/url')->getSecretKey("adminhtml_uploadform","index")){
|
468 |
+
$newUrl .= "key/" . $admin_html_key;
|
469 |
+
}
|
470 |
+
$newUrl .=
|
471 |
+
"/cmd/" . $this->salesAppend['cmd'] .
|
472 |
+
"/ym/" . $this->salesAppend['ym'] .
|
473 |
+
"/p/" . $this->salesAppend['p'];
|
474 |
+
|
475 |
+
$jsUrl = '<script type="text/javascript">window.location.href="' . $newUrl . '";</script>';
|
476 |
+
//$curl = curl_init($newUrl);
|
477 |
+
//$response = curl_exec($curl);
|
478 |
+
//curl_close($curl);
|
479 |
+
Mage::getSingleton('core/session')->addWarning($jsUrl);
|
480 |
+
}
|
481 |
+
|
482 |
+
/**
|
483 |
+
*
|
484 |
+
* After uploading a sales files this gets called, this determines if we
|
485 |
+
* should go to the next page of ther current sales file or go to the next
|
486 |
+
* sales file or if we have finished uploading all sales data
|
487 |
+
*
|
488 |
+
*/
|
489 |
+
/*
|
490 |
+
function processNextSales($sf, $p, $completed) {
|
491 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
492 |
+
$cf = $model->salesFiles[$sf];
|
493 |
+
$isLastUploadMonth = $cf['last'];
|
494 |
+
|
495 |
+
if ($completed == "monthComplete") {
|
496 |
+
$this->salesAppend['ym'] = $this->getNextUploadDate($sf);
|
497 |
+
$this->salesAppend['p'] = 0;
|
498 |
+
} else {
|
499 |
+
$this->salesAppend['p']++;
|
500 |
+
}
|
501 |
+
|
502 |
+
$newUrl = Mage::getBaseUrl() .
|
503 |
+
$this->getRequest()->getModuleName() .
|
504 |
+
"/" . $this->getRequest()->getControllerName() .
|
505 |
+
"/index";
|
506 |
+
|
507 |
+
if (array_key_exists('key', $this->salesAppend) && !empty($this->salesAppend['key'])) {
|
508 |
+
$newUrl .= "/key/" . $this->salesAppend['key'];
|
509 |
+
}
|
510 |
+
|
511 |
+
$newUrl .=
|
512 |
+
"/cmd/" . $this->salesAppend['cmd'] .
|
513 |
+
"/ym/" . $this->salesAppend['ym'] .
|
514 |
+
"/p/" . $this->salesAppend['p'];
|
515 |
+
|
516 |
+
$jsUrl = '<script type="text/javascript">window.location.href="' . $newUrl . '";</script>';
|
517 |
+
Mage::getSingleton('core/session')->addWarning($jsUrl);
|
518 |
+
}
|
519 |
+
*/
|
520 |
+
/**
|
521 |
+
*
|
522 |
+
* Check to see of the current sales file is the last sales file in the
|
523 |
+
* the array of sales file to upload
|
524 |
+
*
|
525 |
+
*/
|
526 |
+
function checkIsLastUploadMonth($sf) {
|
527 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
528 |
+
$ret = 0;
|
529 |
+
$keys = array_keys($model->salesFiles);
|
530 |
+
|
531 |
+
foreach ($keys as $idx => $key) {
|
532 |
+
if ($sf === $key && $idx == count($keys)) {
|
533 |
+
$ret = 1;
|
534 |
+
}
|
535 |
+
}
|
536 |
+
|
537 |
+
return $ret;
|
538 |
+
}
|
539 |
+
|
540 |
+
/**
|
541 |
+
*
|
542 |
+
* Get the next sales file from the array of sales files, if parameter
|
543 |
+
* is null then we return the first sales files, allowing null is used
|
544 |
+
* for when we do the first redirection sine we won't have a value at
|
545 |
+
* that pint to pass in
|
546 |
+
*
|
547 |
+
*/
|
548 |
+
/*
|
549 |
+
function getNextUploadDate($sf = null) {
|
550 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
551 |
+
$ret = 0;
|
552 |
+
$keys = array_keys($model->salesFiles);
|
553 |
+
|
554 |
+
$getNext = 0;
|
555 |
+
if ($sf == null) {
|
556 |
+
$getNext = 1;
|
557 |
+
}
|
558 |
+
|
559 |
+
foreach ($keys as $idx => $key) {
|
560 |
+
if ($getNext == 1) {
|
561 |
+
return $key;
|
562 |
+
}
|
563 |
+
|
564 |
+
if ($sf === $key) {
|
565 |
+
$getNext = 1;
|
566 |
+
}
|
567 |
+
}
|
568 |
+
|
569 |
+
return null;
|
570 |
+
}
|
571 |
+
*/
|
572 |
+
/**
|
573 |
+
*
|
574 |
+
* Get the sales data for the specified month and year
|
575 |
+
*
|
576 |
+
*/
|
577 |
+
function getSalesOrdersForMonth($year, $month, $p) {
|
578 |
+
$collection = null;
|
579 |
+
|
580 |
+
try {
|
581 |
+
$orders = Mage::getModel('sales/order');
|
582 |
+
if (!is_object($orders)) {
|
583 |
+
throw new Exception("Unable to get model: sales/order");
|
584 |
+
}
|
585 |
+
|
586 |
+
$collection = $orders->getCollection();
|
587 |
+
if (!is_object($collection)) {
|
588 |
+
throw new Exception("Unable to get order collection");
|
589 |
+
}
|
590 |
+
|
591 |
+
$collection->addFieldToFilter('created_at', array('gt' => $year . '-' . $month . '-01'));
|
592 |
+
$collection->addFieldToFilter('created_at', array('lt' => $year . '-' . ($month + 1) . '-01'));
|
593 |
+
$collection->setPageSize($this->maxOrders);
|
594 |
+
$collection->setCurPage($p);
|
595 |
+
} catch (Exception $e) {
|
596 |
+
$this->processException($e, "exportSalesData");
|
597 |
+
}
|
598 |
+
|
599 |
+
$startPos = ($p * $this->maxOrders) + 1;
|
600 |
+
Mage::log("Year: " . $year . "] Month: " . $month . "] Start: " . $startPos . "] Max: " . $this->maxOrders . "] Page: " . $p . "] Count: " . $collection->count());
|
601 |
+
|
602 |
+
return $collection;
|
603 |
+
}
|
604 |
+
|
605 |
+
/**
|
606 |
+
*
|
607 |
+
* Get the number of orders for the specified month and year
|
608 |
+
*
|
609 |
+
*/
|
610 |
+
function getSalesCountForMonth($year, $month) {
|
611 |
+
try {
|
612 |
+
$from = $year . "-" . intval($month) . "-1 00:00:00";
|
613 |
+
$to = $year . "-" . ($month + 1) . "-1 00:00:00";
|
614 |
+
|
615 |
+
$_collection = Mage::getResourceModel('sales/order_collection')->addAttributeToSelect('*')->addAttributeToFilter('created_at', array('from' => $from, 'to' => $to));
|
616 |
+
} catch (Exception $e) {
|
617 |
+
$processException($e, "getSalesCountForMonth");
|
618 |
+
return 0;
|
619 |
+
}
|
620 |
+
|
621 |
+
return $_collection->count();
|
622 |
+
}
|
623 |
+
|
624 |
+
/**
|
625 |
+
*
|
626 |
+
* Export Product Data
|
627 |
+
*
|
628 |
+
*/
|
629 |
+
|
630 |
+
function exportProductData() {
|
631 |
+
try {
|
632 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
633 |
+
$model->exportProductData();
|
634 |
+
} catch (Exception $e) {
|
635 |
+
$this->processException($e, "exportProductData");
|
636 |
+
}
|
637 |
+
}
|
638 |
+
|
639 |
+
/**
|
640 |
+
*
|
641 |
+
* Export Product Replacement Data
|
642 |
+
*
|
643 |
+
*/
|
644 |
+
function exportReplacementData() {
|
645 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
646 |
+
if(!$this->options){
|
647 |
+
$this->getUploadSettings();
|
648 |
+
}
|
649 |
+
$generate = "false";
|
650 |
+
|
651 |
+
try {
|
652 |
+
// Create file header
|
653 |
+
$today = date("m-d-Y");
|
654 |
+
$this->fileContents = $this->getClientId() . "\tReplacements.txt\t" . $generate . "\r\nVersion\t2\t" . $today . "\r\nOld Product ID\tNew Product ID\r\n";
|
655 |
+
|
656 |
+
if ($this->options->getSetting('upload_replacement_data') == "Entire Catalog") {
|
657 |
+
// Get all products with just data needed
|
658 |
+
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect($this->options->getSetting('replace_catalog_old_field'), $this->options->getSetting('replace_catalog_new_field'))->addAttributeToSelect(array('name', 'price', 'image', 'url_path'), 'inner');
|
659 |
+
|
660 |
+
// Use an iterator to loop through the collection
|
661 |
+
Mage::getSingleton('core/resource_iterator')->walk($products->getSelect(), array(array($this, 'replacementCallback')), array('arg1' => '====['));
|
662 |
+
} else if ($this->options->getSetting('upload_replacement_data') == "Individual Items") {
|
663 |
+
$opts = Mage::getSingleton('FourTell_Recommend_Model_UploadSetting')->load();
|
664 |
+
|
665 |
+
foreach ($opts['replace_options'] as $o) {
|
666 |
+
$this->fileContents = $this->fileContents . (string) $o->oldid . "\t" . (string) $o->newid . "\r\n";
|
667 |
+
}
|
668 |
+
}
|
669 |
+
|
670 |
+
// Upload Replacements.txt contents to server
|
671 |
+
$model->exportFile("Replacements.txt", $this->fileContents, "create");
|
672 |
+
} catch (Exception $e) {
|
673 |
+
$this->processException($e, "exportReplacementData");
|
674 |
+
}
|
675 |
+
}
|
676 |
+
|
677 |
+
/**
|
678 |
+
*
|
679 |
+
* This is the call back function used in the replacement iterator
|
680 |
+
*
|
681 |
+
*/
|
682 |
+
function replacementCallback($args) {
|
683 |
+
try {
|
684 |
+
$product = Mage::getModel('catalog/product');
|
685 |
+
$product->setData($args['row']);
|
686 |
+
|
687 |
+
$incProduct = true;
|
688 |
+
if ($product->type_id == "simple" || $product_type == "") {
|
689 |
+
// Get product parent ids
|
690 |
+
$configurable_product_model = Mage::getModel('catalog/product_type_configurable');
|
691 |
+
if (!is_object($configurable_product_model)) {
|
692 |
+
throw new Exception("Unable to get model: catalog/product_type_configurable");
|
693 |
+
}
|
694 |
+
$parentIdArray = $configurable_product_model->getParentIdsByChild($product->getEntityId());
|
695 |
+
|
696 |
+
// Don't upload if it has parent ids
|
697 |
+
if (isset($parentIdArray[0])) {
|
698 |
+
$dataProduct = Mage::getModel('catalog/product')->load($parentIdArray[0]);
|
699 |
+
} else {
|
700 |
+
$dataProduct = $product;
|
701 |
+
}
|
702 |
+
} else {
|
703 |
+
$dataProduct = $product;
|
704 |
+
}
|
705 |
+
|
706 |
+
$this->fileContents = $this->fileContents . $product->getData($this->options->getSetting('replace_catalog_old_field')) . "\t" . $dataProduct->getData($this->options->getSetting('replace_catalog_new_field')) . "\r\n";
|
707 |
+
} catch (Exception $e) {
|
708 |
+
$this->processException($e, "replacementCallback");
|
709 |
+
}
|
710 |
+
}
|
711 |
+
|
712 |
+
/**
|
713 |
+
*
|
714 |
+
* Export Product Exclusion Data
|
715 |
+
*
|
716 |
+
*/
|
717 |
+
function exportExclusionData() {
|
718 |
+
$model=Mage::getSingleton('FourTell_Recommend_Model_Adminhtml_Uploadform');
|
719 |
+
$generate = "false";
|
720 |
+
try {
|
721 |
+
$opts = Mage::getSingleton('FourTell_Recommend_Model_UploadSetting')->load();
|
722 |
+
|
723 |
+
if (count($opts['exclude_options'])) {
|
724 |
+
// Create file header
|
725 |
+
$today = date("m-d-Y");
|
726 |
+
$this->fileContents = $this->getClientId() . "\tDoNotRecommend.txt\t" . $generate . "\r\nVersion\t2\t" . $today . "\r\nProduct ID\r\n";
|
727 |
+
|
728 |
+
// Create array of filter options
|
729 |
+
$filters = array();
|
730 |
+
foreach ($opts['exclude_options'] as $o) {
|
731 |
+
$filt = array();
|
732 |
+
$filt['attribute'] = (string) $o['field'];
|
733 |
+
$filt[(string) $o['compare']] = (string) $o['value'];
|
734 |
+
|
735 |
+
$filters[] = $filt;
|
736 |
+
}
|
737 |
+
|
738 |
+
// Get product collection based on filter options
|
739 |
+
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('sku')->addFieldToFilter($filters);
|
740 |
+
|
741 |
+
// Use an iterator to loop through the collection
|
742 |
+
Mage::getSingleton('core/resource_iterator')->walk($products->getSelect(), array(array($this, 'exclusionCallback')), array('arg1' => '====['));
|
743 |
+
|
744 |
+
// Upload DoNotRecommend.txt contents to server
|
745 |
+
$model->exportFile("DoNotRecommend.txt", $this->fileContents, "create");
|
746 |
+
}
|
747 |
+
} catch (Exception $e) {
|
748 |
+
$this->processException($e, "exportExclusionData");
|
749 |
+
}
|
750 |
+
}
|
751 |
+
|
752 |
+
/**
|
753 |
+
*
|
754 |
+
* This is the call back function used in the exclusion iterator
|
755 |
+
*
|
756 |
+
*/
|
757 |
+
function exclusionCallback($args) {
|
758 |
+
try {
|
759 |
+
$product = Mage::getModel('catalog/product');
|
760 |
+
$product->setData($args['row']);
|
761 |
+
|
762 |
+
$this->fileContents = $this->fileContents . $product->getEntityId() . "\r\n";
|
763 |
+
} catch (Exception $e) {
|
764 |
+
$this->processException($e, "exclusionCallback");
|
765 |
+
}
|
766 |
+
}
|
767 |
+
|
768 |
+
/**
|
769 |
+
*
|
770 |
+
* Get mode (live or test)
|
771 |
+
*
|
772 |
+
*/
|
773 |
+
/*
|
774 |
+
function getMode() {
|
775 |
+
try {
|
776 |
+
if (Mage::getStoreConfig('recommend/config/mode') == "Test") {
|
777 |
+
return "biz";
|
778 |
+
}
|
779 |
+
|
780 |
+
return "net";
|
781 |
+
} catch (Exception $e) {
|
782 |
+
$this->processException($e, "getMode");
|
783 |
+
}
|
784 |
+
}
|
785 |
+
*/
|
786 |
+
/**
|
787 |
+
*
|
788 |
+
* Upload data to 4-Tell server
|
789 |
+
*
|
790 |
+
*/
|
791 |
+
|
792 |
+
/**
|
793 |
+
*
|
794 |
+
* Upload data to 4-Tell server
|
795 |
+
*
|
796 |
+
*/
|
797 |
+
function startGenerator() {
|
798 |
+
try {
|
799 |
+
$mode = Mage::helper('recommend')->getMode();
|
800 |
+
|
801 |
+
// The request URL prefix
|
802 |
+
$request = "http://www.4-tell." . $mode . "/Boost2.0/rest/GenerateDataTables?clientAlias=" . $this->getClientId() . "&reloadTables=true";
|
803 |
+
|
804 |
+
$fields = array(
|
805 |
+
'clientAlias' => urlencode($this->getClientId()),
|
806 |
+
'reloadTables' => urlencode("true")
|
807 |
+
);
|
808 |
+
|
809 |
+
$fields_string = "";
|
810 |
+
//url-ify the data for the POST
|
811 |
+
foreach ($fields as $key => $value) {
|
812 |
+
$fields_string .= $key . '=' . $value . '&';
|
813 |
+
}
|
814 |
+
rtrim($fields_string, '&');
|
815 |
+
|
816 |
+
$session = curl_init($request);
|
817 |
+
|
818 |
+
curl_setopt($session, CURLOPT_RETURNTRANSFER, 1);
|
819 |
+
curl_setopt($session, CURLOPT_HEADER, 1);
|
820 |
+
curl_setopt($session, CURLOPT_POST, 1);
|
821 |
+
curl_setopt($session, CURLOPT_POSTFIELDS, $fields_string);
|
822 |
+
curl_setopt($session, CURLOPT_VERBOSE, 0);
|
823 |
+
curl_setopt($session, CURLINFO_HEADER_OUT, 0);
|
824 |
+
|
825 |
+
$response = curl_exec($session);
|
826 |
+
if ($response === false) {
|
827 |
+
throw new Exception(curl_error($session));
|
828 |
+
}
|
829 |
+
curl_close($session);
|
830 |
+
|
831 |
+
if (stripos($response, "200 OK") === false) {
|
832 |
+
throw new Exception("Error generating data: " . ": " . $response);
|
833 |
+
Mage::getSingleton('core/session')->addError("Generator reload failed");
|
834 |
+
|
835 |
+
return false;
|
836 |
+
} else {
|
837 |
+
if (Mage::getStoreConfig('recommend/config/mode') == "Test" && $this->options->getSetting('showUploadDetails') == "Yes") {
|
838 |
+
Mage::getSingleton('core/session')->addWarning("Generator successful, data table reload queued");
|
839 |
+
}
|
840 |
+
|
841 |
+
return true;
|
842 |
+
}
|
843 |
+
} catch (Exception $e) {
|
844 |
+
$this->processException($e, "exportFile");
|
845 |
+
|
846 |
+
return false;
|
847 |
+
}
|
848 |
+
}
|
849 |
+
|
850 |
+
/**
|
851 |
+
*
|
852 |
+
* Add error message to browser and log error file if logging is turned on
|
853 |
+
*
|
854 |
+
* @param e Exception object
|
855 |
+
* @param function Name of function where exception occurred
|
856 |
+
*/
|
857 |
+
function processException($e, $function) {
|
858 |
+
Mage::getSingleton('core/session')->addError($e->getMessage());
|
859 |
+
Mage::log("4-Tell (UploadformController::" . $function . ") :: " . $e->getMessage(), null, "4tell.log");
|
860 |
+
}
|
861 |
+
|
862 |
+
/**
|
863 |
+
*
|
864 |
+
* Test code for getting all available product attributes
|
865 |
+
*
|
866 |
+
* @return array a list of available product attributes
|
867 |
+
*
|
868 |
+
*/
|
869 |
+
public function getProductAttributes() {
|
870 |
+
$prodAttrs = array();
|
871 |
+
|
872 |
+
try {
|
873 |
+
$attrs = Mage::getModel("Mage_Eav_Model_Entity_Attribute");
|
874 |
+
if (!is_object($attrs)) {
|
875 |
+
throw new Exception("Unable to get model: Mage_Eav_Model_Entity_Attribute");
|
876 |
+
}
|
877 |
+
|
878 |
+
$sets = Mage::getModel("Mage_Eav_Model_Entity_Attribute_Set");
|
879 |
+
if (!is_object($sets)) {
|
880 |
+
throw new Exception("Unable to get model: Mage_Eav_Model_Entity_Attribute_Set");
|
881 |
+
}
|
882 |
+
|
883 |
+
foreach ($attrs->getCollection() as $attr) {
|
884 |
+
if ($attr->getData("entity_type_id") == 10)
|
885 |
+
$prodAttrs[] = array('name' => $attr->getData("attribute_code"), 'label' => $attr->getData("frontend_label"));
|
886 |
+
}
|
887 |
+
|
888 |
+
usort($prodAttrs, array(Mage::helper('recommend'), 'compare_type'));
|
889 |
+
} catch (Exception $e) {
|
890 |
+
$this->processException($e, "getProductAttributes");
|
891 |
+
}
|
892 |
+
|
893 |
+
return $prodAttrs;
|
894 |
+
}
|
895 |
+
|
896 |
+
/**
|
897 |
+
* Compare types $a and $b
|
898 |
+
*
|
899 |
+
* @param array $a
|
900 |
+
* @param array $b
|
901 |
+
* @return numeric
|
902 |
+
*/
|
903 |
+
/*
|
904 |
+
private function compare_type($a, $b) {
|
905 |
+
return strnatcmp($a['name'], $b['name']);
|
906 |
+
}
|
907 |
+
*/
|
908 |
+
}
|
app/code/community/FourTell/Recommend/etc/config.xml
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<FourTell_Recommend>
|
5 |
+
<version>1.2.8</version>
|
6 |
+
</FourTell_Recommend>
|
7 |
+
</modules>
|
8 |
+
|
9 |
+
<global>
|
10 |
+
<models>
|
11 |
+
<recommend>
|
12 |
+
<class>FourTell_Recommend_Model</class>
|
13 |
+
<resourceModel>recommend_mysql4</resourceModel>
|
14 |
+
</recommend>
|
15 |
+
|
16 |
+
<recommend_mysql4>
|
17 |
+
<class>FourTell_Recommend_Model_Mysql4</class>
|
18 |
+
</recommend_mysql4>
|
19 |
+
</models>
|
20 |
+
|
21 |
+
<blocks>
|
22 |
+
<recommend>
|
23 |
+
<class>FourTell_Recommend_Block</class>
|
24 |
+
</recommend>
|
25 |
+
|
26 |
+
<!-- Community Edition -->
|
27 |
+
<catalog>
|
28 |
+
<rewrite>
|
29 |
+
<product_list_upsell>FourTell_Recommend_Block_Catalog_Product_List_Upsell</product_list_upsell>
|
30 |
+
</rewrite>
|
31 |
+
</catalog>
|
32 |
+
|
33 |
+
<checkout>
|
34 |
+
<rewrite>
|
35 |
+
<cart_crosssell>FourTell_Recommend_Block_Checkout_Cart_Crosssellcommunity</cart_crosssell>
|
36 |
+
</rewrite>
|
37 |
+
</checkout>
|
38 |
+
|
39 |
+
<!-- Enterprise Edition -->
|
40 |
+
<enterprise_targetrule>
|
41 |
+
<rewrite>
|
42 |
+
<catalog_product_list_related>FourTell_Recommend_Block_Catalog_Product_List_Related</catalog_product_list_related>
|
43 |
+
<catalog_product_list_upsell>FourTell_Recommend_Block_Catalog_Product_List_Upsell</catalog_product_list_upsell>
|
44 |
+
<checkout_cart_crosssell>FourTell_Recommend_Block_Checkout_Cart_Crosssellenterprise</checkout_cart_crosssell>
|
45 |
+
</rewrite>
|
46 |
+
</enterprise_targetrule>
|
47 |
+
</blocks>
|
48 |
+
|
49 |
+
<helpers>
|
50 |
+
<recommend>
|
51 |
+
<class>FourTell_Recommend_Helper</class>
|
52 |
+
</recommend>
|
53 |
+
</helpers>
|
54 |
+
</global>
|
55 |
+
|
56 |
+
<admin>
|
57 |
+
<routers>
|
58 |
+
<recommend>
|
59 |
+
<use>admin</use>
|
60 |
+
<args>
|
61 |
+
<module>FourTell_Recommend</module>
|
62 |
+
<frontName>recommend</frontName>
|
63 |
+
</args>
|
64 |
+
</recommend>
|
65 |
+
</routers>
|
66 |
+
</admin>
|
67 |
+
|
68 |
+
<frontend>
|
69 |
+
<layout>
|
70 |
+
<updates>
|
71 |
+
<recommend>
|
72 |
+
<file>recommend.xml</file>
|
73 |
+
</recommend>
|
74 |
+
</updates>
|
75 |
+
</layout>
|
76 |
+
</frontend>
|
77 |
+
|
78 |
+
<adminhtml>
|
79 |
+
<translate>
|
80 |
+
<modules>
|
81 |
+
<mage_adminhtml>
|
82 |
+
<files>
|
83 |
+
<recommend>FourTell_Recommend.csv</recommend>
|
84 |
+
</files>
|
85 |
+
</mage_adminhtml>
|
86 |
+
</modules>
|
87 |
+
</translate>
|
88 |
+
|
89 |
+
<menu>
|
90 |
+
<catalog>
|
91 |
+
<children>
|
92 |
+
<recommend_adminform translate="title" module="recommend">
|
93 |
+
<title>4-Tell Recommendations</title>
|
94 |
+
<action>recommend/adminhtml_uploadform</action>
|
95 |
+
</recommend_adminform>
|
96 |
+
</children>
|
97 |
+
</catalog>
|
98 |
+
</menu>
|
99 |
+
|
100 |
+
<acl>
|
101 |
+
<resources>
|
102 |
+
<admin>
|
103 |
+
<children>
|
104 |
+
<catalog>
|
105 |
+
<children>
|
106 |
+
<recommend_adminform>
|
107 |
+
<title>4-Tell Recommendations</title>
|
108 |
+
</recommend_adminform>
|
109 |
+
</children>
|
110 |
+
</catalog>
|
111 |
+
</children>
|
112 |
+
</admin>
|
113 |
+
</resources>
|
114 |
+
</acl>
|
115 |
+
|
116 |
+
<acl>
|
117 |
+
<resources>
|
118 |
+
<admin>
|
119 |
+
<children>
|
120 |
+
<system>
|
121 |
+
<children>
|
122 |
+
<config>
|
123 |
+
<children>
|
124 |
+
<recommend>
|
125 |
+
<title>4-Tell Recommendation Service</title>
|
126 |
+
</recommend>
|
127 |
+
</children>
|
128 |
+
</config>
|
129 |
+
</children>
|
130 |
+
</system>
|
131 |
+
</children>
|
132 |
+
</admin>
|
133 |
+
</resources>
|
134 |
+
</acl>
|
135 |
+
|
136 |
+
<layout>
|
137 |
+
<updates>
|
138 |
+
<recommend>
|
139 |
+
<file>recommend.xml</file>
|
140 |
+
</recommend>
|
141 |
+
</updates>
|
142 |
+
</layout>
|
143 |
+
</adminhtml>
|
144 |
+
|
145 |
+
<crontab>
|
146 |
+
<jobs>
|
147 |
+
<recommend_uploader>
|
148 |
+
<schedule><cron_expr>* * * * *</cron_expr></schedule>
|
149 |
+
<run><model>recommend/observer::uploadData</model></run>
|
150 |
+
</recommend_uploader>
|
151 |
+
</jobs>
|
152 |
+
</crontab>
|
153 |
+
|
154 |
+
<default>
|
155 |
+
<recommend>
|
156 |
+
<config>
|
157 |
+
<enabled>1</enabled>
|
158 |
+
<extensionversion>1.2.8</extensionversion>
|
159 |
+
<minlikelihood>3</minlikelihood>
|
160 |
+
<mincommon>2</mincommon>
|
161 |
+
<maxsalesdataageinmonths>18</maxsalesdataageinmonths>
|
162 |
+
</config>
|
163 |
+
|
164 |
+
<display_recommendation>
|
165 |
+
<numupsell>3</numupsell>
|
166 |
+
<numcrosssell>3</numcrosssell>
|
167 |
+
<numrelated>3</numrelated>
|
168 |
+
</display_recommendation>
|
169 |
+
</recommend>
|
170 |
+
</default>
|
171 |
+
|
172 |
+
</config>
|
app/code/community/FourTell/Recommend/etc/system.xml
ADDED
@@ -0,0 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<sections>
|
4 |
+
<recommend translate="label" module="recommend">
|
5 |
+
<label>4-Tell Recommendation Service</label>
|
6 |
+
<tab>service</tab>
|
7 |
+
<frontend_type>text</frontend_type>
|
8 |
+
<sort_order>999</sort_order>
|
9 |
+
<show_in_default>1</show_in_default>
|
10 |
+
<show_in_website>1</show_in_website>
|
11 |
+
<show_in_store>1</show_in_store>
|
12 |
+
<groups>
|
13 |
+
<config translate="label">
|
14 |
+
<label>General Settings</label>
|
15 |
+
<comment>If you haven't already signed up for your Client Alias, please <a target="_blank" href="http://www.4-tell.com/signup">sign up now</a>!</comment>
|
16 |
+
<frontend_type>text</frontend_type>
|
17 |
+
<sort_order>10</sort_order>
|
18 |
+
<show_in_default>1</show_in_default>
|
19 |
+
<show_in_website>1</show_in_website>
|
20 |
+
<show_in_store>1</show_in_store>
|
21 |
+
<fields>
|
22 |
+
<upload translate="label tooltip">
|
23 |
+
<label>Data Upload/Settings</label>
|
24 |
+
<frontend_model>recommend/system_config_form_field_upload</frontend_model>
|
25 |
+
<sort_order>1</sort_order>
|
26 |
+
<show_in_default>1</show_in_default>
|
27 |
+
<show_in_website>1</show_in_website>
|
28 |
+
<show_in_store>1</show_in_store>
|
29 |
+
<tooltip>Click to configure upload settings and upload data</tooltip>
|
30 |
+
</upload>
|
31 |
+
|
32 |
+
<enabled translate="label tooltip">
|
33 |
+
<label>Enabled</label>
|
34 |
+
<frontend_type>select</frontend_type>
|
35 |
+
<source_model>recommend/system_config_source_enabled</source_model>
|
36 |
+
<backend_model>recommend/system_config_validation_clientid</backend_model>
|
37 |
+
<sort_order>3</sort_order>
|
38 |
+
<show_in_default>1</show_in_default>
|
39 |
+
<show_in_website>1</show_in_website>
|
40 |
+
<show_in_store>1</show_in_store>
|
41 |
+
<tooltip>Select yes to enable the 4-Tell extension or no disabled the extension.</tooltip>
|
42 |
+
</enabled>
|
43 |
+
|
44 |
+
<extensionversion translate="label tooltip">
|
45 |
+
<label>Extension Version</label>
|
46 |
+
<frontend_type>label</frontend_type>
|
47 |
+
<sort_order>5</sort_order>
|
48 |
+
<show_in_default>1</show_in_default>
|
49 |
+
<show_in_website>1</show_in_website>
|
50 |
+
<show_in_store>1</show_in_store>
|
51 |
+
<tooltip>The version number of the 4-Tell extension</tooltip>
|
52 |
+
</extensionversion>
|
53 |
+
|
54 |
+
<client_id translate="label tooltip">
|
55 |
+
<label>Client ID</label>
|
56 |
+
<frontend_type>text</frontend_type>
|
57 |
+
<backend_model>recommend/system_config_validation_clientid</backend_model>
|
58 |
+
<sort_order>10</sort_order>
|
59 |
+
<show_in_default>1</show_in_default>
|
60 |
+
<show_in_website>1</show_in_website>
|
61 |
+
<show_in_store>1</show_in_store>
|
62 |
+
<tooltip>Enter your Client ID, this is supplied to you by 4-Tell.</tooltip>
|
63 |
+
</client_id>
|
64 |
+
|
65 |
+
<owner translate="label tooltip">
|
66 |
+
<label>Owner</label>
|
67 |
+
<frontend_type>text</frontend_type>
|
68 |
+
<backend_model>recommend/system_config_validation_owner</backend_model>
|
69 |
+
<sort_order>20</sort_order>
|
70 |
+
<show_in_default>1</show_in_default>
|
71 |
+
<show_in_website>1</show_in_website>
|
72 |
+
<show_in_store>1</show_in_store>
|
73 |
+
<tooltip>Name of contact point (POC) for errors and issues.</tooltip>
|
74 |
+
</owner>
|
75 |
+
|
76 |
+
<email translate="label tooltip">
|
77 |
+
<label>Email</label>
|
78 |
+
<frontend_type>text</frontend_type>
|
79 |
+
<backend_model>recommend/system_config_validation_email</backend_model>
|
80 |
+
<sort_order>30</sort_order>
|
81 |
+
<show_in_default>1</show_in_default>
|
82 |
+
<show_in_website>1</show_in_website>
|
83 |
+
<show_in_store>1</show_in_store>
|
84 |
+
<tooltip>Email address for the POC.</tooltip>
|
85 |
+
</email>
|
86 |
+
|
87 |
+
<reportlevel translate="label tooltip">
|
88 |
+
<label>Report Level</label>
|
89 |
+
<frontend_type>select</frontend_type>
|
90 |
+
<source_model>recommend/system_config_source_reportlevel</source_model>
|
91 |
+
<sort_order>40</sort_order>
|
92 |
+
<show_in_default>1</show_in_default>
|
93 |
+
<show_in_website>1</show_in_website>
|
94 |
+
<show_in_store>1</show_in_store>
|
95 |
+
<tooltip>Types of messages (errors, warnings, etc.) that should be sent to the POC. The options (in decreasing order) are None, Error, Warning, Information, All. The default value is None. If a different level is chosen, all messages generated for your Client Alias at that level or higher will be emailed to the POC.</tooltip>
|
96 |
+
</reportlevel>
|
97 |
+
|
98 |
+
<resell translate="label tooltip">
|
99 |
+
<label>Resell</label>
|
100 |
+
<frontend_type>select</frontend_type>
|
101 |
+
<source_model>recommend/system_config_source_resell</source_model>
|
102 |
+
<sort_order>80</sort_order>
|
103 |
+
<show_in_default>1</show_in_default>
|
104 |
+
<show_in_website>1</show_in_website>
|
105 |
+
<show_in_store>1</show_in_store>
|
106 |
+
<tooltip>Whether previously purchased products should be offered to the same customer.</tooltip>
|
107 |
+
</resell>
|
108 |
+
|
109 |
+
<minlikelihood translate="label tooltip">
|
110 |
+
<label>Min Likelihood</label>
|
111 |
+
<frontend_type>text</frontend_type>
|
112 |
+
<backend_model>recommend/system_config_validation_minlikelihood</backend_model>
|
113 |
+
<sort_order>90</sort_order>
|
114 |
+
<show_in_default>1</show_in_default>
|
115 |
+
<show_in_website>1</show_in_website>
|
116 |
+
<show_in_store>1</show_in_store>
|
117 |
+
<tooltip>The minimum likelihood of purchase for a cross-sell or up-sell product to be included in the recommendation tables. In other words, products with a likelihood percentage below the minimum are not recommended, usually 5%</tooltip>
|
118 |
+
</minlikelihood>
|
119 |
+
|
120 |
+
<mincommon translate="label tooltip">
|
121 |
+
<label>Min Common</label>
|
122 |
+
<frontend_type>text</frontend_type>
|
123 |
+
<backend_model>recommend/system_config_validation_mincommon</backend_model>
|
124 |
+
<sort_order>100</sort_order>
|
125 |
+
<show_in_default>1</show_in_default>
|
126 |
+
<show_in_website>1</show_in_website>
|
127 |
+
<show_in_store>1</show_in_store>
|
128 |
+
<tooltip>The minimum number of common users for a cross-sell or up-sell product to be included in the recommendation tables. In other words, products with common users below the minimum are not included in the tables. Usually this is set to 2, such that product pairs bought by only 1 customer are not recommended.</tooltip>
|
129 |
+
</mincommon>
|
130 |
+
|
131 |
+
<mode translate="label tooltip">
|
132 |
+
<label>Mode</label>
|
133 |
+
<frontend_type>select</frontend_type>
|
134 |
+
<source_model>recommend/system_config_source_mode</source_model>
|
135 |
+
<sort_order>110</sort_order>
|
136 |
+
<show_in_default>1</show_in_default>
|
137 |
+
<show_in_website>1</show_in_website>
|
138 |
+
<show_in_store>1</show_in_store>
|
139 |
+
<tooltip>Select the mode Live to Test.</tooltip>
|
140 |
+
</mode>
|
141 |
+
|
142 |
+
<maxsalesdataageinmonths translate="label tooltip">
|
143 |
+
<label>Max Sales Data Age In Months</label>
|
144 |
+
<frontend_type>text</frontend_type>
|
145 |
+
<backend_model>recommend/system_config_validation_maxsalesdataageinmonths</backend_model>
|
146 |
+
<sort_order>140</sort_order>
|
147 |
+
<show_in_default>1</show_in_default>
|
148 |
+
<show_in_website>1</show_in_website>
|
149 |
+
<show_in_store>1</show_in_store>
|
150 |
+
<tooltip>The number of months of sales data to upload when uploading all sales data.</tooltip>
|
151 |
+
</maxsalesdataageinmonths>
|
152 |
+
</fields>
|
153 |
+
</config>
|
154 |
+
|
155 |
+
<display_recommendation translate="label">
|
156 |
+
<label>Display Recommendations</label>
|
157 |
+
<comment><?php echo "xyz"; ?></comment>
|
158 |
+
<frontend_type>text</frontend_type>
|
159 |
+
<sort_order>20</sort_order>
|
160 |
+
<show_in_default>1</show_in_default>
|
161 |
+
<show_in_website>1</show_in_website>
|
162 |
+
<show_in_store>1</show_in_store>
|
163 |
+
<fields>
|
164 |
+
<upsell translate="label tooltip">
|
165 |
+
<label>Upsell</label>
|
166 |
+
<frontend_type>select</frontend_type>
|
167 |
+
<source_model>recommend/system_config_source_upsell</source_model>
|
168 |
+
<sort_order>10</sort_order>
|
169 |
+
<show_in_default>1</show_in_default>
|
170 |
+
<show_in_website>1</show_in_website>
|
171 |
+
<show_in_store>1</show_in_store>
|
172 |
+
<tooltip>Retrieve recommended Upsell products from 4-Tell</tooltip>
|
173 |
+
</upsell>
|
174 |
+
<numupsell translate="label tooltip">
|
175 |
+
<label>Number of Recommendations</label>
|
176 |
+
<frontend_type>text</frontend_type>
|
177 |
+
<backend_model>recommend/system_config_validation_numupsell</backend_model>
|
178 |
+
<sort_order>15</sort_order>
|
179 |
+
<show_in_default>1</show_in_default>
|
180 |
+
<show_in_website>1</show_in_website>
|
181 |
+
<show_in_store>1</show_in_store>
|
182 |
+
<tooltip>How many recommended products to retrieve for Upsell</tooltip>
|
183 |
+
</numupsell>
|
184 |
+
|
185 |
+
<crosssell translate="label tooltip">
|
186 |
+
<label>Cross Sell</label>
|
187 |
+
<frontend_type>select</frontend_type>
|
188 |
+
<source_model>recommend/system_config_source_crosssell</source_model>
|
189 |
+
<sort_order>20</sort_order>
|
190 |
+
<show_in_default>1</show_in_default>
|
191 |
+
<show_in_website>1</show_in_website>
|
192 |
+
<show_in_store>1</show_in_store>
|
193 |
+
<tooltip>Retrieve recommended Upsell products from 4-Tell</tooltip>
|
194 |
+
</crosssell>
|
195 |
+
<numcrosssell translate="label tooltip">
|
196 |
+
<label>Number of Recommendations</label>
|
197 |
+
<frontend_type>text</frontend_type>
|
198 |
+
<backend_model>recommend/system_config_validation_numcrosssell</backend_model>
|
199 |
+
<sort_order>25</sort_order>
|
200 |
+
<show_in_default>1</show_in_default>
|
201 |
+
<show_in_website>1</show_in_website>
|
202 |
+
<show_in_store>1</show_in_store>
|
203 |
+
<tooltip>How many recommended products to retrieve for Cross Sell</tooltip>
|
204 |
+
</numcrosssell>
|
205 |
+
|
206 |
+
<related translate="label tooltip">
|
207 |
+
<label>Related</label>
|
208 |
+
<frontend_type>select</frontend_type>
|
209 |
+
<source_model>recommend/system_config_source_related</source_model>
|
210 |
+
<sort_order>30</sort_order>
|
211 |
+
<show_in_default>1</show_in_default>
|
212 |
+
<show_in_website>1</show_in_website>
|
213 |
+
<show_in_store>1</show_in_store>
|
214 |
+
<tooltip>Retrieve recommended Upsell products from 4-Tell</tooltip>
|
215 |
+
</related>
|
216 |
+
<numrelated translate="label tooltip">
|
217 |
+
<label>Number of Recommendations</label>
|
218 |
+
<frontend_type>text</frontend_type>
|
219 |
+
<backend_model>recommend/system_config_validation_numrelated</backend_model>
|
220 |
+
<sort_order>35</sort_order>
|
221 |
+
<show_in_default>1</show_in_default>
|
222 |
+
<show_in_website>1</show_in_website>
|
223 |
+
<show_in_store>1</show_in_store>
|
224 |
+
<tooltip>How many recommended products to retrieve for Related products</tooltip>
|
225 |
+
</numrelated>
|
226 |
+
</fields>
|
227 |
+
</display_recommendation>
|
228 |
+
|
229 |
+
<gogle_analytics translate="label">
|
230 |
+
<label>Google Analytics</label>
|
231 |
+
<frontend_type>text</frontend_type>
|
232 |
+
<sort_order>30</sort_order>
|
233 |
+
<show_in_default>1</show_in_default>
|
234 |
+
<show_in_website>1</show_in_website>
|
235 |
+
<show_in_store>1</show_in_store>
|
236 |
+
<fields>
|
237 |
+
<gaenabled translate="label tooltip">
|
238 |
+
<label>Google Analytics enabled</label>
|
239 |
+
<frontend_type>label</frontend_type>
|
240 |
+
<frontend_model>recommend/system_config_google_analytics_status</frontend_model>
|
241 |
+
<sort_order>5</sort_order>
|
242 |
+
<show_in_default>1</show_in_default>
|
243 |
+
<show_in_website>1</show_in_website>
|
244 |
+
<show_in_store>1</show_in_store>
|
245 |
+
<tooltip>Shows if Google Analytics really enabled in the system configuration</tooltip>
|
246 |
+
</gaenabled>
|
247 |
+
<ga_code translate="label tooltip">
|
248 |
+
<label>Google Account ID</label>
|
249 |
+
<frontend_type>label</frontend_type>
|
250 |
+
<frontend_model>recommend/system_config_google_analytics_code</frontend_model>
|
251 |
+
<sort_order>20</sort_order>
|
252 |
+
<show_in_default>1</show_in_default>
|
253 |
+
<show_in_website>1</show_in_website>
|
254 |
+
<show_in_store>1</show_in_store>
|
255 |
+
<tooltip>Your web property ID (UA-XXXXX-X)</tooltip>
|
256 |
+
</ga_code>
|
257 |
+
<ga_change translate="label tooltip">
|
258 |
+
<label>Google Credentials</label>
|
259 |
+
<frontend_type>label</frontend_type>
|
260 |
+
<frontend_model>recommend/system_config_google_analytics_change</frontend_model>
|
261 |
+
<sort_order>30</sort_order>
|
262 |
+
<show_in_default>1</show_in_default>
|
263 |
+
<show_in_website>1</show_in_website>
|
264 |
+
<show_in_store>1</show_in_store>
|
265 |
+
<tooltip>You can change your google analytics settings here</tooltip>
|
266 |
+
</ga_change>
|
267 |
+
</fields>
|
268 |
+
</gogle_analytics>
|
269 |
+
<cron_jobs translate="label">
|
270 |
+
<label>Cron Jobs</label>
|
271 |
+
<frontend_type>text</frontend_type>
|
272 |
+
<sort_order>40</sort_order>
|
273 |
+
<show_in_default>1</show_in_default>
|
274 |
+
<show_in_website>1</show_in_website>
|
275 |
+
<show_in_store>1</show_in_store>
|
276 |
+
<fields>
|
277 |
+
<sales translate="label tooltip">
|
278 |
+
<label>Sales data</label>
|
279 |
+
<frontend_type>select</frontend_type>
|
280 |
+
<source_model>
|
281 |
+
recommend/upload_frequency
|
282 |
+
</source_model>
|
283 |
+
<sort_order>10</sort_order>
|
284 |
+
<show_in_default>1</show_in_default>
|
285 |
+
<show_in_website>1</show_in_website>
|
286 |
+
<show_in_store>1</show_in_store>
|
287 |
+
<tooltip>How often we should start Sales data upload process</tooltip>
|
288 |
+
</sales>
|
289 |
+
<catalog translate="label tooltip">
|
290 |
+
<label>Catalog data</label>
|
291 |
+
<frontend_type>select</frontend_type>
|
292 |
+
<source_model>recommend/upload_frequency</source_model>
|
293 |
+
<sort_order>20</sort_order>
|
294 |
+
<show_in_default>1</show_in_default>
|
295 |
+
<show_in_website>1</show_in_website>
|
296 |
+
<show_in_store>1</show_in_store>
|
297 |
+
<tooltip>How often we should start Catalog data upload process</tooltip>
|
298 |
+
</catalog>
|
299 |
+
</fields>
|
300 |
+
</cron_jobs>
|
301 |
+
</groups>
|
302 |
+
</recommend>
|
303 |
+
</sections>
|
304 |
+
</config>
|
app/code/community/FourTell/Recommend/etc/upload.xml
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<upload_options>
|
3 |
+
<exclude_options/>
|
4 |
+
<replace_options/>
|
5 |
+
<upload_sales_data>All</upload_sales_data>
|
6 |
+
<upload_replacement_data>None</upload_replacement_data>
|
7 |
+
<upload_product_data>Yes</upload_product_data>
|
8 |
+
<upload_exclusion_data>No</upload_exclusion_data>
|
9 |
+
<replace_catalog_old_field>sku</replace_catalog_old_field>
|
10 |
+
<replace_catalog_new_field>entity_id</replace_catalog_new_field>
|
11 |
+
<showUploadDetails>Yes</showUploadDetails>
|
12 |
+
</upload_options>
|
app/code/community/FourTell/Recommend/etc/widget.xml
ADDED
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<widgets>
|
3 |
+
<fourtell_widget type="recommend/widget">
|
4 |
+
<name>4-Tell: Recommendation Widget</name>
|
5 |
+
<description type="desc">Adds Recommendation Products</description>
|
6 |
+
<is_email_compatible>1</is_email_compatible>
|
7 |
+
|
8 |
+
<parameters>
|
9 |
+
<recommendation_type>
|
10 |
+
<required>1</required>
|
11 |
+
<visible>1</visible>
|
12 |
+
<label>Type of Recommendtions</label>
|
13 |
+
<description>Type of Recommendtion products to retrieve from 4-Tell Recommendation Service</description>
|
14 |
+
<type>select</type>
|
15 |
+
|
16 |
+
<values>
|
17 |
+
<one translate="label">
|
18 |
+
<value>topsellers</value>
|
19 |
+
<label>Top Sellers</label>
|
20 |
+
</one>
|
21 |
+
<two translate="label">
|
22 |
+
<value>Personalized</value>
|
23 |
+
<label>Personalized</label>
|
24 |
+
</two>
|
25 |
+
<three translate="label">
|
26 |
+
<value>crosssell</value>
|
27 |
+
<label>Cross Sell</label>
|
28 |
+
</three>
|
29 |
+
</values>
|
30 |
+
</recommendation_type>
|
31 |
+
|
32 |
+
<num_recommendations>
|
33 |
+
<required>1</required>
|
34 |
+
<visible>1</visible>
|
35 |
+
<label>Number of Products</label>
|
36 |
+
<description>Number of products to retrieve from 4-Tell Recommendation Service</description>
|
37 |
+
<type>text</type>
|
38 |
+
</num_recommendations>
|
39 |
+
|
40 |
+
<in_line>
|
41 |
+
<required>1</required>
|
42 |
+
<visible>1</visible>
|
43 |
+
<label>Number of Products per Line</label>
|
44 |
+
<description>Number of products per one line</description>
|
45 |
+
<type>text</type>
|
46 |
+
</in_line>
|
47 |
+
|
48 |
+
<slider_enable>
|
49 |
+
<required>1</required>
|
50 |
+
<visible>1</visible>
|
51 |
+
<label>Enable Slider</label>
|
52 |
+
<description>Enable or disable slider for product blocks</description>
|
53 |
+
<type>select</type>
|
54 |
+
<value>1</value>
|
55 |
+
<values>
|
56 |
+
<default translate="label">
|
57 |
+
<value>1</value>
|
58 |
+
<label>Yes</label>
|
59 |
+
</default>
|
60 |
+
<list translate="label">
|
61 |
+
<value>0</value>
|
62 |
+
<label>No</label>
|
63 |
+
</list>
|
64 |
+
</values>
|
65 |
+
</slider_enable>
|
66 |
+
|
67 |
+
<heading>
|
68 |
+
<required>0</required>
|
69 |
+
<visible>1</visible>
|
70 |
+
<label>Heading for Products</label>
|
71 |
+
<description>Heading to display above products</description>
|
72 |
+
<type>text</type>
|
73 |
+
</heading>
|
74 |
+
|
75 |
+
<cssclass>
|
76 |
+
<required>0</required>
|
77 |
+
<visible>1</visible>
|
78 |
+
<label>Widget CSS Class</label>
|
79 |
+
<description>Override default css class with your own</description>
|
80 |
+
<type>text</type>
|
81 |
+
</cssclass>
|
82 |
+
|
83 |
+
<gafunction>
|
84 |
+
<required>0</required>
|
85 |
+
<visible>1</visible>
|
86 |
+
<label>Google Analytics Function</label>
|
87 |
+
<description>The JavaScript function for Google Analytics tracking</description>
|
88 |
+
<type>text</type>
|
89 |
+
</gafunction>
|
90 |
+
|
91 |
+
<template>
|
92 |
+
<required>1</required>
|
93 |
+
<visible>1</visible>
|
94 |
+
<label>Template</label>
|
95 |
+
<type>select</type>
|
96 |
+
<value>catalog/product/widget/new/content/new_grid.phtml</value>
|
97 |
+
<values>
|
98 |
+
<default translate="label">
|
99 |
+
<value>catalog/product/widget/new/content/new_grid.phtml</value>
|
100 |
+
<label>New Products Grid Template</label>
|
101 |
+
</default>
|
102 |
+
<list translate="label">
|
103 |
+
<value>catalog/product/widget/new/content/new_list.phtml</value>
|
104 |
+
<label>New Products List Template</label>
|
105 |
+
</list>
|
106 |
+
</values>
|
107 |
+
</template>
|
108 |
+
|
109 |
+
</parameters>
|
110 |
+
</fourtell_widget>
|
111 |
+
</widgets>
|
app/design/adminhtml/default/default/layout/recommend.xml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<layout>
|
3 |
+
<recommend_adminhtml_uploadform_index>
|
4 |
+
<update handle="recommend_uploadform_index"/>
|
5 |
+
|
6 |
+
<reference name="content">
|
7 |
+
<block type="adminhtml/template" name="uploadform" template="recommend/uploadform.phtml"/>
|
8 |
+
</reference>
|
9 |
+
</recommend_adminhtml_uploadform_index>
|
10 |
+
</layout>
|
app/design/adminhtml/default/default/template/recommend/uploadform.phtml
ADDED
@@ -0,0 +1,625 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<style>
|
2 |
+
#loading-mask .loader {
|
3 |
+
position: inherit !important;
|
4 |
+
top:20%;
|
5 |
+
}
|
6 |
+
</style>
|
7 |
+
<?php
|
8 |
+
$ex = Mage::getSingleton('FourTell_Recommend_Model_UploadSetting')->load();
|
9 |
+
$attrs = Mage::getSingleton('FourTell_Recommend_Adminhtml_UploadformController');
|
10 |
+
$attrs->__construct(Mage::app()->getRequest());
|
11 |
+
$attrs->getProductAttributes();
|
12 |
+
$cfgLink = Mage::helper('recommend')->getCfgLink();
|
13 |
+
$comps = Mage::helper('recommend')->getCompsArray();
|
14 |
+
$options = Mage::helper('recommend')->getOptionsArray();
|
15 |
+
$rowIdx = 1;
|
16 |
+
?>
|
17 |
+
|
18 |
+
<form id="edit_form" name="edit_form" method="post" action="">
|
19 |
+
<input name="form_key" type="hidden" value="<?php echo Mage::getSingleton('core/session')->getFormKey() ?>" />
|
20 |
+
<input type="hidden" id="what_data" name="what_data" value="" />
|
21 |
+
|
22 |
+
<div class="content-headerx" style="padding-bottom: 20px;">
|
23 |
+
<table cellspacing="0" class="grid-header">
|
24 |
+
<tr>
|
25 |
+
<td><h3>4-Tell Recommend</h3></td>
|
26 |
+
</tr>
|
27 |
+
<tr>
|
28 |
+
<td>
|
29 |
+
Select the data to be uploaded and the press the <b>Upload Data</b> button.
|
30 |
+
If this is your first upload, select "All" sales data.
|
31 |
+
</td>
|
32 |
+
</tr>
|
33 |
+
<tr>
|
34 |
+
<td>
|
35 |
+
<a href="<?php echo $cfgLink; ?>"><?php echo $this->__('Go to 4-Tell System Configuration'); ?></a>
|
36 |
+
</td>
|
37 |
+
</tr>
|
38 |
+
</table>
|
39 |
+
</div>
|
40 |
+
|
41 |
+
|
42 |
+
<div class="content-header">
|
43 |
+
<table cellspacing="0" class="grid-header">
|
44 |
+
<tr>
|
45 |
+
<td><h3>Upload Options</h3></td>
|
46 |
+
<td class="a-right">
|
47 |
+
<button id="saveButton" onclick="$('what_data').setAttribute('value', 'save_settings'); editForm.submit();" class="scalable" type="button" value="save settings" style="display: none;"><span>Save Settings</span></button>
|
48 |
+
<?php if (Mage::helper('recommend')->isEnabled()) { ?>
|
49 |
+
<button id="uploadButton" onclick="$('what_data').setAttribute('value', 'upload_data'); editForm.submit();" class="scalable" type="button" value="upload_data" style="display: none;"><span>Upload Data</span></button>
|
50 |
+
<?php } ?>
|
51 |
+
<button id="ajaxButton" onclick="javascript:ajaxUpload(0);" class="scalable" type="button" value="Upload Data" style="display: none;"><span>Upload Data</span></button>
|
52 |
+
</td>
|
53 |
+
</tr>
|
54 |
+
</table>
|
55 |
+
</div>
|
56 |
+
<div class="content-header" style="border: 0px !important;">
|
57 |
+
<table cellspacing="0" class="grid-header" id="sales_options">
|
58 |
+
<tbody>
|
59 |
+
<tr>
|
60 |
+
<td style="width: 200px; white-space: nowrap;"><h3>Upload Sales Data</h3></td>
|
61 |
+
<td>
|
62 |
+
<select id="upload_sales_data" name="upload_sales_data" style="width: 120px;">
|
63 |
+
<option value="All" <?php if (trim($ex['upload_sales_data']) == "All") { echo 'selected="selected"'; } ?>>All</option>
|
64 |
+
<option value="New" <?php if (trim($ex['upload_sales_data']) == "New") { echo 'selected="selected"'; } ?>>New</option>
|
65 |
+
<option value="None" <?php if (trim($ex['upload_sales_data']) == "None") { echo 'selected="selected"'; } ?>>None</option>
|
66 |
+
</select>
|
67 |
+
</td>
|
68 |
+
<td> </td>
|
69 |
+
</tr>
|
70 |
+
|
71 |
+
<tr>
|
72 |
+
<td style="width: 200px; white-space: nowrap;"><h3>Upload Catalog Data</h3></td>
|
73 |
+
<td>
|
74 |
+
<select id="upload_product_data" name="upload_product_data" style="width: 120px;">
|
75 |
+
<option value="Yes" <?php if (trim($ex['upload_product_data']) == "Yes") { echo 'selected="selected"'; } ?>>Yes</option>
|
76 |
+
<option value="No" <?php if (trim($ex['upload_product_data']) == "No") { echo 'selected="selected"'; } ?>>No</option>
|
77 |
+
</select>
|
78 |
+
</td>
|
79 |
+
<td> </td>
|
80 |
+
</tr>
|
81 |
+
|
82 |
+
<tr>
|
83 |
+
<td style="width: 200px; white-space: nowrap;"><h3>Enable Exclusion Data</h3></td>
|
84 |
+
<td>
|
85 |
+
<select name="upload_exclusion_data" id="upload_exclusion_data" style="width: 120px;">
|
86 |
+
<option value="No" <?php if (trim($ex['upload_exclusion_data']) == "No") { echo 'selected="selected"'; } ?>>No</option>
|
87 |
+
<option value="Yes" <?php if (trim($ex['upload_exclusion_data']) == "Yes") { echo 'selected="selected"'; } ?>>Yes</option>
|
88 |
+
</select>
|
89 |
+
|
90 |
+
<div class="content-header" id="exclude_table_container" <?php if (trim($ex['upload_exclusion_data']) == "No") { ?> style="display: none;" <?php } ?>>
|
91 |
+
<table cellspacing="0" class="grid-header" id="exclude_table">
|
92 |
+
<tbody>
|
93 |
+
<tr>
|
94 |
+
<td><h3>Field</h3></td>
|
95 |
+
<td><h3>Comparison</h3></td>
|
96 |
+
<td><h3>Value</h3></td>
|
97 |
+
<td> </td>
|
98 |
+
</tr>
|
99 |
+
|
100 |
+
<?php
|
101 |
+
$rowIdx = 1;
|
102 |
+
foreach ($ex['exclude_options'] as $o) {
|
103 |
+
?>
|
104 |
+
<tr class="excludeRow" id="excludeRow_<?php echo $rowIdx; ?>">
|
105 |
+
<td>
|
106 |
+
<select id="exclude_field" name="excludeField_Name_<?php echo $rowIdx; ?>">
|
107 |
+
<option value=""></option>
|
108 |
+
<?php foreach ($attrs as $v): ?>
|
109 |
+
<option value="<?php echo htmlspecialchars($v['name']); ?>" <?php if($v['name']==$o['field']): ?>selected="selected"<?php endif ?>><?php echo htmlspecialchars(str_replace('\'', '', $v['label'])); ?></option>
|
110 |
+
<?php endforeach ?>
|
111 |
+
</select>
|
112 |
+
</td>
|
113 |
+
<td>
|
114 |
+
<select id="exclude_field_compare" name="excludeField_Compare_<?php echo $rowIdx; ?>" style="width: 180px;">
|
115 |
+
<?php
|
116 |
+
foreach ($comps as $k => $v)
|
117 |
+
{
|
118 |
+
$selected = "";
|
119 |
+
if ($k == $o['compare'])
|
120 |
+
{
|
121 |
+
$selected = "selected";
|
122 |
+
}
|
123 |
+
?>
|
124 |
+
<option value="<?php echo $k; ?>" <?php if ($selected != "") { ?>selected="selected"<?php } ?>><?php echo $v; ?></option>
|
125 |
+
<?php
|
126 |
+
}
|
127 |
+
?>
|
128 |
+
</select>
|
129 |
+
</td>
|
130 |
+
<td><input id="exclude_field_value" name="excludeField_Value_<?php echo $rowIdx; ?>" type="text" size="40" value="<?php echo $o['value']; ?>" /></td>
|
131 |
+
<td class="a-right">
|
132 |
+
<button onclick="javascript:removeExcludeRow(<?php echo $rowIdx; ?>);" class="scalable" type="button" value=" x "><span> x </span></button>
|
133 |
+
</td>
|
134 |
+
</tr>
|
135 |
+
<?php
|
136 |
+
$rowIdx++;
|
137 |
+
}
|
138 |
+
?>
|
139 |
+
</tbody>
|
140 |
+
</table>
|
141 |
+
</div>
|
142 |
+
</td>
|
143 |
+
</tr>
|
144 |
+
|
145 |
+
<tr>
|
146 |
+
<td style="width: 200px; white-space: nowrap;"><h3>Enable Replacement Data</h3></td>
|
147 |
+
<td>
|
148 |
+
<select name="upload_replacement_data" id="upload_replacement_data" style="width: 120px;">
|
149 |
+
<option value="None" <?php if (trim($ex['upload_replacement_data']) == "None") { echo 'selected="selected"'; } ?>>None</option>
|
150 |
+
<option value="Entire Catalog" <?php if (trim($ex['upload_replacement_data']) == "Entire Catalog") { echo 'selected="selected"'; } ?>>Entire Catalog</option>
|
151 |
+
<option value="Individual Items" <?php if (trim($ex['upload_replacement_data']) == "Individual Items") { echo 'selected="selected"'; } ?>>Individual Items</option>
|
152 |
+
</select>
|
153 |
+
|
154 |
+
<div class="content-header" id="replacement_catalog_table_container" <?php if (trim($ex['upload_replacement_data']) != "Entire Catalog") { ?> style="display: none;" <?php } ?>>
|
155 |
+
<table cellspacing="0" class="grid-header" id="replacement_table">
|
156 |
+
<tr class="excludeRow" id="replacement_header">
|
157 |
+
<td><h3>Old Field</h3></td>
|
158 |
+
<td><h3>New Field</h3></td>
|
159 |
+
<td> </td>
|
160 |
+
</tr>
|
161 |
+
<tr class="excludeRow" id="replacement_data">
|
162 |
+
<td style="padding-right: 20px;">
|
163 |
+
<select name="replace_catalog_old_field">
|
164 |
+
<option value=""></option>
|
165 |
+
<?php foreach ($attrs as $v): ?>
|
166 |
+
<?php if(strlen(trim($v['label']))==0) continue; ?>
|
167 |
+
<option value="<?php echo htmlspecialchars($v['name']); ?>" <?php if($v['name']==$ex['replace_catalog_old_field']): ?>selected="selected"<?php endif ?>><?php echo htmlspecialchars(str_replace('\'', '', $v['label'])); ?></option>
|
168 |
+
<?php endforeach ?>
|
169 |
+
</select>
|
170 |
+
</td>
|
171 |
+
<td style="padding-right: 20px;">
|
172 |
+
<select name="replace_catalog_new_field">
|
173 |
+
<option value=""></option>
|
174 |
+
<?php foreach ($attrs as $v): ?>
|
175 |
+
<?php if(strlen(trim($v['label']))==0) continue; ?>
|
176 |
+
<option value="<?php echo htmlspecialchars($v['name']); ?>" <?php if($v['name']==$ex['replace_catalog_new_field']): ?>selected="selected"<?php endif ?>><?php echo htmlspecialchars(str_replace('\'', '', $v['label'])); ?></option>
|
177 |
+
<?php endforeach ?>
|
178 |
+
</select>
|
179 |
+
</td>
|
180 |
+
<td style="width: 100%;"> </td>
|
181 |
+
</tr>
|
182 |
+
</table>
|
183 |
+
</div>
|
184 |
+
|
185 |
+
<div class="content-header" id="replacement_item_table_container" <?php if (trim($ex['upload_replacement_data']) != "Individual Items") { ?> style="display: none;" <?php } ?>>
|
186 |
+
<table cellspacing="0" class="grid-header" id="replace_table">
|
187 |
+
<tbody>
|
188 |
+
<tr>
|
189 |
+
<td><h3>Old ID</h3></td>
|
190 |
+
<td><h3>New ID</h3></td>
|
191 |
+
<td> </td>
|
192 |
+
</tr>
|
193 |
+
|
194 |
+
<?php
|
195 |
+
$repIdx = 1;
|
196 |
+
foreach ($ex['replace_options'] as $o) {
|
197 |
+
?>
|
198 |
+
<tr class="replaceRow" id="replaceRow_<?php echo $repIdx; ?>">
|
199 |
+
<td>
|
200 |
+
<select id="replace_field_oldid" name="replaceField_oldid_<?php echo $repIdx; ?>">
|
201 |
+
<option value=""></option>
|
202 |
+
<?php foreach ($attrs as $v): ?>
|
203 |
+
<?php if(strlen(trim($v['label']))==0) continue; ?>
|
204 |
+
<option value="<?php echo htmlspecialchars($v['name']); ?>" <?php if($v['name']==$o['oldid']): ?>selected="selected"<?php endif ?>><?php echo htmlspecialchars(str_replace('\'', '', $v['label'])); ?></option>
|
205 |
+
<?php endforeach ?>
|
206 |
+
</select>
|
207 |
+
</td>
|
208 |
+
<td>
|
209 |
+
<select id="replace_field_newid" name="replaceField_newid_<?php echo $repIdx; ?>">
|
210 |
+
<option value=""></option>
|
211 |
+
<?php foreach ($attrs as $v): ?>
|
212 |
+
<?php if(strlen(trim($v['label']))==0) continue; ?>
|
213 |
+
<option value="<?php echo htmlspecialchars($v['name']); ?>" <?php if($v['name']==$o['newid']): ?>selected="selected"<?php endif ?>><?php echo htmlspecialchars(str_replace('\'', '', $v['label'])); ?></option>
|
214 |
+
<?php endforeach ?>
|
215 |
+
</select>
|
216 |
+
</td>
|
217 |
+
<td class="a-right">
|
218 |
+
<button onclick="javascript:removeReplaceRow(<?php echo $repIdx; ?>);" class="scalable" type="button" value=" x "><span> x </span></button>
|
219 |
+
</td>
|
220 |
+
</tr>
|
221 |
+
<?php
|
222 |
+
$repIdx++;
|
223 |
+
}
|
224 |
+
?>
|
225 |
+
</tbody>
|
226 |
+
</table>
|
227 |
+
</div>
|
228 |
+
</td>
|
229 |
+
</tr>
|
230 |
+
<tr>
|
231 |
+
<td style="width: 200px; white-space: nowrap;"><h3>Show Upload Details</h3></td>
|
232 |
+
<td>
|
233 |
+
<select name="showUploadDetails" id="showUploadDetails" style="width: 120px;">
|
234 |
+
<option value="No" <?php if (trim($ex['showUploadDetails']) == "No") { echo 'selected="selected"'; } ?>>No</option>
|
235 |
+
<option value="Yes" <?php if (trim($ex['showUploadDetails']) == "Yes") { echo 'selected="selected"'; } ?>>Yes</option>
|
236 |
+
</select>
|
237 |
+
</td>
|
238 |
+
</tr>
|
239 |
+
</tbody>
|
240 |
+
</table>
|
241 |
+
</div>
|
242 |
+
</form>
|
243 |
+
|
244 |
+
|
245 |
+
<div id="loading-mask" style="display:none">
|
246 |
+
<p class="loader" id="loading_mask_loader">
|
247 |
+
<img src="<?php echo Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB); ?>/skin/adminhtml/default/default/images/ajax-loader-tr.gif" alt="Loading..."/>
|
248 |
+
<span id="loading-msg">Uploading data, please wait...</span>
|
249 |
+
</p>
|
250 |
+
</div>
|
251 |
+
|
252 |
+
|
253 |
+
<script type="text/javascript">
|
254 |
+
var editForm = new varienForm('edit_form');
|
255 |
+
var numExs = <?php echo count($ex['exclude_options']); ?>;
|
256 |
+
|
257 |
+
function removeExcludeRow(row) {
|
258 |
+
var rowEl = $$('#excludeRow_'+row);
|
259 |
+
rowEl.each(function(el) {
|
260 |
+
el.remove();
|
261 |
+
});
|
262 |
+
|
263 |
+
setSaveButton('block');
|
264 |
+
}
|
265 |
+
|
266 |
+
function makeExcludeSelect(id) {
|
267 |
+
var sel = new Element('select', {'style': 'width: 180px'});
|
268 |
+
sel.writeAttribute('name', 'excludeField_Compare_'+id);
|
269 |
+
|
270 |
+
<?php
|
271 |
+
foreach ($comps as $k => $v) {
|
272 |
+
?>
|
273 |
+
sel.insert(new Element('option', {'value': '<?php echo $k; ?>', text: '<?php echo $v; ?>'}).update('<?php echo $v; ?>'));
|
274 |
+
<?php } ?>
|
275 |
+
|
276 |
+
return sel;
|
277 |
+
}
|
278 |
+
|
279 |
+
function makeExcludeButton(id) {
|
280 |
+
var js = 'javascript:addExcludeRow(true); setSaveButton("block");';
|
281 |
+
var but = new Element('button', {'id': 'excludeFieldButton_'+id, 'onclick': js, 'class': 'scalable', 'type': 'button', 'value': ' + '});
|
282 |
+
|
283 |
+
but.insert(new Element('span').update(' + '));
|
284 |
+
|
285 |
+
return but;
|
286 |
+
}
|
287 |
+
|
288 |
+
function swapExcludeButton(id) {
|
289 |
+
var buts = $$('#excludeFieldButton_'+id);
|
290 |
+
buts.each(function(but) {
|
291 |
+
but.down().update(' x ');
|
292 |
+
but.setAttribute('onclick', 'javascript:removeExcludeRow('+id+');');
|
293 |
+
});
|
294 |
+
}
|
295 |
+
|
296 |
+
function addExcludeRow(doSwap) {
|
297 |
+
numExs++;
|
298 |
+
|
299 |
+
$$('#exclude_table tbody').each(function(tbl) {
|
300 |
+
var tr = new Element('tr', {'id': 'excludeRow_' + numExs, 'class': 'excludeRow'});
|
301 |
+
|
302 |
+
var newEl = new Element('select');
|
303 |
+
newEl.writeAttribute('id', 'excludeField_Name_'+numExs);
|
304 |
+
newEl.writeAttribute('name', 'excludeField_Name_'+numExs);
|
305 |
+
var option = new Element("option");
|
306 |
+
option.text = '';
|
307 |
+
option.value = '';
|
308 |
+
newEl.insert(option);
|
309 |
+
<?php
|
310 |
+
foreach ($attrs as $k => $v){
|
311 |
+
if(strlen(trim($v['label']))=='') continue;
|
312 |
+
?>
|
313 |
+
var option = new Element("option");
|
314 |
+
option.text = '<?php echo htmlspecialchars(str_replace('\'', '', $v['label'])); ?>';
|
315 |
+
option.value = '<?php echo htmlspecialchars($v['name']); ?>';
|
316 |
+
newEl.insert(option);
|
317 |
+
<?php
|
318 |
+
}
|
319 |
+
?>
|
320 |
+
tr.insert(new Element('td').update(newEl));
|
321 |
+
tr.insert(new Element('td').update(makeExcludeSelect(numExs)));
|
322 |
+
var newEl = new Element('input', {'type': 'text', 'size': '40' });
|
323 |
+
newEl.writeAttribute('id', 'excludeField_Value_'+numExs);
|
324 |
+
newEl.writeAttribute('name', 'excludeField_Value_'+numExs);
|
325 |
+
tr.insert(new Element('td').update(newEl));
|
326 |
+
|
327 |
+
tr.insert(new Element('td', {'class': 'a-right'}).update(makeExcludeButton(numExs)));
|
328 |
+
|
329 |
+
tbl.insert(tr);
|
330 |
+
|
331 |
+
if (doSwap==true) {
|
332 |
+
swapExcludeButton(numExs-1);
|
333 |
+
}
|
334 |
+
});
|
335 |
+
}
|
336 |
+
|
337 |
+
var numReps = <?php echo count($ex['replace_options']); ?>;
|
338 |
+
|
339 |
+
function removeReplaceRow(row) {
|
340 |
+
var rowEl = $$('#replaceRow_'+row);
|
341 |
+
rowEl.each(function(el) {
|
342 |
+
el.remove();
|
343 |
+
});
|
344 |
+
|
345 |
+
setSaveButton('block');
|
346 |
+
}
|
347 |
+
|
348 |
+
function makeReplaceButton(id) {
|
349 |
+
var js = 'javascript:addReplaceRow(true); setSaveButton("block");';
|
350 |
+
var but = new Element('button', {'id': 'replaceFieldButton_'+id, 'onclick': js, 'class': 'scalable', 'type': 'button', 'value': ' + '});
|
351 |
+
|
352 |
+
but.insert(new Element('span').update(' + '));
|
353 |
+
|
354 |
+
return but;
|
355 |
+
}
|
356 |
+
|
357 |
+
function swapReplaceButton(id) {
|
358 |
+
var buts = $$('#replaceFieldButton_'+id);
|
359 |
+
buts.each(function(but) {
|
360 |
+
but.down().update(' x ');
|
361 |
+
but.setAttribute('onclick', 'javascript:removeReplaceRow('+id+');');
|
362 |
+
});
|
363 |
+
}
|
364 |
+
|
365 |
+
function addReplaceRow(doSwap) {
|
366 |
+
numReps++;
|
367 |
+
|
368 |
+
$$('#replace_table tbody').each(function(tbl) {
|
369 |
+
var tr = new Element('tr', {'id': 'replaceRow_' + numReps, 'class': 'replaceRow'});
|
370 |
+
|
371 |
+
var newEl = new Element('select');
|
372 |
+
newEl.writeAttribute('id', 'replaceField_oldid_'+numReps);
|
373 |
+
newEl.writeAttribute('name', 'replaceField_oldid_'+numReps);
|
374 |
+
|
375 |
+
var option = new Element("option");
|
376 |
+
option.text = '';
|
377 |
+
option.value = '';
|
378 |
+
newEl.insert(option);
|
379 |
+
<?php
|
380 |
+
foreach ($attrs as $k => $v){
|
381 |
+
if(strlen(trim($v['label']))=='') continue;
|
382 |
+
?>
|
383 |
+
var option = new Element("option");
|
384 |
+
option.text = '<?php echo htmlspecialchars(str_replace('\'', '', $v['label'])); ?>';
|
385 |
+
option.value = '<?php echo htmlspecialchars($v['name']); ?>';
|
386 |
+
newEl.insert(option);
|
387 |
+
<?php
|
388 |
+
}
|
389 |
+
?>
|
390 |
+
tr.insert(new Element('td').update(newEl));
|
391 |
+
|
392 |
+
var newEl = new Element('select');
|
393 |
+
var option = new Element("option");
|
394 |
+
option.text = '';
|
395 |
+
option.value = '';
|
396 |
+
newEl.insert(option);
|
397 |
+
<?php
|
398 |
+
foreach ($attrs as $k => $v){
|
399 |
+
if(strlen(trim($v['label']))=='') continue;
|
400 |
+
?>
|
401 |
+
var option = new Element("option");
|
402 |
+
option.text = '<?php echo htmlspecialchars(str_replace('\'', '', $v['label'])); ?>';
|
403 |
+
option.value = '<?php echo htmlspecialchars($v['name']); ?>';
|
404 |
+
newEl.insert(option);
|
405 |
+
<?php
|
406 |
+
}
|
407 |
+
?>
|
408 |
+
newEl.writeAttribute('id', 'replaceField_newid_'+numReps);
|
409 |
+
newEl.writeAttribute('name', 'replaceField_newid_'+numReps);
|
410 |
+
tr.insert(new Element('td').update(newEl));
|
411 |
+
|
412 |
+
tr.insert(new Element('td', {'class': 'a-right', 'style': 'text-align: right !important;'}).update(makeReplaceButton(numReps)));
|
413 |
+
|
414 |
+
tbl.insert(tr);
|
415 |
+
|
416 |
+
if (doSwap==true) {
|
417 |
+
swapReplaceButton(numReps-1);
|
418 |
+
}
|
419 |
+
});
|
420 |
+
}
|
421 |
+
|
422 |
+
|
423 |
+
|
424 |
+
|
425 |
+
|
426 |
+
document.observe("dom:loaded", function() {
|
427 |
+
addExcludeRow(false);
|
428 |
+
addReplaceRow(false);
|
429 |
+
|
430 |
+
var ub = $('uploadButton');
|
431 |
+
var ab = $('ajaxButton');
|
432 |
+
|
433 |
+
ub.setStyle({display: 'none'});
|
434 |
+
ab.setStyle({display: 'block'});
|
435 |
+
});
|
436 |
+
|
437 |
+
Event.observe($('upload_exclusion_data'), 'change', function(event) {
|
438 |
+
var sel = $('upload_exclusion_data').getValue();
|
439 |
+
if (sel == "No") {
|
440 |
+
$('exclude_table_container').setStyle({'display': 'none'});
|
441 |
+
} else {
|
442 |
+
$('exclude_table_container').setStyle({'display': 'block'});
|
443 |
+
}
|
444 |
+
|
445 |
+
setSaveButton('block');
|
446 |
+
});
|
447 |
+
|
448 |
+
Event.observe($('upload_replacement_data'), 'change', function(event) {
|
449 |
+
var sel = $('upload_replacement_data').getValue();
|
450 |
+
if (sel == "None") {
|
451 |
+
$('replacement_catalog_table_container').setStyle({'display': 'none'});
|
452 |
+
$('replacement_item_table_container').setStyle({'display': 'none'});
|
453 |
+
|
454 |
+
} else if (sel == "Entire Catalog") {
|
455 |
+
$('replacement_catalog_table_container').setStyle({'display': 'block'});
|
456 |
+
$('replacement_item_table_container').setStyle({'display': 'none'});
|
457 |
+
|
458 |
+
} else if (sel == "Individual Items") {
|
459 |
+
$('replacement_catalog_table_container').setStyle({'display': 'none'});
|
460 |
+
$('replacement_item_table_container').setStyle({'display': 'block'});
|
461 |
+
|
462 |
+
}
|
463 |
+
|
464 |
+
setSaveButton('block');
|
465 |
+
});
|
466 |
+
|
467 |
+
Event.observe($('upload_sales_data'), 'change', function(event) {
|
468 |
+
setSaveButton('block');
|
469 |
+
});
|
470 |
+
|
471 |
+
Event.observe($('upload_product_data'), 'change', function(event) {
|
472 |
+
setSaveButton('block');
|
473 |
+
});
|
474 |
+
|
475 |
+
Event.observe($('showUploadDetails'), 'change', function(event) {
|
476 |
+
setSaveButton('block');
|
477 |
+
});
|
478 |
+
|
479 |
+
$$('select').each(function(el) {
|
480 |
+
Event.observe(el, 'change', function(event) {
|
481 |
+
setSaveButton('block');
|
482 |
+
});
|
483 |
+
});
|
484 |
+
|
485 |
+
$$('input').each(function(el) {
|
486 |
+
Event.observe(el, 'change', function(event) {
|
487 |
+
setSaveButton('block');
|
488 |
+
});
|
489 |
+
});
|
490 |
+
|
491 |
+
|
492 |
+
function setSaveButton(status) {
|
493 |
+
$('saveButton').setStyle({'display': status});
|
494 |
+
if (status == 'block') {
|
495 |
+
setUploadButton('none');
|
496 |
+
} else {
|
497 |
+
setUploadButton('block');
|
498 |
+
}
|
499 |
+
}
|
500 |
+
|
501 |
+
function setUploadButton(status) {
|
502 |
+
$('uploadButton').setStyle({'display': status});
|
503 |
+
$('ajaxButton').setStyle({'display': status});
|
504 |
+
}
|
505 |
+
|
506 |
+
function getUrlKeyValue(str, key) {
|
507 |
+
var sub = "(/"+key+"/)(.*?/)";
|
508 |
+
var re = new RegExp(sub, "g");
|
509 |
+
var ret = str.match(re);
|
510 |
+
|
511 |
+
if (ret && ret.length) {
|
512 |
+
var vals = ret[0].split('/');
|
513 |
+
if (vals && vals.length > 1) {
|
514 |
+
var out = vals[2];
|
515 |
+
return out;
|
516 |
+
}
|
517 |
+
}
|
518 |
+
|
519 |
+
return null;
|
520 |
+
}
|
521 |
+
|
522 |
+
function ajaxUpload(pos, gourl) {
|
523 |
+
Element.show('loading-mask');
|
524 |
+
|
525 |
+
var dt = '<?php echo date("Y-m"); ?>';
|
526 |
+
var files = new Array(
|
527 |
+
{upload: 1, key: 'configboost', name: 'Uploading<br />Configuration', command: 'ucb', field: null, value: null},
|
528 |
+
{upload: 1, key: 'categories', name: 'Uploading<br />Categories', command: 'ucd', field: null, value: null},
|
529 |
+
{upload: <?php echo strtolower($ex['upload_exclusion_data']) != "no" ? 1 : 0 ?>, key: 'exclusions', name: 'Uploading<br />Exclusions', command: 'ued', field: null, value: null},
|
530 |
+
{upload: <?php echo strtolower($ex['upload_replacement_data']) != "none" ? 1 : 0 ?>, key: 'replacements', name: 'Uploading<br />Replacements', command: 'urd', field: null, value: null},
|
531 |
+
{upload: <?php echo strtolower($ex['upload_product_data']) != "no" ? 1 : 0 ?>, key: 'products', name: 'Uploading<br />Products', command: 'upd', field: null, value: null},
|
532 |
+
{upload: <?php echo strtolower($ex['upload_sales_data']) != "none" ? 1 : 0 ?>, key: 'sales', name: 'Uploading<br />Sales', command: 'usf/ym/' + dt + '/p/0/isajax/true', field: 'status', value: 'completed'},
|
533 |
+
{upload: 1, key: 'generate', name: 'Starting<br />Generate', command: 'gen', field: null, value: null}
|
534 |
+
);
|
535 |
+
|
536 |
+
var doUpload = false;
|
537 |
+
|
538 |
+
for (var uf=pos; uf<files.length; uf++) {
|
539 |
+
if (files[uf].upload==1) {
|
540 |
+
doUpload = true;
|
541 |
+
pos = uf;
|
542 |
+
break;
|
543 |
+
}
|
544 |
+
}
|
545 |
+
|
546 |
+
if (doUpload) {
|
547 |
+
//handle situation when we in the URL do not have '/key/' part
|
548 |
+
var baseUrl = document.location.href.substr(0, document.location.href.indexOf('/key/'));
|
549 |
+
if( baseUrl.length == 0 ) {
|
550 |
+
baseUrl = document.location.href;
|
551 |
+
}
|
552 |
+
var reloadurl = baseUrl +
|
553 |
+
'/key/' + getUrlKeyValue(document.location.href, 'key') +
|
554 |
+
'/cmd/' + files[pos].command;
|
555 |
+
|
556 |
+
reloadurl = reloadurl.replace(document.location.origin, '');
|
557 |
+
|
558 |
+
Element.show('loading-mask');
|
559 |
+
|
560 |
+
if (gourl != undefined) {
|
561 |
+
reloadurl = gourl;
|
562 |
+
}
|
563 |
+
|
564 |
+
var name = files[pos].name;
|
565 |
+
if (pos == 5) {
|
566 |
+
var m = getUrlKeyValue(reloadurl, 'ym');
|
567 |
+
if (m) {
|
568 |
+
name = name + ' for ' + m;
|
569 |
+
}
|
570 |
+
|
571 |
+
var page = getUrlKeyValue(reloadurl, 'p');
|
572 |
+
if (page) {
|
573 |
+
name = name + ' Page: ' + (parseInt(page)+1);
|
574 |
+
}
|
575 |
+
}
|
576 |
+
|
577 |
+
Element.update('loading-msg', '<br />' + name + '<br />Please Wait...');
|
578 |
+
|
579 |
+
new Ajax.Request(reloadurl, {
|
580 |
+
method: 'get',
|
581 |
+
//asynchronous: false,
|
582 |
+
onComplete: function(transport) {
|
583 |
+
Element.hide('loading-mask');
|
584 |
+
|
585 |
+
$('loading-mask').setStyle({display: 'none'});
|
586 |
+
|
587 |
+
var tmp = transport.responseText.replace(new RegExp("[\r\n ]", "gmi"), "");
|
588 |
+
var res = tmp.replace(new RegExp("<!DOCTYPE.*", "gmi"), "");
|
589 |
+
|
590 |
+
if (res != "") {
|
591 |
+
var comp=res.evalJSON();
|
592 |
+
|
593 |
+
if (comp.status != "completed" && comp.month != "" && comp.month != "") {
|
594 |
+
//handle situation when we in the URL do not have '/key/' part
|
595 |
+
var baseUrl = document.location.href.substr(0, document.location.href.indexOf('/key/'));
|
596 |
+
if( baseUrl.length == 0 ) {
|
597 |
+
baseUrl = document.location.href;
|
598 |
+
}
|
599 |
+
reloadurl = baseUrl +
|
600 |
+
'/key/' + getUrlKeyValue(document.location.href, 'key') +
|
601 |
+
'/cmd/usf' +
|
602 |
+
'/ym/' + comp.month +
|
603 |
+
'/p/' + comp.page +
|
604 |
+
'/isajax/true' ;
|
605 |
+
|
606 |
+
ajaxUpload(pos, reloadurl);
|
607 |
+
} else {
|
608 |
+
pos++;
|
609 |
+
if (pos < files.length) {
|
610 |
+
ajaxUpload(pos);
|
611 |
+
}
|
612 |
+
}
|
613 |
+
} else {
|
614 |
+
pos++;
|
615 |
+
if (pos < files.length) {
|
616 |
+
ajaxUpload(pos);
|
617 |
+
}
|
618 |
+
}
|
619 |
+
|
620 |
+
}
|
621 |
+
});
|
622 |
+
|
623 |
+
}
|
624 |
+
}
|
625 |
+
</script>
|
app/design/frontend/base/default/layout/recommend.xml
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<layout version="0.1.0">
|
3 |
+
<default>
|
4 |
+
<reference name="head">
|
5 |
+
<action method="addJs"><file>jquery.tools.min.js</file></action>
|
6 |
+
</reference>
|
7 |
+
</default>
|
8 |
+
|
9 |
+
<catalog_product_view>
|
10 |
+
<reference name="product.info">
|
11 |
+
<!-- remove name="catalog.product.related" / -->
|
12 |
+
<block type="recommend/catalog_product_list_related" name="catalog.product.related" as="relatedProducts" template="recommend/catalog/product/list/related.phtml">
|
13 |
+
<action method="setColumnCount"><columns>3</columns></action>
|
14 |
+
</block>
|
15 |
+
<!-- remove name="product.info.upsell" / -->
|
16 |
+
<block type="recommend/catalog_product_list_upsell" name="product.info.upsell" as="upsell_products" template="recommend/catalog/product/list/upsell.phtml">
|
17 |
+
<action method="setColumnCount"><columns>4</columns></action>
|
18 |
+
</block>
|
19 |
+
</reference>
|
20 |
+
</catalog_product_view>
|
21 |
+
|
22 |
+
<checkout_cart_index>
|
23 |
+
<reference name="checkout.cart">
|
24 |
+
<!-- remove name="checkout.cart.crosssell" / -->
|
25 |
+
<block type="recommend/checkout_cart_crosssell" name="checkout.cart.crosssell" as="crosssell" template="recommend/checkout/cart/crosssell.phtml" />
|
26 |
+
</reference>
|
27 |
+
</checkout_cart_index>
|
28 |
+
</layout>
|
app/design/frontend/base/default/template/recommend/catalog/product/list/related.phtml
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Magento
|
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_AFL.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@magentocommerce.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 Magento to newer
|
18 |
+
* versions in the future. If you wish to customize Magento for your
|
19 |
+
* needs please refer to http://www.magentocommerce.com for more information.
|
20 |
+
*
|
21 |
+
* @category design
|
22 |
+
* @package base_default
|
23 |
+
* @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
|
24 |
+
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
25 |
+
*/
|
26 |
+
//var_dump($this->getItems()->getSize());
|
27 |
+
//exit;
|
28 |
+
?>
|
29 |
+
<?php
|
30 |
+
Mage::log('related_count: '.$this->getItems()->count());
|
31 |
+
|
32 |
+
if($this->getItems()->count()):
|
33 |
+
$gaUA = Mage::helper('recommend')->getGoogleAccountId();
|
34 |
+
$toutType = $this->getRecommendationType();
|
35 |
+
$gafunction='';
|
36 |
+
if( strlen($gaUA) > 0 && Mage::helper('recommend')->getGoogleAccountEnabled()) {
|
37 |
+
?>
|
38 |
+
<script type="text/javascript">
|
39 |
+
//<![CDATA[
|
40 |
+
(function() {
|
41 |
+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
42 |
+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
43 |
+
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
|
44 |
+
})();
|
45 |
+
var _gaq = _gaq || [];
|
46 |
+
_gaq.push(['_setAccount', '<?php echo $gaUA; ?>']);
|
47 |
+
//]]>
|
48 |
+
</script>
|
49 |
+
<?php
|
50 |
+
}
|
51 |
+
?>
|
52 |
+
<div class="block block-related">
|
53 |
+
<div class="block-title">
|
54 |
+
<strong><span><?php echo $this->__('Related Products') ?></span></strong>
|
55 |
+
</div>
|
56 |
+
<div class="block-content">
|
57 |
+
<p class="block-subtitle"><?php echo $this->__('Check items to add to the cart or') ?> <a href="#" onclick="selectAllRelated(this); return false;"><?php echo $this->__('select all') ?></a></p>
|
58 |
+
<ol class="mini-products-list" id="block-related">
|
59 |
+
<?php foreach($this->getItems() as $_item): ?>
|
60 |
+
<?php
|
61 |
+
if( strlen($gaUA) > 0 && Mage::helper('recommend')->getGoogleAccountEnabled()) {
|
62 |
+
$gafunction='onclick="_gaq.push([\'_trackEvent\', \'4TellRecs\', \''.$toutType.'\', \''.$_item->getEntityId().'\']);"';
|
63 |
+
}
|
64 |
+
?>
|
65 |
+
<li class="item">
|
66 |
+
<?php if(!$_item->isComposite() && $_item->isSaleable()): ?>
|
67 |
+
<?php if (!$_item->getRequiredOptions()): ?>
|
68 |
+
<input type="checkbox" class="checkbox related-checkbox" id="related-checkbox<?php echo $_item->getId() ?>" name="related_products[]" value="<?php echo $_item->getId() ?>" />
|
69 |
+
<?php endif; ?>
|
70 |
+
<?php endif; ?>
|
71 |
+
<div class="product">
|
72 |
+
<a href="<?php echo $_item->getProductUrl() ?>" <?php echo $gafunction; ?> title="<?php echo $this->htmlEscape($_item->getName()) ?>" class="product-image"><img src="<?php echo $this->helper('catalog/image')->init($_item, 'thumbnail')->resize(50) ?>" width="50" height="50" alt="<?php echo $this->htmlEscape($_item->getName()) ?>" /></a>
|
73 |
+
<div class="product-details">
|
74 |
+
<p class="product-name"><a href="<?php echo $_item->getProductUrl() ?>" <?php echo $gafunction; ?>><?php echo $this->htmlEscape($_item->getName()) ?></a></p>
|
75 |
+
<?php echo $this->getPriceHtml($_item, true, '-related') ?>
|
76 |
+
<?php if ($this->helper('wishlist')->isAllow()) : ?>
|
77 |
+
<a href="<?php echo $this->getAddToWishlistUrl($_item) ?>" class="link-wishlist"><?php echo $this->__('Add to Wishlist') ?></a>
|
78 |
+
<?php endif; ?>
|
79 |
+
</div>
|
80 |
+
</div>
|
81 |
+
</li>
|
82 |
+
<?php endforeach ?>
|
83 |
+
</ol>
|
84 |
+
<script type="text/javascript">decorateList('block-related', 'none-recursive')</script>
|
85 |
+
</div>
|
86 |
+
<script type="text/javascript">
|
87 |
+
//<![CDATA[
|
88 |
+
$$('.related-checkbox').each(function(elem){
|
89 |
+
Event.observe(elem, 'click', addRelatedToProduct)
|
90 |
+
});
|
91 |
+
|
92 |
+
var relatedProductsCheckFlag = false;
|
93 |
+
function selectAllRelated(txt){
|
94 |
+
if (relatedProductsCheckFlag == false) {
|
95 |
+
$$('.related-checkbox').each(function(elem){
|
96 |
+
elem.checked = true;
|
97 |
+
});
|
98 |
+
relatedProductsCheckFlag = true;
|
99 |
+
txt.innerHTML="<?php echo $this->__('unselect all') ?>";
|
100 |
+
} else {
|
101 |
+
$$('.related-checkbox').each(function(elem){
|
102 |
+
elem.checked = false;
|
103 |
+
});
|
104 |
+
relatedProductsCheckFlag = false;
|
105 |
+
txt.innerHTML="<?php echo $this->__('select all') ?>";
|
106 |
+
}
|
107 |
+
addRelatedToProduct();
|
108 |
+
}
|
109 |
+
|
110 |
+
function addRelatedToProduct(){
|
111 |
+
var checkboxes = $$('.related-checkbox');
|
112 |
+
var values = [];
|
113 |
+
for(var i=0;i<checkboxes.length;i++){
|
114 |
+
if(checkboxes[i].checked) values.push(checkboxes[i].value);
|
115 |
+
}
|
116 |
+
if($('related-products-field')){
|
117 |
+
$('related-products-field').value = values.join(',');
|
118 |
+
}
|
119 |
+
}
|
120 |
+
//]]>
|
121 |
+
</script>
|
122 |
+
</div>
|
123 |
+
<?php endif ?>
|
app/design/frontend/base/default/template/recommend/catalog/product/list/upsell.phtml
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Magento
|
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_AFL.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@magentocommerce.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 Magento to newer
|
18 |
+
* versions in the future. If you wish to customize Magento for your
|
19 |
+
* needs please refer to http://www.magentocommerce.com for more information.
|
20 |
+
*
|
21 |
+
* @category design
|
22 |
+
* @package base_default
|
23 |
+
* @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
|
24 |
+
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
25 |
+
*/
|
26 |
+
?>
|
27 |
+
<?php
|
28 |
+
if(count($this->getItemCollection()->getItems())):
|
29 |
+
$gaUA = Mage::helper('recommend')->getGoogleAccountId();
|
30 |
+
$toutType = $this->getRecommendationType();
|
31 |
+
$gafunction='';
|
32 |
+
if( strlen($gaUA) > 0 && Mage::helper('recommend')->getGoogleAccountEnabled()) {
|
33 |
+
?>
|
34 |
+
<script type="text/javascript">
|
35 |
+
//<![CDATA[
|
36 |
+
(function() {
|
37 |
+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
38 |
+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
39 |
+
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
|
40 |
+
})();
|
41 |
+
var _gaq = _gaq || [];
|
42 |
+
_gaq.push(['_setAccount', '<?php echo $gaUA; ?>']);
|
43 |
+
//]]>
|
44 |
+
</script>
|
45 |
+
<?php
|
46 |
+
}
|
47 |
+
?>
|
48 |
+
<div class="box-collateral box-up-sell">
|
49 |
+
<h2><?php echo $this->__('You may also be interested in the following product(s)') ?></h2>
|
50 |
+
<table class="products-grid" id="upsell-product-table">
|
51 |
+
<?php // $this->setColumnCount(5); // uncomment this line if you want to have another number of columns. also can be changed in layout ?>
|
52 |
+
<?php $this->resetItemsIterator() ?>
|
53 |
+
<?php for($_i=0;$_i<$this->getRowCount();$_i++): ?>
|
54 |
+
<tr>
|
55 |
+
<?php for($_j=0;$_j<$this->getColumnCount();$_j++): ?>
|
56 |
+
<?php if($_link=$this->getIterableItem()): ?>
|
57 |
+
<?php
|
58 |
+
if( strlen($gaUA) > 0 && Mage::helper('recommend')->getGoogleAccountEnabled()) {
|
59 |
+
$gafunction='onclick="_gaq.push([\'_trackEvent\', \'4TellRecs\', \''.$toutType.'\', \''.$_link->getEntityId().'\']);"';
|
60 |
+
}
|
61 |
+
?>
|
62 |
+
<td>
|
63 |
+
<a href="<?php echo $_link->getProductUrl() ?>" <?php echo $gafunction; ?> title="<?php echo $this->htmlEscape($_link->getName()) ?>" class="product-image"><img src="<?php echo $this->helper('catalog/image')->init($_link, 'small_image')->resize(125) ?>" width="125" height="125" alt="<?php echo $this->htmlEscape($_link->getName()) ?>" /></a>
|
64 |
+
<h3 class="product-name"><a href="<?php echo $_link->getProductUrl() ?>" title="<?php echo $this->htmlEscape($_link->getName()) ?>"><?php echo $this->htmlEscape($_link->getName()) ?></a></h3>
|
65 |
+
<?php echo $this->getPriceHtml($_link, true, '-upsell') ?>
|
66 |
+
<?php echo $this->getReviewsSummaryHtml($_link) ?>
|
67 |
+
</td>
|
68 |
+
<?php else: ?>
|
69 |
+
<td class="empty"> </td>
|
70 |
+
<?php endif; ?>
|
71 |
+
<?php endfor; ?>
|
72 |
+
</tr>
|
73 |
+
<?php endfor; ?>
|
74 |
+
</table>
|
75 |
+
<script type="text/javascript">decorateTable('upsell-product-table')</script>
|
76 |
+
</div>
|
77 |
+
<?php
|
78 |
+
endif
|
79 |
+
?>
|
app/design/frontend/base/default/template/recommend/checkout/cart/crosssell.phtml
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Magento
|
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_AFL.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@magentocommerce.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 Magento to newer
|
18 |
+
* versions in the future. If you wish to customize Magento for your
|
19 |
+
* needs please refer to http://www.magentocommerce.com for more information.
|
20 |
+
*
|
21 |
+
* @category design
|
22 |
+
* @package base_default
|
23 |
+
* @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
|
24 |
+
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
25 |
+
*/
|
26 |
+
?>
|
27 |
+
<?php
|
28 |
+
/**
|
29 |
+
* Cart cross sell items template
|
30 |
+
*
|
31 |
+
* @see Mage_Checkout_Block_Cart_Crosssell
|
32 |
+
*/
|
33 |
+
?>
|
34 |
+
<?php
|
35 |
+
if($this->getItemCount()):
|
36 |
+
$gaUA = Mage::helper('recommend')->getGoogleAccountId();
|
37 |
+
$toutType = $this->getRecommendationType();
|
38 |
+
$gafunction='';
|
39 |
+
if( strlen($gaUA) > 0 && Mage::helper('recommend')->getGoogleAccountEnabled()) {
|
40 |
+
?>
|
41 |
+
<script type="text/javascript">
|
42 |
+
//<![CDATA[
|
43 |
+
(function() {
|
44 |
+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
45 |
+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
46 |
+
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
|
47 |
+
})();
|
48 |
+
var _gaq = _gaq || [];
|
49 |
+
_gaq.push(['_setAccount', '<?php echo $gaUA; ?>']);
|
50 |
+
//]]>
|
51 |
+
</script>
|
52 |
+
<?php
|
53 |
+
}
|
54 |
+
?>
|
55 |
+
<div class="crosssell">
|
56 |
+
<h2><?php echo $this->__('Based on your selection, you may be interested in the following items:') ?></h2>
|
57 |
+
<ul id="crosssell-products-list">
|
58 |
+
<?php foreach ($this->getItems() as $_item): ?>
|
59 |
+
<?php
|
60 |
+
if( strlen($gaUA) > 0 && Mage::helper('recommend')->getGoogleAccountEnabled()) {
|
61 |
+
$gafunction='onclick="_gaq.push([\'_trackEvent\', \'4TellRecs\', \''.$toutType.'\', \''.$_item->getEntityId().'\']);"';
|
62 |
+
}
|
63 |
+
?>
|
64 |
+
<li class="item">
|
65 |
+
<a class="product-image" href="<?php echo $_item->getProductUrl() ?>" <?php echo $gafunction; ?> title="<?php echo $this->htmlEscape($_item->getName()) ?>"><img src="<?php echo $this->helper('catalog/image')->init($_item, 'thumbnail')->resize(75); ?>" width="75" height="75" alt="<?php echo $this->htmlEscape($_item->getName()) ?>" /></a>
|
66 |
+
<div class="product-details">
|
67 |
+
<h3 class="product-name"><a href="<?php echo $_item->getProductUrl() ?>" <?php echo $gafunction; ?>><?php echo $this->htmlEscape($_item->getName()) ?></a></h3>
|
68 |
+
<?php echo $this->getPriceHtml($_item, true) ?>
|
69 |
+
<button type="button" title="<?php echo $this->__('Add to Cart') ?>" class="button btn-cart" onclick="setLocation('<?php echo $this->getAddToCartUrl($_item) ?>')"><span><span><?php echo $this->__('Add to Cart') ?></span></span></button>
|
70 |
+
<ul class="add-to-links">
|
71 |
+
<?php if ($this->helper('wishlist')->isAllow()) : ?>
|
72 |
+
<li><a href="<?php echo $this->getAddToWishlistUrl($_item) ?>" class="link-wishlist"><?php echo $this->__('Add to Wishlist') ?></a></li>
|
73 |
+
<?php endif; ?>
|
74 |
+
<?php if($_compareUrl=$this->getAddToCompareUrl($_item)): ?>
|
75 |
+
<li><span class="separator">|</span> <a href="<?php echo $_compareUrl ?>" class="link-compare"><?php echo $this->__('Add to Compare') ?></a></li>
|
76 |
+
<?php endif; ?>
|
77 |
+
</ul>
|
78 |
+
</div>
|
79 |
+
</li>
|
80 |
+
<?php endforeach; ?>
|
81 |
+
</ul>
|
82 |
+
<script type="text/javascript">decorateList('crosssell-products-list', 'none-recursive')</script>
|
83 |
+
</div>
|
84 |
+
<?php
|
85 |
+
endif;
|
86 |
+
?>
|
app/etc/modules/FourTell_Recommend.xml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<FourTell_Recommend>
|
5 |
+
<active>true</active>
|
6 |
+
<codePool>community</codePool>
|
7 |
+
</FourTell_Recommend>
|
8 |
+
</modules>
|
9 |
+
</config>
|
app/locale/en_US/FourTell_Recommend.csv
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
// this step is optional
|
js/jquery.tools.min.js
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* jQuery Tools v1.2.6 - The missing UI library for the Web
|
3 |
+
*
|
4 |
+
* overlay/overlay.js
|
5 |
+
* scrollable/scrollable.js
|
6 |
+
* tabs/tabs.js
|
7 |
+
* tooltip/tooltip.js
|
8 |
+
*
|
9 |
+
* NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
|
10 |
+
*
|
11 |
+
* http://flowplayer.org/tools/
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */
|
15 |
+
(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bZ(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bY(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bA.test(a)?d(a,e):bY(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)bY(a+"["+e+"]",b[e],c,d);else d(a,b)}function bX(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bW(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bP,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bW(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bW(a,c,d,e,"*",g));return l}function bV(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bL),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function by(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bt:bu;if(d>0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bf(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function V(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(Q.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(w,"")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:H?function(a){return a==null?"":H.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?F.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(!b)return-1;if(I)return I.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=G.call(arguments,2),g=function(){return a.apply(c,f.concat(G.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf("compatible")<0&&v.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){J["[object "+b+"]"]=b.toLowerCase()}),A=e.uaMatch(z),A.browser&&(e.browser[A.browser]=!0,e.browser.version=A.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?C=function(){c.removeEventListener("DOMContentLoaded",C,!1),e.ready()}:c.attachEvent&&(C=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",C),e.ready())});return e}(),g="done fail isResolved isRejected promise then always pipe".split(" "),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j==="array"?e.done.apply(e,i):j==="function"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[c,"reject"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g+"With"](this===b?d:this,[h])}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement("div"),b=c.documentElement,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;a.setAttribute("className","t"),a.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a=="object")return this.each(function(){f.data(this,a)});var j=a.split(".");j[1]=j[1]?"."+j[1]:"";if(c===b){d=this.triggerHandler("getData"+j[1]+"!",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler("setData"+j[1]+"!",d),f.data(this,a,c),b.triggerHandler("changeData"+j[1]+"!",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||"fx")+"mark",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||"fx";var e=d+"mark",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,"mark"))}},queue:function(a,c,d){if(a){c=(c||"fx")+"queue";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e;d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+"queue",!0),m(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\n\t\r]/g,o=/\s+/,p=/\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u,v;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(o);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(o);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(n," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(n," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute("disabled")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,"optgroup"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete
|
16 |
+
t[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf("!")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,M(a.origType,a.selector),f.extend({},a,{handler:L,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,M(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?D:C):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=D;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=D;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=D,this.stopPropagation()},isDefaultPrevented:C,isPropagationStopped:C,isImmediatePropagationStopped:C};var E=function(a){var b=a.relatedTarget,c=!1,d=a.type;a.type=a.data,b!==this&&(b&&(c=f.contains(this,b)),c||(f.event.handle.apply(this,arguments),a.type=d))},F=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?F:E,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?F:E)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,"form"))f.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=f.nodeName(b,"input")||f.nodeName(b,"button")?b.type:"";(c==="submit"||c==="image")&&f(b).closest("form").length&&J("submit",this,arguments)}),f.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=f.nodeName(b,"input")||f.nodeName(b,"button")?b.type:"";(c==="text"||c==="password")&&f(b).closest("form").length&&a.keyCode===13&&J("submit",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,".specialSubmit")}});if(!f.support.changeBubbles){var G,H=function(a){var b=f.nodeName(a,"input")?a.type:"",c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a=="object"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,"lastToggle"+a.guid)||0)%d;f.data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var K={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};f.each(["live","die"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a=="object"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c==="die"&&!a&&g&&g.charAt(0)==="."){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||C,d=b;a=(a||"").split(" ");while((h=a[i++])!=null){j=w.exec(h),k="",j&&(k=j[0],h=h.replace(w,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,K[h]?(a.push(K[h]+k),h=h+k):h=(K[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],"live."+M(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind("live."+M(h,m),e)}return this}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("parentNode",b,f,a,e,c)},"~":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("previousSibling",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[":"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var N=/Until$/,O=/^(?:parents|prevUntil|prevAll)/,P=/,/,Q=/^.[^:#\[\.,]*$/,R=Array.prototype.slice,S=f.expr.match.POS,T={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(V(this,a,!1),"not",a)},filter:function(a){return this.pushStack(V(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=S.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|object|embed|option|style)/i,bb=/checked\s*(?:[^=]|=\s*.checked.)/i,bc=/\/(java|ecma)script/i,bd=/^\s*<!(?:\[CDATA\[|\-\-)/,be={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bb.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bf(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bl)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i;b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof a[0]=="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!ba.test(a[0])&&(f.support.checkClone||!bb.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean
|
17 |
+
(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bk(k[i]);else bk(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||bc.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bm=/alpha\([^)]*\)/i,bn=/opacity=([^)]*)/,bo=/([A-Z]|^ms)/g,bp=/^-?\d+(?:px)?$/i,bq=/^-?\d/,br=/^([\-+])=([\-+.\de]+)/,bs={position:"absolute",visibility:"hidden",display:"block"},bt=["Left","Right"],bu=["Top","Bottom"],bv,bw,bx;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bv(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=br.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bv)return bv(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return by(a,b,d);f.swap(a,bs,function(){e=by(a,b,d)});return e}},set:function(a,b){if(!bp.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cr(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cq("hide",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],"display");g!=="none"&&!f._data(this[d],"olddisplay")&&f._data(this[d],"olddisplay",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cq("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?"each":"queue"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(f.support.inlineBlockNeedsLayout?(j=cr(this.nodeName),j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)):this.style.display="inline-block"))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)k=new f.fx(this,b,i),h=a[i],cj.test(h)?k[h==="toggle"?d?"show":"hide":h]():(l=ck.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?"":"px"),o!=="px"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]==="-="?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,""));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cq("show",1),slideUp:cq("hide",1),slideToggle:cq("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return d.step(a)}var d=this,e=f.fx;this.startTime=cn||co(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&f.timers.push(g)&&!cl&&(cl=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cn||co(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cl),cl=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cs=/^t(?:able|d|h)$/i,ct=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cu(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!cs.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement("div"),d,e,g,h,i=parseFloat(f.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window);(function(a){a.tools=a.tools||{version:"v1.2.6"},a.tools.overlay={addEffect:function(a,b,d){c[a]=[b,d]},conf:{close:null,closeOnClick:!0,closeOnEsc:!0,closeSpeed:"fast",effect:"default",fixed:!a.browser.msie||a.browser.version>6,left:"center",load:!1,mask:null,oneInstance:!0,speed:"normal",target:null,top:"10%"}};var b=[],c={};a.tools.overlay.addEffect("default",function(b,c){var d=this.getConf(),e=a(window);d.fixed||(b.top+=e.scrollTop(),b.left+=e.scrollLeft()),b.position=d.fixed?"fixed":"absolute",this.getOverlay().css(b).fadeIn(d.speed,c)},function(a){this.getOverlay().fadeOut(this.getConf().closeSpeed,a)});function d(d,e){var f=this,g=d.add(f),h=a(window),i,j,k,l=a.tools.expose&&(e.mask||e.expose),m=Math.random().toString().slice(10);l&&(typeof l=="string"&&(l={color:l}),l.closeOnClick=l.closeOnEsc=!1);var n=e.target||d.attr("rel");j=n?a(n):null||d;if(!j.length)throw"Could not find Overlay: "+n;d&&d.index(j)==-1&&d.click(function(a){f.load(a);return a.preventDefault()}),a.extend(f,{load:function(d){if(f.isOpened())return f;var i=c[e.effect];if(!i)throw"Overlay: cannot find effect : \""+e.effect+"\"";e.oneInstance&&a.each(b,function(){this.close(d)}),d=d||a.Event(),d.type="onBeforeLoad",g.trigger(d);if(d.isDefaultPrevented())return f;k=!0,l&&a(j).expose(l);var n=e.top,o=e.left,p=j.outerWidth({margin:!0}),q=j.outerHeight({margin:!0});typeof n=="string"&&(n=n=="center"?Math.max((h.height()-q)/2,0):parseInt(n,10)/100*h.height()),o=="center"&&(o=Math.max((h.width()-p)/2,0)),i[0].call(f,{top:n,left:o},function(){k&&(d.type="onLoad",g.trigger(d))}),l&&e.closeOnClick&&a.mask.getMask().one("click",f.close),e.closeOnClick&&a(document).bind("click."+m,function(b){a(b.target).parents(j).length||f.close(b)}),e.closeOnEsc&&a(document).bind("keydown."+m,function(a){a.keyCode==27&&f.close(a)});return f},close:function(b){if(!f.isOpened())return f;b=b||a.Event(),b.type="onBeforeClose",g.trigger(b);if(!b.isDefaultPrevented()){k=!1,c[e.effect][1].call(f,function(){b.type="onClose",g.trigger(b)}),a(document).unbind("click."+m).unbind("keydown."+m),l&&a.mask.close();return f}},getOverlay:function(){return j},getTrigger:function(){return d},getClosers:function(){return i},isOpened:function(){return k},getConf:function(){return e}}),a.each("onBeforeLoad,onStart,onLoad,onBeforeClose,onClose".split(","),function(b,c){a.isFunction(e[c])&&a(f).bind(c,e[c]),f[c]=function(b){b&&a(f).bind(c,b);return f}}),i=j.find(e.close||".close"),!i.length&&!e.close&&(i=a("<a class=\"close\"></a>"),j.prepend(i)),i.click(function(a){f.close(a)}),e.load&&f.load()}a.fn.overlay=function(c){var e=this.data("overlay");if(e)return e;a.isFunction(c)&&(c={onBeforeLoad:c}),c=a.extend(!0,{},a.tools.overlay.conf,c),this.each(function(){e=new d(a(this),c),b.push(e),a(this).data("overlay",e)});return c.api?e:this}})(jQuery);
|
18 |
+
(function(a){a.tools=a.tools||{version:"v1.2.6"},a.tools.scrollable={conf:{activeClass:"active",circular:!1,clonedClass:"cloned",disabledClass:"disabled",easing:"swing",initialIndex:0,item:"> *",items:".items",keyboard:!0,mousewheel:!1,next:".next",prev:".prev",size:1,speed:400,vertical:!1,touch:!0,wheelSpeed:0}};function b(a,b){var c=parseInt(a.css(b),10);if(c)return c;var d=a[0].currentStyle;return d&&d.width&&parseInt(d.width,10)}function c(b,c){var d=a(c);return d.length<2?d:b.parent().find(c)}var d;function e(b,e){var f=this,g=b.add(f),h=b.children(),i=0,j=e.vertical;d||(d=f),h.length>1&&(h=a(e.items,b)),e.size>1&&(e.circular=!1),a.extend(f,{getConf:function(){return e},getIndex:function(){return i},getSize:function(){return f.getItems().size()},getNaviButtons:function(){return n.add(o)},getRoot:function(){return b},getItemWrap:function(){return h},getItems:function(){return h.find(e.item).not("."+e.clonedClass)},move:function(a,b){return f.seekTo(i+a,b)},next:function(a){return f.move(e.size,a)},prev:function(a){return f.move(-e.size,a)},begin:function(a){return f.seekTo(0,a)},end:function(a){return f.seekTo(f.getSize()-1,a)},focus:function(){d=f;return f},addItem:function(b){b=a(b),e.circular?(h.children().last().before(b),h.children().first().replaceWith(b.clone().addClass(e.clonedClass))):(h.append(b),o.removeClass("disabled")),g.trigger("onAddItem",[b]);return f},seekTo:function(b,c,k){b.jquery||(b*=1);if(e.circular&&b===0&&i==-1&&c!==0)return f;if(!e.circular&&b<0||b>f.getSize()||b<-1)return f;var l=b;b.jquery?b=f.getItems().index(b):l=f.getItems().eq(b);var m=a.Event("onBeforeSeek");if(!k){g.trigger(m,[b,c]);if(m.isDefaultPrevented()||!l.length)return f}var n=j?{top:-l.position().top}:{left:-l.position().left};i=b,d=f,c===undefined&&(c=e.speed),h.animate(n,c,e.easing,k||function(){g.trigger("onSeek",[b])});return f}}),a.each(["onBeforeSeek","onSeek","onAddItem"],function(b,c){a.isFunction(e[c])&&a(f).bind(c,e[c]),f[c]=function(b){b&&a(f).bind(c,b);return f}});if(e.circular){var k=f.getItems().slice(-1).clone().prependTo(h),l=f.getItems().eq(1).clone().appendTo(h);k.add(l).addClass(e.clonedClass),f.onBeforeSeek(function(a,b,c){if(!a.isDefaultPrevented()){if(b==-1){f.seekTo(k,c,function(){f.end(0)});return a.preventDefault()}b==f.getSize()&&f.seekTo(l,c,function(){f.begin(0)})}});var m=b.parents().add(b).filter(function(){if(a(this).css("display")==="none")return!0});m.length?(m.show(),f.seekTo(0,0,function(){}),m.hide()):f.seekTo(0,0,function(){})}var n=c(b,e.prev).click(function(a){a.stopPropagation(),f.prev()}),o=c(b,e.next).click(function(a){a.stopPropagation(),f.next()});e.circular||(f.onBeforeSeek(function(a,b){setTimeout(function(){a.isDefaultPrevented()||(n.toggleClass(e.disabledClass,b<=0),o.toggleClass(e.disabledClass,b>=f.getSize()-1))},1)}),e.initialIndex||n.addClass(e.disabledClass)),f.getSize()<2&&n.add(o).addClass(e.disabledClass),e.mousewheel&&a.fn.mousewheel&&b.mousewheel(function(a,b){if(e.mousewheel){f.move(b<0?1:-1,e.wheelSpeed||50);return!1}});if(e.touch){var p={};h[0].ontouchstart=function(a){var b=a.touches[0];p.x=b.clientX,p.y=b.clientY},h[0].ontouchmove=function(a){if(a.touches.length==1&&!h.is(":animated")){var b=a.touches[0],c=p.x-b.clientX,d=p.y-b.clientY;f[j&&d>0||!j&&c>0?"next":"prev"](),a.preventDefault()}}}e.keyboard&&a(document).bind("keydown.scrollable",function(b){if(!(!e.keyboard||b.altKey||b.ctrlKey||b.metaKey||a(b.target).is(":input"))){if(e.keyboard!="static"&&d!=f)return;var c=b.keyCode;if(j&&(c==38||c==40)){f.move(c==38?-1:1);return b.preventDefault()}if(!j&&(c==37||c==39)){f.move(c==37?-1:1);return b.preventDefault()}}}),e.initialIndex&&f.seekTo(e.initialIndex,0,function(){})}a.fn.scrollable=function(b){var c=this.data("scrollable");if(c)return c;b=a.extend({},a.tools.scrollable.conf,b),this.each(function(){c=new e(a(this),b),a(this).data("scrollable",c)});return b.api?c:this}})(jQuery);
|
19 |
+
(function(a){a.tools=a.tools||{version:"v1.2.6"},a.tools.tabs={conf:{tabs:"a",current:"current",onBeforeClick:null,onClick:null,effect:"default",initialIndex:0,event:"click",rotate:!1,slideUpSpeed:400,slideDownSpeed:400,history:!1},addEffect:function(a,c){b[a]=c}};var b={"default":function(a,b){this.getPanes().hide().eq(a).show(),b.call()},fade:function(a,b){var c=this.getConf(),d=c.fadeOutSpeed,e=this.getPanes();d?e.fadeOut(d):e.hide(),e.eq(a).fadeIn(c.fadeInSpeed,b)},slide:function(a,b){var c=this.getConf();this.getPanes().slideUp(c.slideUpSpeed),this.getPanes().eq(a).slideDown(c.slideDownSpeed,b)},ajax:function(a,b){this.getPanes().eq(0).load(this.getTabs().eq(a).attr("href"),b)}},c,d;a.tools.tabs.addEffect("horizontal",function(b,e){if(!c){var f=this.getPanes().eq(b),g=this.getCurrentPane();d||(d=this.getPanes().eq(0).width()),c=!0,f.show(),g.animate({width:0},{step:function(a){f.css("width",d-a)},complete:function(){a(this).hide(),e.call(),c=!1}}),g.length||(e.call(),c=!1)}});function e(c,d,e){var f=this,g=c.add(this),h=c.find(e.tabs),i=d.jquery?d:c.children(d),j;h.length||(h=c.children()),i.length||(i=c.parent().find(d)),i.length||(i=a(d)),a.extend(this,{click:function(c,d){var i=h.eq(c);typeof c=="string"&&c.replace("#","")&&(i=h.filter("[href*="+c.replace("#","")+"]"),c=Math.max(h.index(i),0));if(e.rotate){var k=h.length-1;if(c<0)return f.click(k,d);if(c>k)return f.click(0,d)}if(!i.length){if(j>=0)return f;c=e.initialIndex,i=h.eq(c)}if(c===j)return f;d=d||a.Event(),d.type="onBeforeClick",g.trigger(d,[c]);if(!d.isDefaultPrevented()){b[e.effect].call(f,c,function(){j=c,d.type="onClick",g.trigger(d,[c])}),h.removeClass(e.current),i.addClass(e.current);return f}},getConf:function(){return e},getTabs:function(){return h},getPanes:function(){return i},getCurrentPane:function(){return i.eq(j)},getCurrentTab:function(){return h.eq(j)},getIndex:function(){return j},next:function(){return f.click(j+1)},prev:function(){return f.click(j-1)},destroy:function(){h.unbind(e.event).removeClass(e.current),i.find("a[href^=#]").unbind("click.T");return f}}),a.each("onBeforeClick,onClick".split(","),function(b,c){a.isFunction(e[c])&&a(f).bind(c,e[c]),f[c]=function(b){b&&a(f).bind(c,b);return f}}),e.history&&a.fn.history&&(a.tools.history.init(h),e.event="history"),h.each(function(b){a(this).bind(e.event,function(a){f.click(b,a);return a.preventDefault()})}),i.find("a[href^=#]").bind("click.T",function(b){f.click(a(this).attr("href"),b)}),location.hash&&e.tabs=="a"&&c.find("[href="+location.hash+"]").length?f.click(location.hash):(e.initialIndex===0||e.initialIndex>0)&&f.click(e.initialIndex)}a.fn.tabs=function(b,c){var d=this.data("tabs");d&&(d.destroy(),this.removeData("tabs")),a.isFunction(c)&&(c={onBeforeClick:c}),c=a.extend({},a.tools.tabs.conf,c),this.each(function(){d=new e(a(this),b,c),a(this).data("tabs",d)});return c.api?d:this}})(jQuery);
|
20 |
+
(function(a){a.tools=a.tools||{version:"v1.2.6"},a.tools.tooltip={conf:{effect:"toggle",fadeOutSpeed:"fast",predelay:0,delay:30,opacity:1,tip:0,fadeIE:!1,position:["top","center"],offset:[0,0],relative:!1,cancelDefault:!0,events:{def:"mouseenter,mouseleave",input:"focus,blur",widget:"focus mouseenter,blur mouseleave",tooltip:"mouseenter,mouseleave"},layout:"<div/>",tipClass:"tooltip"},addEffect:function(a,c,d){b[a]=[c,d]}};var b={toggle:[function(a){var b=this.getConf(),c=this.getTip(),d=b.opacity;d<1&&c.css({opacity:d}),c.show(),a.call()},function(a){this.getTip().hide(),a.call()}],fade:[function(b){var c=this.getConf();!a.browser.msie||c.fadeIE?this.getTip().fadeTo(c.fadeInSpeed,c.opacity,b):(this.getTip().show(),b())},function(b){var c=this.getConf();!a.browser.msie||c.fadeIE?this.getTip().fadeOut(c.fadeOutSpeed,b):(this.getTip().hide(),b())}]};function c(b,c,d){var e=d.relative?b.position().top:b.offset().top,f=d.relative?b.position().left:b.offset().left,g=d.position[0];e-=c.outerHeight()-d.offset[0],f+=b.outerWidth()+d.offset[1],/iPad/i.test(navigator.userAgent)&&(e-=a(window).scrollTop());var h=c.outerHeight()+b.outerHeight();g=="center"&&(e+=h/2),g=="bottom"&&(e+=h),g=d.position[1];var i=c.outerWidth()+b.outerWidth();g=="center"&&(f-=i/2),g=="left"&&(f-=i);return{top:e,left:f}}function d(d,e){var f=this,g=d.add(f),h,i=0,j=0,k=d.attr("title"),l=d.attr("data-tooltip"),m=b[e.effect],n,o=d.is(":input"),p=o&&d.is(":checkbox, :radio, select, :button, :submit"),q=d.attr("type"),r=e.events[q]||e.events[o?p?"widget":"input":"def"];if(!m)throw"Nonexistent effect \""+e.effect+"\"";r=r.split(/,\s*/);if(r.length!=2)throw"Tooltip: bad events configuration for "+q;d.bind(r[0],function(a){clearTimeout(i),e.predelay?j=setTimeout(function(){f.show(a)},e.predelay):f.show(a)}).bind(r[1],function(a){clearTimeout(j),e.delay?i=setTimeout(function(){f.hide(a)},e.delay):f.hide(a)}),k&&e.cancelDefault&&(d.removeAttr("title"),d.data("title",k)),a.extend(f,{show:function(b){if(!h){l?h=a(l):e.tip?h=a(e.tip).eq(0):k?h=a(e.layout).addClass(e.tipClass).appendTo(document.body).hide().append(k):(h=d.next(),h.length||(h=d.parent().next()));if(!h.length)throw"Cannot find tooltip for "+d}if(f.isShown())return f;h.stop(!0,!0);var o=c(d,h,e);e.tip&&h.html(d.data("title")),b=a.Event(),b.type="onBeforeShow",g.trigger(b,[o]);if(b.isDefaultPrevented())return f;o=c(d,h,e),h.css({position:"absolute",top:o.top,left:o.left}),n=!0,m[0].call(f,function(){b.type="onShow",n="full",g.trigger(b)});var p=e.events.tooltip.split(/,\s*/);h.data("__set")||(h.unbind(p[0]).bind(p[0],function(){clearTimeout(i),clearTimeout(j)}),p[1]&&!d.is("input:not(:checkbox, :radio), textarea")&&h.unbind(p[1]).bind(p[1],function(a){a.relatedTarget!=d[0]&&d.trigger(r[1].split(" ")[0])}),e.tip||h.data("__set",!0));return f},hide:function(c){if(!h||!f.isShown())return f;c=a.Event(),c.type="onBeforeHide",g.trigger(c);if(!c.isDefaultPrevented()){n=!1,b[e.effect][1].call(f,function(){c.type="onHide",g.trigger(c)});return f}},isShown:function(a){return a?n=="full":n},getConf:function(){return e},getTip:function(){return h},getTrigger:function(){return d}}),a.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","),function(b,c){a.isFunction(e[c])&&a(f).bind(c,e[c]),f[c]=function(b){b&&a(f).bind(c,b);return f}})}a.fn.tooltip=function(b){var c=this.data("tooltip");if(c)return c;b=a.extend(!0,{},a.tools.tooltip.conf,b),typeof b.position=="string"&&(b.position=b.position.split(/,?\s/)),this.each(function(){c=new d(a(this),b),a(this).data("tooltip",c)});return b.api?c:this}})(jQuery);
|
21 |
+
jQuery.noConflict();
|
package.xml
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>FourTell_Recommend_S</name>
|
4 |
+
<version>1.2.8</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="http://www.opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>Extension to connect to 4-Tell product recommendation services</summary>
|
10 |
+
<description>Extension to connect to 4-Tell product recommendation services</description>
|
11 |
+
<notes>Google Analytics code for related, crosssells, upsells</notes>
|
12 |
+
<authors><author><name>4Tell Inc</name><user>nlofgren</user><email>neil@4-tell.com</email></author></authors>
|
13 |
+
<date>2012-02-17</date>
|
14 |
+
<time>2012-02-17</time>
|
15 |
+
<contents><target name="magecommunity"><dir name="FourTell"><dir name="Recommend"><dir><dir name="Block"><dir name="Catalog"><dir name="Product"><dir name="List"><file name="Related.php" hash="05e53235542d67eef22c5db524421529"/><file name="Upsell.php" hash="a5e9ec301b6fbf6c2e72f65c7241b1a1"/></dir></dir></dir><dir name="Checkout"><dir name="Cart"><file name="Crosssell.php" hash="58eea7eb123df498f33cd33db46021a4"/><file name="Crosssellcommunity.php" hash="4a186abc5c99736b91984577357e33f5"/><file name="Crosssellenterprise.php" hash="08833d8b155fcd0490dc100eca549e9f"/></dir></dir><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="Upload.php" hash="052c32eeb22437ef2c9291f60d6dad23"/></dir></dir><dir name="Google"><dir name="Analytics"><file name="Change.php" hash="9ef76b1efeab5316d790e7b07305565c"/><file name="Code.php" hash="d412c7bbcf6d6c5a540c66a70e26ea1d"/><file name="Status.php" hash="78f2a402c8c3c61c79e510b3d9251608"/></dir></dir></dir></dir><file name="Widget.php" hash="4ad115559597f0d69058101483c200e4"/></dir><dir name="Helper"><file name="Data.php" hash="5859427c6bbe4da27d24c2eb5e4737ae"/></dir><dir name="Model"><dir name="Adminhtml"><file name="Uploadform.php" hash="aeeb0d8dfb15d2ca3e83bf343f0c8e8f"/></dir><file name="DataProcess.php" hash="bf42a3cb1489579f13b86fd913f3dee5"/><file name="Observer.php" hash="6e64e578a37e102d3d7868cee2520976"/><dir name="System"><dir name="Config"><dir name="Source"><file name="Crosssell.php" hash="7e17ad93818ea3ee31ac4bf4c858586c"/><file name="Enabled.php" hash="de9c787170a8cdc02763e65ddb24cf01"/><file name="Mode.php" hash="f830de55a2223e112010d98b1999dee9"/><file name="Related.php" hash="94101116d67f4f0a93dfd66ac6ef4c66"/><file name="Reportlevel.php" hash="5fae778206574824df9f29aa8b72a816"/><file name="Resell.php" hash="7c8e551665aad76692e98349001a1d2d"/><file name="Resultformat.php" hash="9d593961a2c6b846f8092441403c0add"/><file name="Upsell.php" hash="9acd8b40e00c60816187b03beadae0f4"/></dir><dir name="Validation"><file name="Clientid.php" hash="9fd28852ad88b253c20e06bc3e6dd108"/><file name="Email.php" hash="a9c8e7759e9efdba4624e24df8496e3e"/><file name="Maxsalesdataageinmonths.php" hash="7e0c4f922f6ad2a3047bc296cf64efed"/><file name="Mincommon.php" hash="a79c18f3f04c6031976f00aa6ba86f3f"/><file name="Minlikelihood.php" hash="281ba400ca276b66617c928effc9713d"/><file name="Numcrosssell.php" hash="a767518242e2829b0ffa9224b8b2fd09"/><file name="Numrelated.php" hash="23bab32136ce4825d71d0bb755386ae5"/><file name="Numupsell.php" hash="badbe34d0781b7239829a7d76d37d078"/><file name="Owner.php" hash="3c1569fb2ea1300665447efef6f75123"/></dir></dir></dir><dir name="Upload"><file name="Frequency.php" hash="46f8352ca038ac089e58803f93f375ec"/></dir><file name="UploadSetting.php" hash="128b0542e004ab142099727e19230034"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="UploadformController.php" hash="62837b3fb96296bb892aea6290384411"/></dir></dir><dir name="etc"><file name="config.xml" hash="e11c61a531295115b1ea90dac035b4fd"/><file name="system.xml" hash="ca678935196450f96a2de93c9e70828b"/><file name="upload.xml" hash="cb681f67371e8bb70c344b06077a8c1b"/><file name="widget.xml" hash="419db35eacdc29efeb5ab1a16f6fcaed"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="recommend.xml" hash="31c1d9505e1e75e4a84bfc8a57dbe770"/></dir><dir name="template"><dir name="recommend"><file name="uploadform.phtml" hash="75076ab74754925df55355803853d06f"/></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="recommend.xml" hash="7476d838384550b7303de09562d832db"/></dir><dir name="template"><dir name="recommend"><dir><dir name="catalog"><dir name="product"><dir name="list"><file name="related.phtml" hash="85607d036396a9676df287198d0337ed"/><file name="upsell.phtml" hash="81f56a44037d8d468f4b7b07358aa746"/></dir></dir></dir><dir name="checkout"><dir name="cart"><file name="crosssell.phtml" hash="2b0a9b82b82d1e901f85e07a1f3ef86f"/></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="FourTell_Recommend.xml" hash="868f2cca675ef1190b6a73de52469f9f"/></dir></target><target name="magelocale"><dir name="en_US"><file name="FourTell_Recommend.csv" hash="e8b3a2f7139dbe184779cec31ae2d68a"/></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="images"><file name="hori_large.png" hash="259708c04db8e05f9cc1f732cce78523"/></dir></dir></dir></dir></target><target name="mageweb"><dir name="js"><file name="jquery.tools.min.js" hash="eec050dadaa6b202aa84ac85294af744"/></dir></target></contents>
|
16 |
+
<compatible/>
|
17 |
+
<dependencies><required><php><min>5.0.0</min><max>5.4.0</max></php></required></dependencies>
|
18 |
+
</package>
|
skin/frontend/base/default/images/hori_large.png
ADDED
Binary file
|