CVE-2016-9020 (PHP, published 2017-03-07T16:59Z)
Description: value: SQL injection vulnerability in framework/modules/help/controllers/helpController.php in Exponent CMS 2.3.9 and earlier allows remote attackers to execute arbitrary SQL commands via the version parameter.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-89 \u2014 Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
Repository: https://github.com/exponentcms/exponent-cms
Files changed:
framework/core/controllers/expController.php
framework/core/expFramework.php
framework/core/models/expRecord.php
framework/core/subsystems/database/mysqli.php
framework/core/subsystems/expDatabase.php
framework/core/subsystems/expPaginator.php
framework/core/subsystems/expSettings.php
framework/core/subsystems/expString.php
framework/core/subsystems/expTheme.php
framework/modules/addressbook/controllers/addressController.php
framework/modules/administration/controllers/administrationController.php
framework/modules/banners/controllers/bannerController.php
framework/modules/blog/controllers/blogController.php
framework/modules/core/controllers/expCatController.php
framework/modules/core/controllers/expCommentController.php
framework/modules/core/controllers/expDefinableFieldController.php
framework/modules/core/controllers/expHTMLEditorController.php
framework/modules/core/controllers/expSimpleNoteController.php
framework/modules/core/controllers/expTagController.php
framework/modules/eaas/controllers/eaasController.php
framework/modules/ealerts/controllers/ealertController.php
framework/modules/ecommerce/controllers/billingController.php
framework/modules/ecommerce/controllers/ecomconfigController.php
framework/modules/ecommerce/controllers/eventregistrationController.php
framework/modules/ecommerce/controllers/orderController.php
framework/modules/ecommerce/controllers/order_statusController.php
framework/modules/ecommerce/controllers/purchaseOrderController.php
framework/modules/ecommerce/controllers/shippingController.php
framework/modules/ecommerce/controllers/storeCategoryController.php
framework/modules/ecommerce/controllers/storeController.php
framework/modules/ecommerce/controllers/taxController.php
framework/modules/ecommerce/products/models/donation.php
framework/modules/events/controllers/eventController.php
framework/modules/events/models/event.php
framework/modules/file/controllers/fileController.php
framework/modules/file/models/expFile.php
framework/modules/filedownloads/controllers/filedownloadController.php
framework/modules/forms/controllers/formsController.php
framework/modules/help/controllers/helpController.php
framework/modules/help/models/help_version.php
framework/modules/importexport/controllers/importexportController.php
framework/modules/migration/controllers/migrationController.php
framework/modules/navigation/controllers/navigationController.php
framework/modules/news/controllers/newsController.php
framework/modules/photoalbum/controllers/photosController.php
framework/modules/pixidou/controllers/pixidouController.php
framework/modules/portfolio/controllers/portfolioController.php
framework/modules/recyclebin/controllers/recyclebinController.php
framework/modules/report/controllers/reportController.php
framework/modules/search/controllers/searchController.php
framework/modules/simplepoll/controllers/simplePollController.php
framework/modules/users/controllers/loginController.php
framework/modules/users/controllers/usersController.php
Commit message: iniitial effort to greatly enhance system security (xss, sql inject, file exploit, rce, etc...)


Vulnerable code:
        'approve'  => 'Approval',
    protected $add_permissions = array();  // additional $permissions processed for this module
    public $requires_login = array(); // actions/methods which ONLY require user be logged in to access...$permissions take priority
        $tag = new expTag($this->params['tag']);
            'moduletitle' => ucfirst($modelname) . ' ' . gt('items tagged with') . ' "' . expString::sanitize($this->params['tag']) . '"',
            $id = $this->params['title'];
        $id = isset($this->params['title']) ? $this->params['title'] : (isset($this->params['id']) ? $this->params['id'] : null);
     * permission functions to aggregate a module's permissions based on add/remove permissions
    $controller = new $fullControllerName($src, $parms);    
    
    
    $perms = $controller->permissions();
    
    $common_action = null;
    //FIXME do we also need to account for actions with camelcase action/perm such as editItem ???
    if ($parms['action'] == 'update') {
    } elseif ($parms['action'] == 'edit' && (!isset($parms['id']) || $parms['id'] == 0)) {
        // action convention for controllers that manage more than one model (datatype). 
        // if you preface the name action name with a common crud action name we can check perms on 
        // it with the developer needing to specify any...better safe than sorry.
        // i.e if the action is edit_mymodel it will be checked against the edit permission
        if (stristr($parms['action'], '_')) $parts = explode("_", $parms['action']);
        $common_action = isset($parts[0]) ? $parts[0] : null;
            $msg = empty($controller->requires_login[$perm_action]) ? gt("You must be logged in to perform this action") : $controller->requires_login[$perm_action];
            $msg = empty($controller->requires_login[$common_action]) ? gt("You must be logged in to perform this action") : $controller->requires_login[$common_action];
    } 
    
    
}   
    
    
    
    
    
    // get the common configuration files    
    // look for a config form for this module's current view    
    
    
    // set path information 
    
    
    
        // retrieve objects 
            // Otherwise we assume that in inbound is an array or Object to be processed as is.        
        // setup the exception array if it's not there.  This array tells the getAssociatedObjectsForThisModel() function which 
            // if not, then we check to see if we had a previous value in this particular 
            // this is good for when the developer is trying to update just a field or two 
            // in an existing record. 
        //$this->saveAssociatedObjects(); 
        // mapped view and src hasn't been passed in via link to the form 
    function columnUpdate($table, $col, $val, $where=1) {         
        //fwrite($lfh, $sql . "\n");    
        //fclose($lfh);                 
       
        $res = mysqli_query($this->connection, $sql); 
        
    
        //if ($table=="text") eDebug($object,true); 
            //if ($table=="text") eDebug($object,true); 
                    $val = serialize($val);   
        //if ($table == 'text') eDebug($sql,true);        
	 * Unescape a string based on the database connection
    function selectArraysBySql($sql) {        
		
	 * Unescape a string based on the database connection
   	 * Unescape a string based on the database connection
 * 
 *  
 *      'where'=>1, 
 * 
	public $where = '';	
     */	
		global $router,$db;
        $this->limit = empty($params['limit']) ? 0 : $params['limit'];
		$this->order = empty($params['order']) ? 'id' : $params['order'];
		$this->dir = empty($params['dir']) ? 'ASC' : $params['dir'];
		$this->src = empty($params['src']) ? null : $params['src'];
	
		
		
		$this->order_direction = $this->dir;	
                        
			
		}	
			
		
		
		
		
		        $this->last_pagelink = $this->total_pages; 
		for($i=$this->first_pagelink; $i<=$this->last_pagelink; $i++) { 
		} 	
		
         
		
       
        
	
        $func = new ReflectionClass($this);       
                $newParams[$propname] = $params[$propname];                
            }               
        }        
                $newParams[$propname] = $params[$propname];                
            }               
        }        
        
    
            
            
            
                
                } 
                
                    
                
    
        }    
    
			
			
            
				
				} 
				$params['order'] = $col;      				                        
				
				if (!empty($col)) {	
                        $params['dir'] = 'ASC'; 
                        $params['dir'] = 'DESC'; 
                        $params['dir'] = 'ASC'; 
                    }	
				}                  								
	
                $str .= "'" . $value . "'";
                    $str .= "'" . str_replace("'", "\'", $value) . "'";  //FIXME is this still necessary since we stripslashes above???
                    $str .= "'" . str_replace("'", '', $value) . "'";
?>
	} 
		}		
		
			$str = stripcslashes($str);  
        $str = str_replace("&lsquo;","'",$str);        
        $str = str_replace("�","-", $str); 
        $str = str_replace("\r\n"," ",$str); 
        $str = str_replace("�","(R)",$str);        
        $str = str_replace("&","&amp;",$str);      
		$str = str_replace(">","&gt;",$str);      		
        global $db;
//	        $str = @mysqli_real_escape_string($db->connection,trim(str_replace("�", "&trade;", $str)));
//            $str = @mysql_real_escape_string(trim(str_replace("�", "&trade;", $str)),$db->connection);
        $str = @$db->escapeString($db->connection, trim(str_replace("�", "&trade;", $str)));
        $str = '<title>' . $metainfo['title'] . "</title>\n";
            $str .= "\t" . '<meta http-equiv="Content-Type" content="text/html; charset=' . LANG_CHARSET . '" ' . XHTML_CLOSING . '>' . "\n";
            $str .= "\t" . '<meta content="' . $locale . '" http-equiv="Content-Language" ' . XHTML_CLOSING . '>' . "\n";

            // turn off ie compatibility mode which will break the display
            $str .= "\t" . '<meta http-equiv="X-UA-Compatible" content="IE=edge"' . XHTML_CLOSING . '>' . "\n";
?>
	public $useractions = array(
    );
    protected $add_permissions = array(
        'import' => 'Import External Addresses',
//        'export' => 'Export External Addresses'
    
    
	
			if ($count == 0) 
            //user is not logged in, but allow anonymous checkout is enabled so we'll check 
            $this->params['is_shipping'] = 1; 
		expHistory::back(); 
	
        {    
                if ($address->is_shipping) 
    
        $db->setUniqueFlag($object, 'addresses', $this->params['is_what'], "user_id=" . $user->id);
        expHistory::back(); 
    
        
        $gr = new geoRegion();             
        
    
            $gc->active = true;            
            $gc->save();            
            $gc = new geoCountry($this->params['country_default']);            
            $db->setUniqueFlag($gc,'geo_country','is_default','id=' . $gc->id);    
            $gc->refresh();            
            $gr->save();            
    protected $add_permissions = array(
        'mass'=>'Mass Mailing',
        'update'=>'Update Settings',
        'change'=>'Change Settings',
        'save'=>'Save Settings',
        
        
    
        
	public function fixsessions() {
	    global $db;

//		$test = $db->sql('CHECK TABLE '.$db->prefix.'sessionticket');
		$fix = $db->sql('REPAIR TABLE '.$db->prefix.'sessionticket');
		flash('message', gt('Sessions Table was Repaired'));
		expHistory::back();
	}
//					$section = $db->selectObject('sectionref',"module='containermodule' AND source='".$eloc->src."'");
		ksort($menu);		
        
        
    
    
    
    
    }	
    
        
        
        
        
        
        
    public $useractions = array(
        'showall'=>'Display Banner(s)'
    );
    
            // randomly grab one banner to be displayed 
            $where = 'id IN ('.implode(',', $this->config['banners']).')';    
            foreach($banners as $banner) {            
        
    
    
    
        
		
    
        }  
	
	
        
        $filename = 'banner_export' . date("m-d-Y") . '.csv';        
        fclose($fh);        
        
        // let the user know we did stuff.      
    protected $add_permissions = array(
        'approve'=>"Approve Comments",
        'import'=>'Import Blog Items',
        'export'=>'Export Blog Items'
    );
            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>$this->params['title']));
        $modelname = empty($this->params['model']) ? $this->basemodel_name : $this->params['model'];
    protected $add_permissions = array(
        'approve'=>"Approve Comments"
    );
   	protected $remove_permissions = array(
    
            expHistory::back();  
	    } 
        
        
	}	
	
	    
            'sql'=>$sql, 
        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
            'sql'=>$sql, 
        
            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
        }        
        
			'content_id'=>$this->params['content_id'], 
        
        
                        
        
		
		
	
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
	    
	
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
	
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
	    
        
        $db->delete($comment->attachable_table, 'expcomments_id='.$this->params['id']);        
        
	
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
        
        
        $mail = new expMail();        
        
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
        $mail = new expMail();        
        
        assign_to_template(array('record'=>$record,'tag'=>$tag));  //FIXME $record & $tag are undefined
		
	
		 
		if ($ctl) { 
		assign_to_template(array('form_html'=>$form->toHTML(), 'types'=>$types[$control_type]));			
	
	function save() {	
		if (call_user_func(array($_POST['control_type'],'useGeneric')) == true) { 	
		
	
	
			
		
    protected $add_permissions = array(
        'activate' => "Activate",
        'preview'  => "Preview Editor Toolbars"
    );

    protected $add_permissions = array(
        'approve'=>"Approve Comments"
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        if (empty($this->params['formtitle'])) 
        
    }    
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
            'sql'=>$sql, 
        
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
        $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
        $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
        $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
        
        
        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
        
            'sql'=>$sql, 
        
        // count the unapproved comments
            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
        }        
 
            'unapproved'=>$unapproved, 
            'content_id'=>$this->params['content_id'], 
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
        // if simplenotes are configed to require approvals set this to 0 otherwise we 
        
        
        
        
        
        
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
    
        
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
    
        
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
        
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
        
        $db->delete($simplenote->attachable_table, 'expsimplenote_id='.$this->params['id']);        
        
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
        $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
        $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
        $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
        
        
        
        $mail = new expMail();        
        
            $id = $this->params['title'];
    protected $add_permissions = array(
        // 'approve'=>"Approve Comments"
    );



	
    
    
        $src = empty($this->params['src']) ? null : $this->params['src'];
        
        
    
        
        
    
        $src = empty($this->params['src']) ? null : $this->params['src'];
        
        
        
            
            
        } 
        
    public function subscriptions() {
        global $db;
        
        expHistory::set('manageable', $this->params);
        // make sure we have what we need.
        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
        
        // verify the id/key pair    
        $sub = new subscribers($this->params['id']);
        if (empty($sub->id)) expQueue::flashAndFlow('error', gt('We could not find any subscriptions matching the ID and Key you provided.'));
        
        // get this users subscriptions
        $subscriptions = $db->selectColumn('expeAlerts_subscribers', 'expeAlerts_id', 'subscribers_id='.$sub->id);
        
        // get a list of all available E-Alerts
        $ealerts = new expeAlerts();
        assign_to_template(array(
            'subscriber'=>$sub,
            'subscriptions'=>$subscriptions,
            'ealerts'=>$ealerts->find('all')
        ));
    }
    
    public function subscription_update() {
        global $db;
        
        // make sure we have what we need.
        if (empty($this->params['email'])) expQueue::flashAndFlow('error', gt('You must supply an email address to sign up for email alerts.'));
        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
        
        // find the subscriber and validate the security key
        $subscriber = new subscribers($this->params['id']);
        if ($subscriber->hash != $this->params['key']) expQueue::flashAndFlow('error', gt('The security key you supplied does not match the one we have on file.'));
        
        // delete any old subscriptions and add the user to new subscriptions
        $db->delete('expeAlerts_subscribers', 'subscribers_id='.$subscriber->id);
        foreach($this->params['ealerts'] as $ea_id) {
            $obj = new stdClass();
            $obj->subscribers_id = $subscriber->id;
            $obj->expeAlerts_id = $ea_id;
            $db->insertObject($obj, 'expeAlerts_subscribers');
        }
        
        $count = count($this->params['ealerts']);
        
        if ($count > 0) {
            flash('message', gt("Your subscriptions have been updated.  You are now subscriber to")." ".$count.' '.gt('E-Alerts.'));
        } else {
            flash('error', gt("You have been unsubscribed from all E-Alerts."));
        }
        
        expHistory::back();
    }
    
    public function signup() {
        global $db;
        // check the anti-spam control
        expValidator::check_antispam($this->params, gt("Anti-spam verification failed.  Please try again."));
        
        // make sure we have what we need.
        if (empty($this->params['email'])) expQueue::flashAndFlow('error', gt('You must supply an email address to sign up for email alerts.'));
        if (empty($this->params['ealerts'])) expQueue::flashAndFlow('error', gt('You did not select any E-Alert topics to subscribe to.'));
        
        // find or create the subscriber
        $id = $db->selectValue('subscribers', 'id', 'email="'.$this->params['email'].'"');
        $subscriber = new subscribers($id);
        if (empty($subscriber->id)) {
            $subscriber->email = trim($this->params['email']);
            $subscriber->hash = md5($subscriber->email.time());
            $subscriber->save();
        }
        
        // delete any old subscriptions and add the user to new subscriptions
        $db->delete('expeAlerts_subscribers', 'subscribers_id='.$subscriber->id);
        foreach($this->params['ealerts'] as $ea_id) {
            $obj = new stdClass();
            $obj->subscribers_id = $subscriber->id;
            $obj->expeAlerts_id = $ea_id;
            $db->insertObject($obj, 'expeAlerts_subscribers');
        }
  
        // send a confirmation email to the user.    
        $ealerts = $db->selectObjects('expeAlerts', 'id IN ('.implode(',', $this->params['ealerts']).')');
        $body = expTemplate::get_template_for_action($this, 'email/confirmation_email', $this->loc);
        $body->assign('ealerts', $ealerts);
        $body->assign('subscriber', $subscriber);
        
        $mail = new expMail();
        $mail->quickSend(array(
                'html_message'=>$body->render(),
		        'to'=>$subscriber->email,
                'from'=>array(trim(SMTP_FROMADDRESS) => trim(ORGANIZATION_NAME)),
		        'subject'=>gt('Please confirm your E-Alert subscriptions'),
        ));
        
        redirect_to(array('controller'=>'ealert', 'action'=>'pending', 'id'=>$subscriber->id));
    }
    
    public function pending() {
        
        // make sure we have what we need.
        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('Your subscriber ID was not supplied.'));
        // find the subscriber and their pending subscriptions
        $ealerts = expeAlerts::getPendingBySubscriber($this->params['id']);
        $subscriber = new subscribers($this->params['id']);
        
        // render the template
        assign_to_template(array(
            'subscriber'=>$subscriber,
            'ealerts'=>$ealerts
        ));
    }
    
    public function confirm() {
        global $db;
        
        // make sure we have what we need.
        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
        
        // verify the id/key pair    
        $id = $db->selectValue('subscribers','id', 'id='.$this->params['id'].' AND hash="'.$this->params['key'].'"');
        if (empty($id)) expQueue::flashAndFlow('error', gt('We could not find any subscriptions matching the ID and Key you provided.'));
        
        // activate this users pending subscriptions
        $sub = new stdClass();
        $sub->enabled = 1;
        $db->updateObject($sub, 'expeAlerts_subscribers', 'subscribers_id='.$id);
        
        // find the users active subscriptions
        $ealerts = expeAlerts::getBySubscriber($id);
        assign_to_template(array(
            'ealerts'=>$ealerts
        ));
    }
    protected $add_permissions = array(
        'activate'=>'Activate Payment Options'
    
	
		
	
	    
                                'body'=>$calcobj->description(), 
        
	
	public function activate(){	
    
	
    
        
        $record = new optiongroup_master($id);       
    
        
        
    
        
        
        
        
    
        
    
        
        $record = new option_master($params);      
    
    function update_option_master() {        
        
        
            
        
    
    
    
		
    
        
        
        $groups = array( 
       // eDebug($discount);                        
       
       
        
    
        
    
    public function activate_discount(){    
        
    
	
	    
	
    
        
        
        $gc = new geoCountry();             
        
        $gr = new geoRegion();             
        
    }   
	
		$gc = new geoCountry();             
        
        $gr = new geoRegion();             
	 
		
		
	


    protected $add_permissions = array(
        'view_registrants'=> 'View Registrants',
        'emailRegistrants'=> 'Email Registrants',
    );

    protected $add_permissions = array(
        'showall'             => 'Manage',
        'show'                => 'View Orders',
        'setStatus'           => 'Change Status',
        'edit_payment_info'   => 'Edit Payment Info',
        'edit_address'        => 'Edit Address',
        'edit_order_item'     => 'Edit Order Item',
        'add_order_item'      => 'Add Order Item',
        'save_new_order_item'=> 'Save New Order Item',
        'edit_totals'         => 'Edit Totals',
        'edit_invoice_id'     => 'Edit Invoice Id',
        'update_sales_reps'   => 'Manage Sales Reps',
        'quickfinder'=> 'Do a quick order lookup',
        'edit_shipping_method'=> 'Edit Shipping Method',
        'create_new_order'    => 'Create A New Order',
        'createReferenceOrder'=> 'Create Reference Order',
        'save_reference_order'=> 'Save Reference Order'
            
                    $db->delete('orderitems', 'orders_id='.$cart->id);    
                
            }           
            
        //viewing of the order?        
                    //eDebug($order['id'] . ": " . $timer->mark());                        
            
            //eDebug($note,true);            
        // figure out what metadata to pass back based on the action 
        /*eDebug($this->params); 
        //eDebug($order,true); 
        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));        
        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true); 
            //$newOi->products_tax = 0;        
        //eDebug($order,true); 
        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));        
        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true); 
            //$oi->product->optiongroup = $parProd->optiongroup;   
            /*if ($uif['is_required'] || (!$uif['is_required'] && strlen($params['user_input_fields'][$uifkey]) > 0)) 
                    //flash('error', 'test');    
                    //redirect_to(array('controller'=>cart, 'action'=>'displayForm', 'form'=>'addToCart', 'product_id'=>$this->id, 'product_type'=>$this->product_type));  
                    
                    //flash('error', );    
                    //redirect_to(array('controller'=>cart, 'action'=>'displayForm', 'form'=>'addToCart', 'product_id'=>$this->id, 'product_type'=>$this->product_type));      
                } 
        //eDebug($oi);        
            //we'll send over the product_id of the parent, along with id's and quantities of children we're adding 
        
                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order[0]->id));            
                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order->id));            
            flashAndFlow('message','Invalid order number.');        
                //eDebug($tmpCart,true); 
        $sql .= "from " . $db->prefix . "addresses as a "; //R JOIN " . 
        $sql .= "from " . $db->prefix . "external_addresses as a "; //R JOIN " . 
    
        
    
        
    
    
    
    
    
    
    
    

	protected $add_permissions = array(
        'manage'=>'Manage Purchase Orders',
        'edit'=>'Edit Purchase Orders',
        'manage_vendors'=>'Manage Vendors',
        'edit_vendor'=>'Edit Vendor',
        'update_vendor'=>'Update Vendor',
        'delete_vendor'=>'Delete vendors',
	
	
		
		
	
    
		
	
		
		
	
		
	
		
	
		
	
		
		
    
    protected $add_permissions = array(
        'toggle'=>'Enable/Disable Options'
		
		
		
	
		    
		        $sm->to = empty($this->params['shpmessageto']) ? null : $this->params['shpmessageto'];   
		        $sm->from = empty($this->params['shpmessagefrom']) ? null : $this->params['shpmessagefrom']; 
		        $sm->message = empty($this->params['shpmessage']) ? null : $this->params['shpmessage']; 
		
		$ar->send();		
	
        
        
	
	
	    
                    $id = $db->selectValue('shippingcalculator', 'id', 'calculator_name="'.$classname.'"');                    
                        if ($calcobj->isSelectable() == true) {                            
	
		
    
        $conf = serialize($calc->parseConfig($this->params));        
	
		
	
	
    static function displayname() {
        return gt("e-Commerce Category Manager");
    }

    static function description() {
        return gt("This module is for managing categories in your store.");
    }

    protected $add_permissions = array(

        //         
        //         //  $this->tags[$i]->draggable = $this->draggable; 
        //         //  $this->tags[$i]->checkable = $this->checkable; 
        // $obj = json_encode($categories);  
            // Trees mapped            
                    
                }        
                
        // 
        // 
        // 
        // 
        // 
        // 
        // 
        // 


    //protected $permissions = array_merge(array("test"=>'Test'), array('copyProduct'=>"Copy Product"));
    protected $add_permissions = array(
        'copyProduct'                 => "Copy Product",
        'delete_children'             => "Delete Children",
        'reimport'                    => 'ReImport Products',
        'findDupes'                   => 'Fix Duplicate SEF Names',
        'manage_sales_reps'           => 'Manage Sales Reps',
        'batch_process'               => 'Batch capture order transactions',
        'process_orders'              => 'Batch capture order transactions',
        'import_external_addresses'   => 'Import addresses from other sources',
        'showallImpropercategorized'  => 'View products in top level categories that should not be',
        'showallUncategorized'        => 'View all uncategorized products',
        'nonUnicodeProducts'          => 'View all non-unicode charset products',
        'cleanNonUnicodeProducts'     => 'Clean all non-unicode charset products',
        'uploadModelAliases'          => 'Upload model aliases',
        'processModelAliases'         => 'Process uploaded model aliases',
        'saveModelAliases'            => 'Save uploaded model aliases',
        'deleteProcessedModelAliases' => 'Delete processed uploaded model aliases',
        'delete_model_alias'          => 'Process model aliases',
        'update_model_alias'          => 'Save model aliases',
        'edit_model_alias'            => 'Delete model aliases',
        'import'                      => 'Import Products',
        'export'                      => 'Export Products',
    );

            $ancestors = $this->category->pathToNode();       
            {                   
            $ancestors = $this->category->pathToNode();       
            //eDebug($editable_options[$group->title]);        
        //eDebug($product_type);  
        //eDebug($this->params,true);        
        if (empty($product->id)) // || empty($product->previous_id)) 
            //fwrite($lfh, "Deleting:" . $ctd->id . "\n");                             
        //$sql .= "GROUP BY p.id "; 
        $req = 'a29f9shsgh32hsf80s7';        
        {   
            $successSet[$count]['message'] = "Sucessfully imported row " . $count . ", order: " . $data[2] . "<br/>";                
            $successSet[$count]['shipping_tracking_number'] = '1ZNF453937547';    
        {   
            $data[2] = $inv + $count;                
            $amt += $count*$count;        
        
        assign_to_template(array('errorSet'=>$errorSet, 'successSet'=>$successSet));     
        //eDebug($this->params,true); 
        //eDebug($data);      
                        //just need to set the order shipping info, check and see if we send user an email, and set statuses.  
                        //shipping info:                                      
                        //$failMessage = "Attempted to delay capture order " . $data[2] . " and it failed with the following error: " . $result->errorCode . " - " .$result->message;   
                            
                            $order->save();                             
                        //continue;   
                    //dont suppose we do anything here, as it may be set to approved manually 
                    //$errorSet[$count] = "Order " . $data[2] . " does not use a billing method with delayed capture ability.";  
            //eDebug($product);        
        //eDebug($data);      
    protected $add_permissions = array(
        'manage_zones' => 'Manages Zones',
        'edit_zone'    => 'Add/Edit Zone',
        'update_zone'  => 'Update Zone',
        'delete_zone'  => 'Delete Zone'
    );

        $sql .= empty($order) ? '' : ' ORDER BY ' . $order;
            $sql .= empty($limit) ? '' : ' LIMIT ' . $limitstart . ',' . $limit;
<?php

##################################################
#
# Copyright (c) 2004-2016 OIC Group, Inc.
#
# This file is part of Exponent
#
# Exponent is free software; you can redistribute
# it and/or modify it under the terms of the GNU
# General Public License as published by the Free
# Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# GPL: http://www.gnu.org/licenses/gpl.txt
#
##################################################

/**
 * @subpackage Controllers
 * @package    Modules
 */

class eventController extends expController {
//    public $basemodel_name = 'event';
    public $useractions = array(
        'showall' => 'Show Calendar',
    );
//    public $codequality = 'beta';

    public $remove_configs = array(
        'comments',
        'ealerts',
//        'facebook',
        'files',
        'pagination',
        'rss',
//        'twitter',
    );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)

    static function displayname() {
        return "Events";
    }

    static function description() {
        return "Manage events and schedules, and optionally publish them.";
    }

    static function author() {
        return "Dave Leffler";
    }

    static function isSearchable() {
        return true;
    }

    function searchName() {
        return gt("Calendar Event");
    }

    function searchCategory() {
        return gt('Event');
    }

    /**
     * can this module import data?
     *
     * @return bool
     */
    public static function canImportData() {
        return true;
    }

    function showall() {
        global $user;

        expHistory::set('viewable', $this->params);
        $locsql = $this->aggregateWhereClause();
        $time = (isset($this->params['time']) ? $this->params['time'] : time());
        assign_to_template(array(
            'time' => $time,
            'daynames' => event::dayNames(),
        ));

        $regcolor = !empty($this->config['registrations_color']) ? $this->config['registrations_color'] : null;

        $ed = new eventdate();
        $viewtype = 'default';
        $viewrange = 'all';
        $view = !empty($this->params['view']) ? $this->params['view'] : 'showall';
        switch ($view) {
            case 'showall_Administration':
                $viewtype = "administration";
                break;
            case 'showall_Past Events':
                $viewrange = "past";
                break;
            case 'showall_Monthly Summary':
            case 'showall_Mini-Calendar':
            case 'minical':
                $viewtype = "minical";
                break;
            case 'showall_Monthly List':
            case 'showall_List':
            case 'monthlist':
                $viewtype = "byday";
                $viewrange = "month";
                break;
            case 'showall_Week':
            case 'week':
                $viewtype = "byday";
                $viewrange = "week";
                break;
            case 'showall_Day':
            case 'day':
                $viewtype = "byday";
                $viewrange = "day";
                break;
            case 'showall_announcement':
            case 'showall_Upcoming Events':
            case 'showall_Upcoming Events - Headlines':
                $viewrange = "upcoming";
                break;
            case 'showall':
            case 'month':
                $viewtype = "monthly";
                break;
            default :
                $view_params = explode('_',$view);
                if (!empty($view_params[1])) $viewtype = $view_params[1];
                if (!empty($view_params[2])) $viewrange = $view_params[2];
        }  // end switch $view

        switch ($viewtype) {
            case "minical":
                $monthly = expDateTime::monthlyDaysTimestamp($time);
                $info = getdate($time);
                $timefirst = mktime(0, 0, 0, $info['mon'], 1, $info['year']);
                $now = getdate(time());
                $currentday = $now['mday'];
                $endofmonth = date('t', $time);
                foreach ($monthly as $weekNum => $week) {
                    foreach ($week as $dayNum => $day) {
                        if ($dayNum == $now['mday']) {
                            $currentweek = $weekNum;
                        }
                        if ($dayNum <= $endofmonth) {
//                            $monthly[$weekNum][$dayNum]['number'] = ($monthly[$weekNum][$dayNum]['ts'] != -1) ? $db->countObjects("eventdate", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($day['ts']) . " AND date <= " . expDateTime::endOfDayTimestamp($day['ts'])) : -1;
                            $monthly[$weekNum][$dayNum]['number'] = ($monthly[$weekNum][$dayNum]['ts'] != -1) ? $ed->find("count", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($day['ts']) . " AND date <= " . expDateTime::endOfDayTimestamp($day['ts'])) : -1;
                        }
                    }
                }
                $prevmonth = mktime(0, 0, 0, date("m", $timefirst) - 1, date("d", $timefirst) + 10, date("Y", $timefirst));
                $nextmonth = mktime(0, 0, 0, date("m", $timefirst) + 1, date("d", $timefirst) + 10, date("Y", $timefirst));
                assign_to_template(array(
                    "monthly"     => $monthly,
                    "currentweek" => $currentweek,
                    "currentday"  => $currentday,
                    "now"         => $timefirst,
                    "prevmonth"   => $prevmonth,
                    "thismonth"   => $timefirst,
                    "nextmonth"   => $nextmonth,
                ));
                break;  // end switch $viewtype minicalendar
            case "byday":  //note aggregates events by groups of days
                // Remember this is the code for weekly view and monthly listview
                // Test your fixes on both views
                //   		$startperiod = 0;
                //			$totaldays = 0;
                switch ($viewrange) {
                    case "day":
                        $startperiod = expDateTime::startOfDayTimestamp($time);
                        $totaldays = 1;
                        $next = expDateTime::endOfDayTimestamp($startperiod);
                        if (!empty($this->config['starttype'])) $startperiod = $time;
                        $this->params['time'] = $time;
                        assign_to_template(array(
                            "prev_timestamp3" => strtotime('-3 days', $startperiod),
                            "prev_timestamp2" => strtotime('-2 days', $startperiod),
                            "prev_timestamp"  => strtotime('-1 days', $startperiod),
                            "next_timestamp"  => strtotime('+1 days', $startperiod),
                            "next_timestamp2" => strtotime('+2 days', $startperiod),
                            "next_timestamp3" => strtotime('+3 days', $startperiod),
                            'params'      => $this->params
                        ));
                        break;
                    case "week":
                        $startperiod = expDateTime::startOfWeekTimestamp($time);
                        $totaldays = 7;
                        $next = strtotime('+7 days', $startperiod);
//                        $next = expDateTime::endOfWeekTimestamp($startperiod);
                        if (!empty($this->config['starttype'])) $startperiod = $time;
                        $this->params['time'] = $time;
                        assign_to_template(array(
                            "prev_timestamp3" => strtotime('-21 days', $startperiod),
                            "prev_timestamp2" => strtotime('-14 days', $startperiod),
                            "prev_timestamp"  => strtotime('-7 days', $startperiod),
                            "next_timestamp"  => $next,
                            "next_timestamp2" => strtotime('+14 days', $startperiod),
                            "next_timestamp3" => strtotime('+21 days', $startperiod),
                            'params'      => $this->params
                        ));
                        break;
                    case "twoweek":
                        $startperiod = expDateTime::startOfWeekTimestamp($time);
                        $totaldays = 14;
                        $next = strtotime('+14 days', $startperiod);
                        if (!empty($this->config['starttype'])) $startperiod = $time;
                        assign_to_template(array(
                            "prev_timestamp3" => strtotime('-42 days', $startperiod),
                            "prev_timestamp2" => strtotime('-28 days', $startperiod),
                            "prev_timestamp"  => strtotime('-14 days', $startperiod),
                            "next_timestamp"  => $next,
                            "next_timestamp2" => strtotime('+28 days', $startperiod),
                            "next_timestamp3" => strtotime('+42 days', $startperiod),
                        ));
                        break;
                    case "month":
                    default: // range = month
                        $startperiod = expDateTime::startOfMonthTimestamp($time);
                        $totaldays = date('t', $time);
                        $next = strtotime('+1 months', $startperiod);
//                        $next = expDateTime::endOfMonthTimestamp($startperiod);
                        $this->params['time'] = $time;
                        assign_to_template(array(
                            "prev_timestamp3" => strtotime('-3 months', $startperiod),
                            "prev_timestamp2" => strtotime('-2 months', $startperiod),
                            "prev_timestamp"  => strtotime('-1 months', $startperiod),
                            "next_timestamp"  => $next,
                            "next_timestamp2" => strtotime('+2 months', $startperiod),
                            "next_timestamp3" => strtotime('+3 months', $startperiod),
                            'params'      => $this->params
                        ));
                        break;
                }  // end switch $viewrange

                //                $days = array();
                // added per Ignacio
                //			$endofmonth = date('t', $time);
                $extitems = $this->getExternalEvents($startperiod, $next);
                if (!empty($this->config['aggregate_registrations'])) 
                    $regitems = eventregistrationController::getRegEventsForDates($startperiod, $next, $regcolor);
                for ($i = 1; $i <= $totaldays; $i++) {
                    //                    $info = getdate($time);
                    //                    switch ($viewrange) {
                    //                        case "week":
                    //                            $start = mktime(0,0,0,$info['mon'],$i,$info['year']);  //FIXME this can't be right?
                    //                            break;
                    //                        case "twoweek":
                    ////                            $start = mktime(0,0,0,$info['mon'],$info['mday']+($i-1),$info['year']);  //FIXME this can't be right?
                    //                  		    $start = $startperiod + ($i*86400);
                    //                            break;
                    //                        default:  // range = month
                    //                            $start = mktime(0,0,0,$info['mon'],$i,$info['year']);
                    //                    }
                    $start = expDateTime::startOfDayTimestamp($startperiod + ($i * 86400) - 86400);
                    $edates = $ed->find("all", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start));
//                    $days[$start] = $this->getEventsForDates($edates, true, isset($this->config['only_featured']) ? true : false);
                    $days[$start] = $this->event->getEventsForDates($edates, true, isset($this->config['only_featured']) ? true : false);
                    //                    for ($j = 0; $j < count($days[$start]); $j++) {
                    //                        $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$days[$start][$j]->id);
                    //                        $days[$start][$j]->permissions = array(
                    //                            "manage"=>(expPermissions::check("manage",$thisloc) || expPermissions::check("manage",$this->loc)),
                    //                            "edit"=>(expPermissions::check("edit",$thisloc) || expPermissions::check("edit",$this->loc)),
                    //                            "delete"=>(expPermissions::check("delete",$thisloc) || expPermissions::check("delete",$this->loc))
                    //                        );
                    //                    }
                    if (!empty($extitems[$start]))
                        $days[$start] = array_merge($extitems[$start], $days[$start]);
                    if (!empty($regitems[$start]))
                        $days[$start] = array_merge($regitems[$start], $days[$start]);
                    $days[$start] = expSorter::sort(array('array' => $days[$start], 'sortby' => 'eventstart', 'order' => 'ASC'));
                }
                assign_to_template(array(
                    "time" => $startperiod,
                    'days' => $days,
                    "now"  => $startperiod,
                ));
                break;  // end switch $viewtype byday
            case "monthly":  //note this is a simply array of events for the requested month
                // build a month array of weeks with an array of days
                //                $monthly = array();
                //                $counts = array();
                $info = getdate($time);
                $nowinfo = getdate(time());
                if ($info['mon'] != $nowinfo['mon']) $nowinfo['mday'] = -10;
                // Grab non-day numbers only (before end of month)
//                $week = 0;
                $currentweek = -1;
                $timefirst = mktime(0, 0, 0, $info['mon'], 1, $info['year']);
                $week = (int)date('W',$timefirst);
                if ($week >= 52 && $info['mon'] == 1) $week = 1;
                $infofirst = getdate($timefirst);
                $monthly[$week] = array(); // initialize for non days
                $counts[$week] = array();
                if (($infofirst['wday'] == 0) && (DISPLAY_START_OF_WEEK == 1)) {
                    for ($i = -6; $i < (1 - DISPLAY_START_OF_WEEK); $i++) {
                        $monthly[$week][$i] = array();
                        $counts[$week][$i] = -1;
                    }
                    $weekday = $infofirst['wday'] + 7; // day number in grid.  if 7+, switch weeks
                } else {
                    for ($i = 1 - $infofirst['wday']; $i < (1 - DISPLAY_START_OF_WEEK); $i++) {
                        $monthly[$week][$i] = array();
                        $counts[$week][$i] = -1;
                    }
                    $weekday = $infofirst['wday']; // day number in grid.  if 7+, switch weeks
                }
                // Grab day counts
                $endofmonth = date('t', $time);
                $extitems = $this->getExternalEvents($timefirst, expDateTime::endOfMonthTimestamp($timefirst));
                if (!empty($this->config['aggregate_registrations'])) 
                    $regitems = eventregistrationController::getRegEventsForDates($timefirst, expDateTime::endOfMonthTimestamp($timefirst), $regcolor);
                for ($i = 1; $i <= $endofmonth; $i++) {
                    $start = mktime(0, 0, 0, $info['mon'], $i, $info['year']);
                    if ($i == $nowinfo['mday']) $currentweek = $week;
                    $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start) . ")");
//                    $monthly[$week][$i] = $this->getEventsForDates($dates, true, isset($this->config['only_featured']) ? true : false);
                    $monthly[$week][$i] = $this->event->getEventsForDates($dates, true, isset($this->config['only_featured']) ? true : false);
                    if (!empty($extitems[$start]))
                        $monthly[$week][$i] = array_merge($extitems[$start], $monthly[$week][$i]);
                    if (!empty($regitems[$start]))
                        $monthly[$week][$i] = array_merge($regitems[$start], $monthly[$week][$i]);
                    $monthly[$week][$i] = expSorter::sort(array('array' => $monthly[$week][$i], 'sortby' => 'eventstart', 'order' => 'ASC'));
                    $counts[$week][$i] = count($monthly[$week][$i]);
                    if ($weekday >= (6 + DISPLAY_START_OF_WEEK)) {
                        $week++;
                        $monthly[$week] = array(); // allocate an array for the next week
                        $counts[$week] = array();
                        $weekday = DISPLAY_START_OF_WEEK;
                    } else $weekday++;
                }
                // Grab non-day numbers only (after end of month)
                for ($i = 1; $weekday && $i < (8 + DISPLAY_START_OF_WEEK - $weekday); $i++) {
                    $monthly[$week][$i + $endofmonth] = array();
                    $counts[$week][$i + $endofmonth] = -1;
                }
                $this->params['time'] = $time;
                assign_to_template(array(
                    "currentweek" => $currentweek,
                    "monthly"     => $monthly,
                    "counts"      => $counts,
                    "prevmonth3"  => strtotime('-3 months', $timefirst),
                    "prevmonth2"  => strtotime('-2 months', $timefirst),
                    "prevmonth"   => strtotime('-1 months', $timefirst),
                    "nextmonth"   => strtotime('+1 months', $timefirst),
                    "nextmonth2"  => strtotime('+2 months', $timefirst),
                    "nextmonth3"  => strtotime('+3 months', $timefirst),
                    "now"         => $timefirst,
                    "today"       => expDateTime::startOfDayTimestamp(time()),
                    'params'      => $this->params
                ));
                break;  // end switch $viewtype monthly
            case "administration":  //note a simple list of all upcoming events, except no external nor registration events
                // Check perms and return if cant view
                if (!$user) return;
                $continue = (expPermissions::check("manage", $this->loc) ||
                    expPermissions::check("create", $this->loc) ||
                    expPermissions::check("edit", $this->loc) ||
                    expPermissions::check("delete", $this->loc)
                ) ? 1 : 0;
                $dates = $ed->find("all", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp(time()));
//                $items = $this->getEventsForDates($dates);
                $items = $this->event->getEventsForDates($dates);
                //                if (!$continue) {
                //                    foreach ($items as $i) {
                //                        $iloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$i->id);
                //                        if (expPermissions::check("edit",$iloc) ||
                //                            expPermissions::check("delete",$iloc) ||
                //                            expPermissions::check("manage",$iloc)
                //                        ) {
                //                            $continue = true;
                //                        }
                //                    }
                //                }
                if (!$continue) return;
                //                for ($i = 0; $i < count($items); $i++) {
                //                    $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$items[$i]->id);
                //    //				if ($user && $items[$i]->poster == $user->id) $canviewapproval = 1;
                //                    $items[$i]->permissions = array(
                //                        "manage"=>(expPermissions::check("manage",$thisloc) || expPermissions::check("manage",$this->loc)),
                //                        "edit"=>(expPermissions::check("edit",$thisloc) || expPermissions::check("edit",$this->loc)),
                //                        "delete"=>(expPermissions::check("delete",$thisloc) || expPermissions::check("delete",$this->loc))
                //                    );
                //                }
                $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
                assign_to_template(array(
                    'items' => $items,
                ));
                break;  // end switch $viewtype administration
            case "default":  //note a simple list of events based on $viewrange
            default;
                //                $items = null;
                //                $dates = null;
                $day = expDateTime::startOfDayTimestamp(time());
                $sort_asc = true; // For the getEventsForDates call
                //                $moreevents = false;
                switch ($viewrange) {
                    case "upcoming":  // events in the future
                        if (!empty($this->config['enable_ical']) && !empty($this->config['rss_limit']) && $this->config['rss_limit'] > 0) {
                            $eventlimit = " AND date <= " . ($day + ($this->config['rss_limit'] * 86400));
                        } else {
                            $eventlimit = "";
                        }
                        $dates = $ed->find("all", $locsql . " AND date >= " . $day . $eventlimit . " ORDER BY date ASC ");
                        $begin = $day;
                        $end = null;
                        //					$moreevents = count($dates) < $db->countObjects("eventdate",$locsql." AND date >= $day");
                        break;
                    case "past":  // events in the past
                        $dates = $ed->find("all", $locsql . " AND date < $day ORDER BY date DESC ");
                        //					$moreevents = count($dates) < $db->countObjects("eventdate",$locsql." AND date < $day");
                        $sort_asc = false;
                        $begin = null;
                        $end = $day;
                        break;
                    case "today":  // events occuring today
                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($day) . " AND date <= " . expDateTime::endOfDayTimestamp($day) . ")");
                        $begin = $day;
                        $end = expDateTime::endOfDayTimestamp($day);
                        break;
                    case "day":  // events for a specific day (same as byday day?)
                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($time) . " AND date <= " . expDateTime::endOfDayTimestamp($time) . ")");
                        $begin = expDateTime::startOfDayTimestamp($time);
                        $end = expDateTime::endOfDayTimestamp($time);
                        break;
                    case "next":  // future events
                        $dates = array($ed->find("all", $locsql . " AND date >= $time"));
                        $begin = expDateTime::startOfDayTimestamp($time);
                        $end = null;
                        break;
                    case "month": // events for a specific month (same as monthly?)
//                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp(time()) . " AND date <= " . expDateTime::endOfMonthTimestamp(time()) . ")");
                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp($time) . " AND date <= " . expDateTime::endOfMonthTimestamp($time) . ")");
                        $begin = expDateTime::startOfMonthTimestamp($time);
                        $end = expDateTime::endOfMonthTimestamp($time);
                        break;
                    case "all":  // all events
                    default;
                        $dates = $ed->find("all", $locsql);
                        $begin = null;
                        $end = null;
                }
//                $items = $this->getEventsForDates($dates, $sort_asc, isset($this->config['only_featured']) ? true : false, true);
                $items = $this->event->getEventsForDates($dates, $sort_asc, isset($this->config['only_featured']) ? true : false, true);
                if ($viewrange != 'past') {
                    $extitems = $this->getExternalEvents($begin, $end);
                    // we need to flatten these down to simple array of events
                    $extitem = array();
                    foreach ($extitems as $days) {
                        foreach ($days as $event) {
                            if (empty($event->eventdate->date) || ($viewrange == 'upcoming' && $event->eventdate->date < time()))
                                break;
                            if (empty($event->eventstart))
                                $event->eventstart = $event->eventdate->date;
                            $extitem[] = $event;
                        }
                    }
                    $items = array_merge($items, $extitem);
                    
                    if (!empty($this->config['aggregate_registrations']))
                        $regitems = eventregistrationController::getRegEventsForDates($begin, $end, $regcolor);
                    // we need to flatten these down to simple array of events
                    $regitem = array();
                    if (!empty($regitems)) foreach ($regitems as $days) {
                        foreach ($days as $value) {
                            $regitem[] = $value;
                        }
                    }
                    $items = array_merge($items, $regitem);

                    // remove today's events that have already ended
                    if ($viewtype == 'default' && $viewrange == 'upcoming') {
                        foreach ($items as $key=>$item) {
                            if (!$item->is_allday && $item->eventend < time()) {
                                //fixme we've left events ending earlier in the day, but already cancelled out tomorrow's event
                                unset($items[$key]);
                            } else {
                                break;  // they are chronological so we can end
                            }
                        }
                    }
                }
                $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
                // Upcoming events can be configured to show a specific number of events.
                // The previous call gets all events in the future from today
                // If configured, cut the array to the configured number of events
                //			if ($template->viewconfig['num_events']) {
                //				switch ($viewrange) {
                //					case "upcoming":
                //					case "past":
                //						$moreevents = $template->viewconfig['num_events'] < count($items);
                //						break;
                //				}
                //				$items = array_slice($items, 0, $template->viewconfig['num_events']);
                //			}
                //                for ($i = 0; $i < count($items); $i++) {
                //                    $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$items[$i]->id);
                //                    $items[$i]->permissions = array(
                //                        'manage'=>(expPermissions::check('manage',$thisloc) || expPermissions::check('manage',$this->loc)),
                //                        'edit'=>(expPermissions::check('edit',$thisloc) || expPermissions::check('edit',$this->loc)),
                //                        'delete'=>(expPermissions::check('delete',$thisloc) || expPermissions::check('delete',$this->loc))
                //                    );
                //                }
                assign_to_template(array(
                    'items' => $items,
                    "now"   => $day,
                ));
        }
    }

    /**
     * default view for individual item
     */
    function show() {
        expHistory::set('viewable', $this->params);
        if (!empty($this->params['date_id'])) {  // specific event instance
            $eventdate = new eventdate($this->params['date_id']);
            $eventdate->event = new event($eventdate->event_id);
        } else {  // we'll default to the first event of this series
            $event = new event($this->params['id']);
            $eventdate = new eventdate($event->eventdate[0]->id);
        }
        if (empty($eventdate->id))
            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>'event'));

        if (!empty($eventdate->event->feedback_form) && $eventdate->event->feedback_form != 'Disallow Feedback') {
            assign_to_template(array(
                'feedback_form' => $eventdate->event->feedback_form,
            ));
        }

        assign_to_template(array(
            'event' => $eventdate,
        ));
    }

    function edit() {
        global $template;

        parent::edit();
        $allforms = array();
        $allforms[""] = gt('Disallow Feedback');
        // calculate which event date is the one being edited
        $event_key = 0;
        foreach ($template->tpl->tpl_vars['record']->value->eventdate as $key=>$d) {
       	    if ($d->id == $this->params['date_id']) $event_key = $key;
       	}

        assign_to_template(array(
            'allforms'     => array_merge($allforms, expTemplate::buildNameList("forms", "event/email", "tpl", "[!_]*")),
            'checked_date' => !empty($this->params['date_id']) ? $this->params['date_id'] : null,
            'event_key'    => $event_key,
        ));
    }

    /**
     * Delete a recurring event by asking for which event dates to delete
     *
     */
    function delete_recurring() {
        $item = $this->event->find('first', 'id=' . $this->params['id']);
        if ($item->is_recurring == 1) { // need to give user options
            expHistory::set('editable', $this->params);
            assign_to_template(array(
                'checked_date' => $this->params['date_id'],
                'event'        => $item,
            ));
        } else { // Process a regular delete
            $item->delete();
        }
    }

    /**
     * Delete selected event dates for a recurring event and event if all event dates deleted
     *
     */
    function delete_selected() {
        $item = $this->event->find('first', 'id=' . $this->params['id']);
        if ($item && $item->is_recurring == 1) {
            $event_remaining = false;
            $eventdates = $item->eventdate[0]->find('all', 'event_id=' . $item->id);
            foreach ($eventdates as $ed) {
                if (array_key_exists($ed->id, $this->params['dates'])) {
                    $ed->delete();
                } else {
                    $event_remaining = true;
                }
            }
            if (!$event_remaining) {
                $item->delete(); // model will also ensure we delete all event dates
            }
            expHistory::back();
        } else {
            notfoundController::handle_not_found();
        }
    }

    function delete_all_past() {
        $locsql = $this->aggregateWhereClause();
        $ed = new eventdate();
        $dates = $ed->find("all", $locsql . " AND date < " . strtotime('-1 months', time()));
        foreach ($dates as $date) {
            $date->delete(); // event automatically deleted if all assoc eventdates are deleted
        }
        expHistory::back();
    }

    /**
   	 * get the metainfo for this module
   	 * @return array
   	 */
   	function metainfo() {
       global $router;

        $action = $router->params['action'];
        $metainfo = array('title' => '', 'keywords' => '', 'description' => '', 'canonical'=> '', 'noindex' => false, 'nofollow' => false);
        // look for event date_id which expController::metainfo won't detect
//        if (!empty($router->params['action']) && $router->params['action'] == 'show' && !isset($router->params['id']) && isset($router->params['date_id'])) {
        switch ($action) {
            case 'show':
                if (!isset($router->params['id']) && isset($router->params['date_id'])) {
                    // look up the record.
                    $object = new eventdate((int)$router->params['date_id']);
                    // set the meta info
                    if (!empty($object)) {
                        if (!empty($object->event->body)) {
                            $desc = str_replace('"',"'",expString::summarize($object->event->body,'html','para'));
                        } else {
                            $desc = SITE_DESCRIPTION;
                        }
                        if (!empty($object->expTag)) {
                            $keyw = '';
                            foreach ($object->expTag as $tag) {
                                if (!empty($keyw)) $keyw .= ', ';
                                $keyw .= $tag->title;
                            }
                        } else {
                            $keyw = SITE_KEYWORDS;
                        }
                        $metainfo['title'] = empty($object->event->meta_title) ? $object->event->title : $object->event->meta_title;
                        $metainfo['keywords'] = empty($object->event->meta_keywords) ? $keyw : $object->event->meta_keywords;
                        $metainfo['description'] = empty($object->event->meta_description) ? $desc : $object->event->meta_description;
                        $metainfo['canonical'] = empty($object->event->canonical) ? $router->plainPath() : $object->event->canonical;
                        $metainfo['noindex'] = empty($object->event->meta_noindex) ? false : $object->event->meta_noindex;
                        $metainfo['nofollow'] = empty($object->event->meta_nofollow) ? false : $object->event->meta_nofollow;
                        return $metainfo;
                        break;
                    }
                }
            default:
                return parent::metainfo();
        }
    }

    /**
     * function to build a string to pull in all events within requested date range
     */
    function build_daterange_sql($timestamp, $endtimestamp=null, $field='date', $multiday=false) {
        if (empty($endtimestamp)) {
            $date_sql = "((".$field." >= " . expDateTime::startOfDayTimestamp($timestamp) . " AND ".$field." <= " . expDateTime::endOfDayTimestamp($timestamp) . ")";
        } else {
            $date_sql = "((".$field." >= " . expDateTime::startOfDayTimestamp($timestamp) . " AND ".$field." <= " . expDateTime::endOfDayTimestamp($endtimestamp) . ")";
        }
        if ($multiday)
            $date_sql .= " OR (" . expDateTime::startOfDayTimestamp($timestamp) . " BETWEEN ".$field." AND dateFinished)";
        $date_sql .= ")";
        return $date_sql;
    }

    function send_feedback() {
        $success = false;
        if (isset($this->params['id'])) {
            $ed = new eventdate($this->params['id']);
//            $email_addrs = array();
            if ($ed->event->feedback_email != '') {
                $msgtemplate = expTemplate::get_template_for_action($this, 'email/_' . $this->params['formname'], $this->loc);
                $msgtemplate->assign('params', $this->params);
                $msgtemplate->assign('event', $ed);
                $email_addrs = explode(',', $ed->event->feedback_email);
                //This is an easy way to remove duplicates
                $email_addrs = array_flip(array_flip($email_addrs));
                $email_addrs = array_map('trim', $email_addrs);
                $mail = new expMail();
                $success += $mail->quickSend(array(
                    "text_message" => $msgtemplate->render(),
                    'to'           => $email_addrs,
                    'from'         => !empty($this->params['email']) ? $this->params['email'] : trim(SMTP_FROMADDRESS),
                    'subject'      => $this->params['subject'],
                ));
            }
        }

        if ($success) {
            flashAndFlow('message', gt('Your feedback was successfully sent.'));
        } else {
            flashAndFlow('error', gt('We could not send your feedback.  Please contact your administrator.'));
        }
    }

    function ical() {
        if (isset($this->params['date_id']) || isset($this->params['title']) || isset($this->params['src'])) {
            $cfg = new expConfig();
            $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
            foreach ($configs as $config) {
                $loc = expUnserialize($config->location_data);
                if (!empty($this->params['title'])) {
                    if ($this->params['title'] == $config->config['feed_sef_url']) {
                        $this->config = $config->config;
                        break;
                    }
                } elseif (!empty($this->params['src'])) {
                    if ($this->params['src'] == $loc->src) {
                        $this->config = $config->config;
                        break;
                    }
                }
            }
            $this->loc = $loc;

            if ($this->config['enable_ical']) {
                $ed = new eventdate();
                if (isset($this->params['date_id'])) { // get single specific event only
//                    $dates = array($db->selectObject("eventdate","id=".$this->params['date_id']));
                    $dates = $ed->find('first', "id=" . $this->params['date_id']);
                    $Filename = "Event-" . $this->params['date_id'];
                } else {
                    $locsql = $this->aggregateWhereClause();

                    $day = expDateTime::startOfDayTimestamp(time());
                    if (!empty($this->config['enable_ical']) && isset($this->config['rss_limit']) && ($this->config['rss_limit'] > 0)) {
                        $rsslimit = " AND date <= " . ($day + ($this->config['rss_limit'] * 86400));
                    } else {
                        $rsslimit = "";
                    }

                    if (isset($this->params['time'])) {
                        $time = $this->params['time']; // get current month's events
//                        $dates = $db->selectObjects("eventdate",$locsql." AND (date >= ".expDateTime::startOfMonthTimestamp($time)." AND date <= ".expDateTime::endOfMonthTimestamp($time).")");
                        $dates = $ed->find('all', $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp($time) . " AND date <= " . expDateTime::endOfMonthTimestamp($time) . ")");
                    } else {
                        $time = date('U', strtotime("midnight -1 month", time())); // previous month also
//                        $dates = $db->selectObjects("eventdate",$locsql." AND date >= ".expDateTime::startOfDayTimestamp($time).$rsslimit);
                        $dates = $ed->find('all', $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($time) . $rsslimit);
                    }
                    //			$title = $db->selectValue('container', 'title', "internal='".serialize($loc)."'");
                    $title = $this->config['feed_title'];
                    $Filename = preg_replace('/\s+/', '', $title); // without whitespace
                }

                if (!function_exists("quoted_printable_encode")) { // function added in php v5.3.0
                    function quoted_printable_encode($input, $line_max = 75) {
                        $hex = array('0', '1', '2', '3', '4', '5', '6', '7',
                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
                        $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
                        $linebreak = "=0D=0A=\r\n";
                        /* the linebreak also counts as characters in the mime_qp_long_line
                         * rule of spam-assassin */
                        $line_max = $line_max - strlen($linebreak);
                        $escape = "=";
                        $output = "";
                        $cur_conv_line = "";
                        $length = 0;
                        $whitespace_pos = 0;
                        $addtl_chars = 0;

                        // iterate lines
                        for ($j = 0, $jMax = count($lines); $j < $jMax; $j++) {
                            $line = $lines[$j];
                            $linlen = strlen($line);

                            // iterate chars
                            for ($i = 0; $i < $linlen; $i++) {
                                $c = substr($line, $i, 1);
                                $dec = ord($c);

                                $length++;

                                if ($dec == 32) {
                                    // space occurring at end of line, need to encode
                                    if (($i == ($linlen - 1))) {
                                        $c = "=20";
                                        $length += 2;
                                    }

                                    $addtl_chars = 0;
                                    $whitespace_pos = $i;
                                } elseif (($dec == 61) || ($dec < 32) || ($dec > 126)) {
                                    $h2 = floor($dec / 16);
                                    $h1 = floor($dec % 16);
                                    $c = $escape . $hex["$h2"] . $hex["$h1"];
                                    $length += 2;
                                    $addtl_chars += 2;
                                }

                                // length for wordwrap exceeded, get a newline into the text
                                if ($length >= $line_max) {
                                    $cur_conv_line .= $c;

                                    // read only up to the whitespace for the current line
                                    $whitesp_diff = $i - $whitespace_pos + $addtl_chars;

                                    /* the text after the whitespace will have to be read
                                     * again ( + any additional characters that came into
                                     * existence as a result of the encoding process after the whitespace)
                                     *
                                     * Also, do not start at 0, if there was *no* whitespace in
                                     * the whole line */
                                    if (($i + $addtl_chars) > $whitesp_diff) {
                                        $output .= substr($cur_conv_line, 0, (strlen($cur_conv_line) -
                                            $whitesp_diff)) . $linebreak;
                                        $i = $i - $whitesp_diff + $addtl_chars;
                                    } else {
                                        $output .= $cur_conv_line . $linebreak;
                                    }

                                    $cur_conv_line = "";
                                    $length = 0;
                                    $whitespace_pos = 0;
                                } else {
                                    // length for wordwrap not reached, continue reading
                                    $cur_conv_line .= $c;
                                }
                            } // end of for

                            $length = 0;
                            $whitespace_pos = 0;
                            $output .= $cur_conv_line;
                            $cur_conv_line = "";

                            if ($j <= count($lines) - 1) {
                                $output .= $linebreak;
                            }
                        } // end for

                        return trim($output);
                    } // end quoted_printable_encode
                }

                $tz = DISPLAY_DEFAULT_TIMEZONE;
                $msg = "BEGIN:VCALENDAR\n";
                $msg .= "VERSION:2.0\n"; // version for iCalendar files vs vCalendar files
                $msg .= "CALSCALE:GREGORIAN\n";
                $msg .= "METHOD: PUBLISH\n";
                $msg .= "PRODID:<-//ExponentCMS//EN>\n";
                if (isset($this->config['rss_cachetime']) && ($this->config['rss_cachetime'] > 0)) {
                    $msg .= "X-PUBLISHED-TTL:PT" . $this->config['rss_cachetime'] . "M\n";
                }
                $msg .= "X-WR-CALNAME:$Filename\n";

//                $items = $this->getEventsForDates($dates);
                $items = $this->event->getEventsForDates($dates);

                for ($i = 0, $iMax = count($items); $i < $iMax; $i++) {

                    // Convert events stored in local time to GMT
                    $eventstart = new DateTime(date('r', $items[$i]->eventstart), new DateTimeZone($tz));
                    $eventstart->setTimezone(new DateTimeZone('GMT'));
                    $eventend = new DateTime(date('r', $items[$i]->eventend), new DateTimeZone($tz));
                    $eventend->setTimezone(new DateTimeZone('GMT'));
                    if ($items[$i]->is_allday) {
                        $dtstart = "DTSTART;VALUE=DATE:" . date("Ymd", $items[$i]->eventstart) . "\n";
                        $dtend = "DTEND;VALUE=DATE:" . date("Ymd", strtotime("midnight +1 day", $items[$i]->eventstart)) . "\n";
                    } else {
                        $dtstart = "DTSTART;VALUE=DATE-TIME:" . $eventstart->format("Ymd\THi00") . "Z\n";
                        if ($items[$i]->eventend) {
                            $dtend = "DTEND;VALUE=DATE-TIME:" . $eventend->format("Ymd\THi00") . "Z\n";
                        } else {
                            $dtend = "DTEND;VALUE=DATE-TIME:" . $eventstart->format("Ymd\THi00") . "Z\n";
                        }
                    }

                    $body = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>", "</p>"), "\n", $items[$i]->body)));
                    if ($items[$i]->is_cancelled) $body = gt('This Event Has Been Cancelled') . ' - ' . $body;
                    $body = str_replace(array("\r"), "", $body);
                    $body = str_replace(array("&#160;"), " ", $body);
                    $body = expString::convertSmartQuotes($body);
                    if (!isset($this->params['style'])) {
                        // it's going to Outlook so remove all formatting from body text
                        $body = quoted_printable_encode($body);
                    } elseif ($this->params['style'] == "g") {
                        // It's going to Google (doesn't like quoted-printable, but likes html breaks)
                        $body = str_replace(array("\n"), "<br />", $body);
                    } else {
                        // It's going elsewhere (doesn't like quoted-printable)
                        $body = str_replace(array("\n"), " -- ", $body);
                    }
                    $title = $items[$i]->title;

                    $msg .= "BEGIN:VEVENT\n";
                    $msg .= $dtstart . $dtend;
                    $msg .= "UID:" . $items[$i]->date_id . "\n";
                    $msg .= "DTSTAMP:" . date("Ymd\THis", time()) . "Z\n";
                    if ($title) {
                        $msg .= "SUMMARY:$title\n";
                    }
                    if ($body) {
                        $msg .= "DESCRIPTION;ENCODING=QUOTED-PRINTABLE:" . $body . "\n";
                    }
                    //	if($link_url) { $msg .= "URL: $link_url\n";}
                    if (!empty($this->config['usecategories'])) {
                        if (!empty($items[$i]->expCat[0]->title)) {
                            $msg .= "CATEGORIES:".$items[$i]->expCat[0]->title."\n";
                        } else {
                            $msg .= "CATEGORIES:".$this->config['uncat']."\n";
                        }
                    }
                    $msg .= "END:VEVENT\n";
                }
                $msg .= "END:VCALENDAR";

                // Kick it out as a file download
                ob_end_clean();

                //	$mime_type = (EXPONENT_USER_BROWSER == 'IE' || EXPONENT_USER_BROWSER == 'OPERA') ? 'application/octet-stream;' : "text/x-vCalendar";
                //	$mime_type = "text/x-vCalendar";
                $mime_type = 'text/Calendar';
                header('Content-Type: ' . $mime_type);
                header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT');
                header('Content-length: ' . strlen($msg));
                header('Content-Transfer-Encoding: binary');
                header('Content-Encoding:');
                //	header("Content-Disposition: inline; filename=".$Filename.".ics");
                header('Content-Disposition: attachment; filename="' . $Filename . '.ics"');
                // IE need specific headers
                //	if (EXPONENT_USER_BROWSER == 'IE') {
                header('Cache-Control: no-cache, must-revalidate');
                header('Pragma: public');
                header('Vary: User-Agent');
                //	} else {
                header('Pragma: no-cache');
                //	}
                echo $msg;
                exit();
            } else {
                notfoundController::handle_not_found();
            }
        } else {
            notfoundController::handle_not_found();
        }
    }

    function send_reminders() {
        if (isset($this->params['title']) || isset($this->params['src'])) {
            $cfg = new expConfig();
            $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
            foreach ($configs as $config) {
                $loc = expUnserialize($config->location_data);
                if (!empty($this->params['title'])) {
                    if ($this->params['title'] == $config->config['feed_sef_url']) {
                        $this->config = $config->config;
                        break;
                    }
                } elseif (!empty($this->params['src'])) {
                    if ($this->params['src'] == $loc->src) {
                        $this->config = $config->config;
                        break;
                    }
                }
            }

            if (empty($this->config['reminder_active'])) {
                notfoundController::handle_not_found();
                return;
            }
            if (!empty($this->config['reminder_code']) && (empty($this->params['code']) || ($this->params['code'] != $this->config['reminder_code']))) {
                notfoundController::handle_not_authorized();
                return;
            }

            $this->loc = $loc;
            $locsql = $this->aggregateWhereClause();

            $view = (isset($this->params['view']) ? $this->params['view'] : '');
            if ($view == "") {
                $view = "send_reminders"; // default reminder view
            }

//            $template = expTemplate::get_template_for_action($this, $view, $this->loc);
            global $template;

            $title = $this->config['feed_title'];
            $template->assign('moduletitle', $title);

            $time = (isset($this->params['time']) ? $this->params['time'] : time());
            $time = (int)$time;

            $template->assign("time", $time);

            $startperiod = expDateTime::startOfDayTimestamp($time);
            if (!empty($this->params['days'])) {
                $totaldays = $this->params['days'];
            } else {
                $totaldays = 7; // default 7 days of events
            }

            $count = 0;
            $info = getdate($startperiod);
            for ($i = 0; $i < $totaldays; $i++) {
                $start = mktime(0, 0, 0, $info['mon'], $info['mday'] + $i, $info['year']);
                $ed = new eventdate();
                $edates = $ed->find('all', $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start) . ")");
                $days[$start] = array();
//                $days[$start] = $this->getEventsForDates($edates);
                $days[$start] = $this->event->getEventsForDates($edates);
                for ($j = 0, $jMax = count($days[$start]); $j < $jMax; $j++) {
                    $thisloc = expCore::makeLocation($loc->mod, $loc->src, $days[$start][$j]->id);
                    $days[$start][$j]->permissions = array(
                        "manage" => (expPermissions::check("manage", $thisloc) || expPermissions::check("manage", $loc)),
                        "edit"   => (expPermissions::check("edit", $thisloc) || expPermissions::check("edit", $loc)),
                        "delete" => (expPermissions::check("delete", $thisloc) || expPermissions::check("delete", $loc))
                    );
                }
                $counts[$start] = count($days[$start]);
                $count += count($days[$start]);
                $days[$start] = expSorter::sort(array('array' => $days[$start], 'sortby' => 'eventstart', 'order' => 'ASC'));
            }
            $template->assign("days", $days);
            $template->assign("counts", $counts);
            $template->assign("start", $startperiod);
            $template->assign("totaldays", $totaldays);

            if ($count == 0) {
                flash('error',gt('No Events to Send!'));
                echo show_msg_queue('error');
                return;
            }

            if (bs3())
                $css = file_get_contents(BASE . "external/bootstrap3/css/bootstrap.css");
            elseif (bs2())
                $css = file_get_contents(BASE . "external/bootstrap/css/bootstrap.css");
            else
                $css = file_get_contents(BASE . "framework/modules/events/assets/css/calendar.css");
            $template->assign("css", $css);
            $template->assign("config", $this->config);
            $template->assign("src", $loc->src);

            // format and send email
            $subject = $this->config['email_title_reminder'] . " - $title";
            $from_addr = $this->config['email_address_reminder'];
            $headers = array(
                "From"     => $from = $this->config['email_from_reminder'],
                "Reply-to" => $reply = $this->config['email_reply_reminder']
            );

            // set up the html message
            $template->assign("showdetail", !empty($this->config['email_showdetail']));
            $htmlmsg = $template->render();

            // now the same thing for the text message
            $msg = preg_replace('/(<script[^>]*>.+?<\/script>|<style[^>]*>.+?<\/style>)/s', '', $htmlmsg); // remove any script or style blocks
            $msg = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>"), "\n", $msg)));

            // Saved.  do notifs
            $emails = array();
            if (!empty($this->config['user_list'])) foreach ($this->config['user_list'] as $c) {
                $u = user::getUserById($c);
                $emails[$u->email] = trim(user::getUserAttribution($u->id));
            }
            if (!empty($this->config['group_list'])) foreach ($this->config['group_list'] as $c) {
                $grpusers = group::getUsersInGroup($c);
                foreach ($grpusers as $u) {
                    $emails[$u->email] = trim(user::getUserAttribution($u->id));
                }
            }
            if (!empty($this->config['address_list'])) foreach ($this->config['address_list'] as $c) {
                $emails[] = $c;
            }
            if (empty($emails)) {
                flash('error',gt('No One to Send Reminders to!'));
                echo show_msg_queue('error');
                return;
            }

            $emails = array_flip(array_flip($emails));
            $emails = array_map('trim', $emails);
//            $headers = array(
//                "MIME-Version" => "1.0",
//                "Content-type" => "text/html; charset=" . LANG_CHARSET
//            );
            $mail = new expMail();
            $mail->quickSend(array(
//                'headers'      => $headers,
                'html_message' => $htmlmsg,
                "text_message" => $msg,
                'to'           => $emails,
                'from'         => array(trim($this->config['email_address_reminder']) => $this->config['email_from_reminder']),
                'subject'      => $subject,
            ));

            flash('message',gt('The following reminder was sent via email'));
            echo show_msg_queue();
//            echo($htmlmsg);
        } else {
            flash('error',gt('No Calendar Selected!'));
            echo show_msg_queue('error');
        }
    }

    /** @deprecated moved to event model
     * @param $edates
     * @param bool $sort_asc
     * @param bool $featuredonly
     * @param bool $condense
     * @return array
     */
    function getEventsForDates($edates, $sort_asc = true, $featuredonly = false, $condense = false) {
        global $eventid;

        $events = array();
        $featuresql = "";
        if ($featuredonly) $featuresql = " AND is_featured=1";
        foreach ($edates as $edate) {
            $evs = $this->event->find('all', "id=" . $edate->event_id . $featuresql);
            foreach ($evs as $key=>$event) {
                if ($condense) {
                    $eventid = $event->id;
                    $multiday_event = array_filter($events, create_function('$event', 'global $eventid; return $event->id === $eventid;'));
                    if (!empty($multiday_event)) {
                        unset($evs[$key]);
                        continue;
                    }
                }
                $evs[$key]->eventstart += $edate->date;
                $evs[$key]->eventend += $edate->date;
                $evs[$key]->date_id = $edate->id;
                if (!empty($event->expCat)) {
                    $catcolor = empty($event->expCat[0]->color) ? null : trim($event->expCat[0]->color);
//                    if (substr($catcolor,0,1)=='#') $catcolor = '" style="color:'.$catcolor.';';
                    $evs[$key]->color = $catcolor;
                }
            }
            if (count($events) < 500) {  // magic number to not crash loop?
                $events = array_merge($events, $evs);
            } else {
//                $evs[$key]->title = gt('Too many events to list').', '.(count($edates)-count($events)).' '.gt('not displayed!');
//                $events = array_merge($events, $evs);
                flash('notice',gt('Too many events to list').', '.(count($edates)-count($events)).' '.gt('not displayed!'));
                break; // keep from breaking system by too much data
            }
        }
        $events = expSorter::sort(array('array' => $events, 'sortby' => 'eventstart', 'order' => $sort_asc ? 'ASC' : 'DESC'));
        return $events;
    }

    function getExternalEvents($startdate, $enddate, $multiday = false) {
        global $db;

        $extevents = array();
        $dy = 0;  // index of events array
        if (!empty($this->config['pull_gcal'])) foreach ($this->config['pull_gcal'] as $key=>$extgcalurl) {
//            $dy = count($extevents);  // index of events array
            $cache_hit = false;
            $gcal_cname = str_replace(array("/",":","&","?"),"_",$extgcalurl);
            $cache_fname = BASE.'tmp/cache/'.$gcal_cname.".cache";
            if (file_exists($cache_fname)) {
                $cache = unserialize(file_get_contents($cache_fname));
                if ($startdate >= $cache['start_date'] || $startdate >= $cache['first_date']) {
                    $events = $db->selectObjects('event_cache','feed="'.$extgcalurl.'" AND ' . self::build_daterange_sql($startdate,$enddate,'eventdate',true));
                    foreach ($events as $event) {
                        if ($multiday) {
                            $extevents[$event->eventdate][$dy] = $event;
                            $extevents[$event->eventdate][$dy]->feedkey = $key;
                            $extevents[$event->eventdate][$dy]->location_data = 'gcalevent' . $key;
                            $extevents[$event->eventdate][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
                            if ($event->is_allday) {
                                $extevents[$event->eventdate][$dy]->eventstart = $event->eventdate;
                            }
                            $dy++;
                        } else {
                            $endit = !empty($event->dateFinished) ? $event->dateFinished : $event->eventdate;
//                            for ($i = $startdate; $i < $enddate; $i += 86400) {
                            for ($i = $event->eventdate; $i <= $endit; $i += 86400) {
                                if ((!empty($event->dateFinished) && $i > $event->dateFinished) || (empty($event->dateFinished) && $i > $event->eventdate)) {
                                    break;
                                } else {
                                    $extevents[$i][$dy] = clone($event);
                                    $extevents[$i][$dy]->eventdate = (int)$i;
                                    $extevents[$i][$dy]->eventstart = ($event->eventstart - $event->eventdate);
                                    $extevents[$i][$dy]->eventend = ($event->eventend - (!empty($event->dateFinished)?$event->dateFinished:$event->eventdate));
                                    $extevents[$i][$dy]->eventstart = ($extevents[$i][$dy]->eventstart) + $i;
                                    $extevents[$i][$dy]->eventend = ($extevents[$i][$dy]->eventend) + $i;
                                    $extevents[$i][$dy]->feedkey = $key;
                                    $extevents[$i][$dy]->location_data = 'gcalevent' . $key;
                                    $extevents[$i][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
                                    $dy++;
                                }
                            }
                        }
                    }
                    $cache_hit = true;
                }
            }
            if (!$cache_hit) { // pull in the external events
                foreach ($this->get_gcal_events($extgcalurl, $startdate, $enddate, $dy, $key, $multiday) as $date=>$events) {
                    foreach ($events as $event) {
                        $extevents[$date][] = $event;
                    }
                }
            }
        }
        if (!empty($this->config['pull_ical'])) foreach ($this->config['pull_ical'] as $key=>$exticalurl) {
//            $dy = count($extevents);  // index of events array
            $cache_hit = false;
            $ical_cname = str_replace(array("/",":","&","?"),"_",$exticalurl);
            $cache_fname = BASE.'tmp/cache/'.$ical_cname.".cache";
            if (file_exists($cache_fname)) {
                $cache = unserialize(file_get_contents($cache_fname));
                if ($startdate >= $cache['start_date'] || $startdate >= $cache['first_date']) {
                    $events = $db->selectObjects('event_cache','feed="'.$exticalurl.'" AND ' . self::build_daterange_sql($startdate,$enddate,'eventdate',true));
                    foreach ($events as $event) {
                        $extevents[$event->eventdate][$dy] = $event;
                        $extevents[$event->eventdate][$dy]->location_data = 'icalevent' . $key;
                        $extevents[$event->eventdate][$dy]->color = !empty($this->config['pull_ical_color'][$key]) ? $this->config['pull_ical_color'][$key] : null;
                        $dy++;
                    }
                    $cache_hit = true;
                }
            }
            if (!$cache_hit) {  // pull in the external events
                foreach ($this->get_ical_events($exticalurl, $startdate, $enddate, $dy, $key, $multiday) as $date=>$events) {
                    foreach ($events as $event) {
                        $extevents[$date][] = $event;
                    }
                }
            }
        }
        return $extevents;
    }

    public function get_gcal_events($extgcalurl, $startdate, $enddate=null, &$dy=0, $key=0, $multiday=false) {
        $extevents = array();
        if (!empty($startdate)) $begin = date("Y-m-d\Th:i:sP", expDateTime::startOfDayTimestamp($startdate));
        if (!empty($enddate)) $end = date("Y-m-d\Th:i:sP", expDateTime::endOfDayTimestamp($enddate));
            else $end = date("Y-m-d\Th:i:sP", (expDateTime::endOfDayTimestamp($startdate + ((3600*24)*30))));

        if (substr($extgcalurl, -5) == 'basic') {
            $extgcalurl = substr($extgcalurl, 0, - 5) . 'full';
        }
        $feed = $extgcalurl . "?orderby=starttime&singleevents=true";
        if (!empty($startdate)) $feed .= "&start-min=" . $begin;
        if (!empty($enddate)) $feed .= "&start-max=" . $end;

        // XML method
//            $s = simplexml_load_file($feed);
//            foreach ($s->entry as $item) {
//                $gd = $item->children('http://schemas.google.com/g/2005');
//                if (!empty($gd->when)) {
//                   $dtstart = $gd->when->attributes()->startTime;
//                } elseif (!empty($gd->recurrence)){
//                   $dtstart = $gd->recurrence->when->attributes()->startTime;
//                } else {
//                    $dtstart = $item->attributes()->When;
//                }
//                //FIXME must convert $dtstart timezone
//                $eventdate = expDateTime::startOfDayTimestamp(strtotime($dtstart));
//                $ourtzoffsets = (int)(date('O',$eventdate)) * 36;
//                $theirtzoffset = -((int)(substr($dtstart,-5,2)) * 3600);
//                $tzoffset = $ourtzoffsets - $theirtzoffset;
//                $extevents[$eventdate][$dy] = new stdClass();
//                $extevents[$eventdate][$dy]->eventdate = $eventdate;
//                $extevents[$eventdate][$dy]->eventstart += strtotime($dtstart) + $tzoffset;
//                if (!empty($gd->when)) {
//                    $dtend = $gd->when->attributes()->endTime;
//                } elseif (!empty($gd->recurrence)) {
//                    $dtend = $gd->recurrence->when->attributes()->endTime;
//                }
//                //FIXME must convert $dtend timezone
//                if (!empty($dtend)) $extevents[$eventdate][$dy]->eventend += strtotime($dtend) + $tzoffset;
//                // dtstart required, one occurrence, (orig. start date)
//                $extevents[$eventdate][$dy]->title = $item->title;
//                $extevents[$eventdate][$dy]->body = $item->content;
        // End XML method

        // DOM method
        $doc = new DOMDocument();
        $doc->load($feed);
        $entries = $doc->getElementsByTagName("entry");
        foreach ($entries as $item) {
            $times = $item->getElementsByTagName("when");
            $dtstart = $times->item(0)->getAttributeNode("startTime")->value;
            $eventdate = expDateTime::startOfDayTimestamp(strtotime($dtstart));
            $extevents[$eventdate][$dy] = new stdClass();
            $extevents[$eventdate][$dy]->eventdate = $eventdate;
            $dtend = @$times->item(0)->getAttributeNode("endTime")->value;
            $ourtzoffsets = (int)date('O',$eventdate) * 36;
            $theirtzoffset = -((int)substr($dtstart,-5,2) * 3600);
            $tzoffset = $ourtzoffsets - $theirtzoffset;
            if (strlen($dtstart) > 10) {
                $extevents[$eventdate][$dy]->eventstart = ((int)substr($dtstart, 11, 2) * 3600) + ((int)substr($dtstart, 14, 2) * 60) + $tzoffset;
//                    if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventstart += 3600;
                $extevents[$eventdate][$dy]->eventend = ((int)substr($dtend, 11, 2) * 3600) + ((int)substr($dtend, 14, 2) * 60) + $tzoffset;
//                    if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventend += 3600;
            } else {
                $extevents[$eventdate][$dy]->eventstart = null;
                $extevents[$eventdate][$dy]->is_allday = 1;
            }
            $extevents[$eventdate][$dy]->eventstart += $eventdate;
            $extevents[$eventdate][$dy]->eventend += $eventdate;
            if (empty($dtend)) $extevents[$eventdate][$dy]->eventend = $extevents[$eventdate][$dy]->eventstart;

            $titles = $item->getElementsByTagName("title");
            $extevents[$eventdate][$dy]->title = $titles->item(0)->nodeValue;
            $contents = $item->getElementsByTagName("content");
            $extevents[$eventdate][$dy]->body = $contents->item(0)->nodeValue;
            // End DOM method

//                    $extevents[$eventdate][$dy]->location_data = serialize(expCore::makeLocation('extevent',$extcal->id));
            $extevents[$eventdate][$dy]->location_data = 'gcalevent' . $key;
            $extevents[$eventdate][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
            $dy++;
        }
        return $extevents;
    }

    public function get_ical_events($exticalurl, $startdate=null, $enddate=null, &$dy=0, $key=0, $multiday=false) {
        $extevents = array();
//            require_once BASE . 'external/iCalcreator.class.php';
        require_once BASE . 'external/iCalcreator-2.22/iCalcreator.php';
        $v = new vcalendar(); // initiate new CALENDAR
        if (stripos($exticalurl, 'http') === 0) {
            $v->setConfig('url', $exticalurl);
        } else {
            $v->setConfig('directory', dirname($exticalurl));
            $v->setConfig('filename', basename($exticalurl));
        }
        $v->parse();
        if ($startdate === null) {
            $startYear = false;
            $startMonth = false;
            $startDay = false;
        } else {
            $startYear = date('Y', $startdate);
            $startMonth = date('n', $startdate);
            $startDay = date('j', $startdate);
        }
        if ($enddate === null) {
            $endYear = $startYear+1;
            $endMonth = $startMonth;
            $endDay = $startDay;
        } else {
            $endYear = date('Y', $enddate);
            $endMonth = date('n', $enddate);
            $endDay = date('j', $enddate);
        }
        // get all events within period split out recurring events as single events per each day
        $eventArray = $v->selectComponents($startYear, $startMonth, $startDay, $endYear, $endMonth, $endDay, 'vevent');
        // Set the timezone to GMT
        @date_default_timezone_set('GMT');
        $tzarray = getTimezonesAsDateArrays($v);
        // Set the default timezone
        @date_default_timezone_set(DISPLAY_DEFAULT_TIMEZONE);
        if (!empty($eventArray)) foreach ($eventArray as $year => $yearArray) {
            if (!empty($yearArray)) foreach ($yearArray as $month => $monthArray) {
                if (!empty($monthArray)) foreach ($monthArray as $day => $dailyEventsArray) {
                    if (!empty($dailyEventsArray)) foreach ($dailyEventsArray as $vevent) {
                        // process each event
                        $yesterday = false;
                        $currdate = $vevent->getProperty('x-current-dtstart');
                        $thisday = explode('-', $currdate[1]);
                        $thisday2 = substr($thisday[2], 0, 2);
                        // if member of a recurrence set,
                        // returns array( 'x-current-dtstart', <DATE>)
                        // <DATE> = (string) date("Y-m-d [H:i:s][timezone/UTC offset]")
                        $dtstart = $vevent->getProperty('dtstart', false, true);
                        $dtend = $vevent->getProperty('dtend', false, true);
                        if (empty($dtend))
                            $dtend = $dtstart;

                        // calculate the cumulative timezone offset in seconds to convert to local/system time
                        $tzoffsets = array();
                        $date_tzoffset = 0;
                        if (!empty($tzarray)) {
//                                $ourtzoffsets = -(iCalUtilityFunctions::_tz2offset(date('O',time())));
                            $ourtzoffsets = -(iCalUtilityFunctions::_tz2offset(date('O',self::_date2timestamp($dtstart['value']))));
                            // Set the timezone to GMT
                            @date_default_timezone_set('GMT');
                            if (!empty($dtstart['params']['TZID'])) $tzoffsets = getTzOffsetForDate($tzarray, $dtstart['params']['TZID'], $dtstart['value']);
                            // Set the default timezone
                            @date_default_timezone_set(DISPLAY_DEFAULT_TIMEZONE);
                            if (isset($tzoffsets['offsetSec'])) $date_tzoffset = $ourtzoffsets + $tzoffsets['offsetSec'];
                        }
                        if (empty($tzoffsets)) {
                            $date_tzoffset = -(iCalUtilityFunctions::_tz2offset(date('O',self::_date2timestamp($dtstart['value']))));
                        }
                        //FIXME we must have the real timezone offset for the date by this point

                        //FIXME this is for the google ical feed which is bad!
                        if ($dtstart['value']['day'] != (int)$thisday2 && (isset($dtstart['value']['day']) && isset($dtend['value']['hour']))&&
                            !((int)$dtstart['value']['hour'] == 0 && (int)$dtstart['value']['min'] == 0  && (int)$dtstart['value']['sec'] == 0
                                && (int)$dtend['value']['hour'] == 0 && (int)$dtend['value']['min'] == 0  && (int)$dtend['value']['sec'] == 0
                                && ((((int)$dtstart['value']['day'] - (int)$dtend['value']['day']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -11)))) {
                            $dtst = strtotime($currdate[1]);
                            $dtst1 = iCalUtilityFunctions::_timestamp2date($dtst);
                            $dtstart['value']['year'] = $dtst1['year'];
                            $dtstart['value']['month'] = $dtst1['month'];
                            $dtstart['value']['day'] = $dtst1['day'];
                            $currenddate = $vevent->getProperty('x-current-dtend');
                            $dtet = strtotime($currenddate[1]);
                            $dtet1 = iCalUtilityFunctions::_timestamp2date($dtet);
                            $dtend['value']['year'] = $dtet1['year'];
                            $dtend['value']['month'] = $dtet1['month'];
                            $dtend['value']['day'] = $dtet1['day'];
//                                $date_tzoffset = 0;
                        }

                        if (!empty($dtstart['value']['hour']) && !((int)$dtstart['value']['hour'] == 0 && (int)$dtstart['value']['min'] == 0  && (int)$dtstart['value']['sec'] == 0
                                                            && (int)$dtend['value']['hour'] == 0 && (int)$dtend['value']['min'] == 0  && (int)$dtend['value']['sec'] == 0
                                                            && ((((int)$dtstart['value']['day'] - (int)$dtend['value']['day']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -11)))) {
                            $eventdate = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtstart['value']) - $date_tzoffset);
//                                $eventend = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtend['value']) - $date_tzoffset);
                            $extevents[$eventdate][$dy] = new stdClass();
                            $extevents[$eventdate][$dy]->eventdate = new stdClass();
                            $extevents[$eventdate][$dy]->eventdate->date = $eventdate;
//                                if ((int)($dtstart['value']['hour']) == 0 && (int)($dtstart['value']['min']) == 0  && (int)($dtstart['value']['sec']) == 0
//                                    && (int)($dtend['value']['hour']) == 0 && (int)($dtend['value']['min']) == 0  && (int)($dtend['value']['sec']) == 0
//                                    && ((((int)($dtstart['value']['day']) - (int)($dtend['value']['day'])) == -1) || (((int)($dtstart['value']['month']) - (int)($dtend['value']['month'])) == -1) || (((int)($dtstart['value']['month']) - (int)($dtend['value']['month'])) == -11))) {
////                                    if ($dtstart['value']['day'] != (int)($thisday2)) {
//                                    if (date('d',$eventdate) != $thisday2) {
////                                    if (date('d',$eventdate) != date('d',$eventend)) {
//                                        $yesterday = true;
//                                    } else {
//                                        $extevents[$eventdate][$dy]->eventstart = null;
//                                        $extevents[$eventdate][$dy]->is_allday = 1;
//                                    }
//                                } else {
                                if (date('d',$eventdate) != $thisday2) {
//                                    if (date('d',$eventdate) != date('d',$eventend)) {
                                    $yesterday = true;
                                } else {
                                    $extevents[$eventdate][$dy]->eventstart = ($dtstart['value']['hour'] * 3600) + ($dtstart['value']['min'] * 60) - $date_tzoffset;
//                                        if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventstart += 3600; // adjust for daylight savings time
                                }
//                                }
                        } else {
                            // this is an all day event
                            $eventdate = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtstart['value']));
//                                $eventend = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtend['value']));
                            $extevents[$eventdate][$dy] = new stdClass();
                            $extevents[$eventdate][$dy]->eventdate = new stdClass();
                            $extevents[$eventdate][$dy]->eventdate->date = $eventdate;
//                                if ($dtstart['value']['day'] != (int)($thisday2)) {
                            if (date('d',$eventdate) != $thisday2) {
//                                if (date('d',$eventdate) != date('d',$eventend)) {
                                $yesterday = true;
                            } else {
                                $extevents[$eventdate][$dy]->eventstart = null;
                                $extevents[$eventdate][$dy]->is_allday = 1;
                            }
                        }

                        // set the end time if needed
                        if (!$yesterday && isset($dtend['value']['hour']) && empty($extevents[$eventdate][$dy]->is_allday)) {
//                                if ($dtend['value']['day'] != (int)($thisday2)) {
//                                if ((date('d',$eventend) != $thisday2)) {
//                                    $yesterday = true;
//                                } else {
                            $extevents[$eventdate][$dy]->eventend = ($dtend['value']['hour'] * 3600) + ($dtend['value']['min'] * 60) - $date_tzoffset;
//                                if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventend += 3600; // adjust for daylight savings time
//                                }
                        }

                        // convert the start and end times to a full date
                        if (isset($extevents[$eventdate][$dy]->eventstart) && $extevents[$eventdate][$dy]->eventstart != null)
                            $extevents[$eventdate][$dy]->eventstart += $eventdate;
                        if (isset($extevents[$eventdate][$dy]->eventend))
                            $extevents[$eventdate][$dy]->eventend += $eventdate;

                        // dtstart required, one occurrence, (orig. start date)
                        $extevents[$eventdate][$dy]->title = $vevent->getProperty('summary');
                        $body = $vevent->getProperty('description');
                        // convert end of lines
                        $body = nl2br(str_replace("\\n"," <br>\n",$body));
                        $body = str_replace("\n"," <br>\n",$body);
                        $body = str_replace(array('==0A','=0A','=C2=A0')," <br>\n",$body);
                        $extevents[$eventdate][$dy]->body = $body;
                        $extevents[$eventdate][$dy]->location_data = 'icalevent' . $key;
                        $extevents[$eventdate][$dy]->color = !empty($this->config['pull_ical_color'][$key]) ? $this->config['pull_ical_color'][$key] : null;
                        if (!$yesterday && $eventdate >= $startdate) {
                            $dy++;
                        } else {
                            unset($extevents[$eventdate][$dy]);
                        }
                    }
                }
            }
        }
        return $extevents;
    }

    public static function _date2timestamp( $datetime, $wtz=null ) {
      if( !isset( $datetime['hour'] )) $datetime['hour'] = 0;
      if( !isset( $datetime['min'] ))  $datetime['min']  = 0;
      if( !isset( $datetime['sec'] ))  $datetime['sec']  = 0;
      if( empty( $wtz ) && ( !isset( $datetime['tz'] ) || empty(  $datetime['tz'] )))
        return mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
      $output = $offset = 0;
      if( empty( $wtz )) {
        if( iCalUtilityFunctions::_isOffset( $datetime['tz'] )) {
          $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) * -1;
          $wtz    = 'UTC';
        }
        else
          $wtz    = $datetime['tz'];
      }
      if(( 'Z' == $wtz ) || ( 'GMT' == strtoupper( $wtz )))
        $wtz      = 'UTC';
      try {
        $strdate  = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['min'], $datetime['sec'] );
        $d        = new DateTime( $strdate, new DateTimeZone( $wtz ));
        if( 0    != $offset )  // adjust for offset
          $d->modify( $offset.' seconds' );
        $output   = $d->format( 'U' );
        unset( $d );
      }
      catch( Exception $e ) {
        $output = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
      }
      return $output;
    }

    /**
     * build/update the external event cache
     *
     */
    public function build_cache() {
        global $db;

        // get our requested config
        $cfg = new expConfig();
        $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
        foreach ($configs as $config) {
            $loc = expUnserialize($config->location_data);
            if (!empty($this->params['title'])) {
                if ($this->params['title'] == $config->config['feed_sef_url']) {
                    $this->config = $config->config;
                    break;
                }
            } elseif (!empty($this->params['src'])) {
                if ($this->params['src'] == $loc->src) {
                    $this->config = $config->config;
                    break;
                }
            }
        }

        // next loop through our config pull urls

        // google xml pull
        if (!empty($this->config['pull_gcal'])) foreach ($this->config['pull_gcal'] as $key=>$extgcalurl) {
            $start = expDateTime::startOfMonthTimestamp(time());
            $gcal_cname = str_replace(array("/",":","&","?"),"_",$extgcalurl);
            $cache_fname = BASE.'tmp/cache/'.$gcal_cname.".cache";
            $db->delete('event_cache', "feed='" . $extgcalurl . "' AND eventdate > " . $start);  // replace future events
            // loop through 12 months, 1 month at a time
            for ($i=1; $i < 13; $i++) {
                $end = expDateTime::endOfMonthTimestamp($start);
                $tmp = 0;
                $extevents = $this->get_gcal_events($extgcalurl, $start, $end, $tmp, 0, true);
//                $extevents = $this->get_gcal_events($extgcalurl, null, null, 0, 0, 0, true);
                foreach ($extevents as $day) {
                    foreach ($day as $extevent) {
                        $event_cache = new stdClass();
                        $event_cache->feed = $extgcalurl;
                        $event_cache->event_id = $extevent->event_id;
                        $event_cache->title = $extevent->title;
                        $event_cache->body = $extevent->body;
                        $event_cache->eventdate = $extevent->eventdate->date;
                        if (isset($extevent->dateFinished) && $extevent->dateFinished != -68400)
                            $event_cache->dateFinished = $extevent->dateFinished;
                        if (isset($extevent->eventstart))
                            $event_cache->eventstart = $extevent->eventstart;
                        if (isset($extevent->eventend))
                            $event_cache->eventend = $extevent->eventend;
                        if (isset($extevent->is_allday))
                            $event_cache->is_allday = $extevent->is_allday;
                        $found = false;
                        if ($extevent->eventdate->date < $start)   // prevent duplicating events crossing month boundaries
                            $found = $db->selectObject('event_cache','feed="'.$extgcalurl.'" AND event_id="'.$event_cache->event_id.'" AND eventdate='.$event_cache->eventdate);
                        if (!$found)
                            $db->insertObject($event_cache,'event_cache');
                    }
                }
                $start = expDateTime::startOfMonthTimestamp($end + 1024);
            }
            $cache_contents = serialize(array('start_date'=>$start,'first_date'=>(int)$db->selectValue('event_cache','eventdate','feed="'.$extgcalurl.'" ORDER BY eventdate'),'refresh_date'=>time()));
            file_put_contents($cache_fname, $cache_contents);
        }

        // ical pull
        $start = expDateTime::startOfMonthTimestamp(time());
        if (!empty($this->config['pull_ical'])) foreach ($this->config['pull_ical'] as $key=>$exticalurl) {
            $ical_cname = str_replace(array("/",":","&","?"),"_",$exticalurl);
            $cache_fname = BASE.'tmp/cache/'.$ical_cname.".cache";
            $db->delete('event_cache', "feed='" . $exticalurl . "' AND eventdate > " . $start);
            // get 1 years worth of events
            $extevents = $this->get_ical_events($exticalurl, $start);
            foreach ($extevents as $day) {
                foreach ($day as $extevent) {
                    $event_cache = new stdClass();
                    $event_cache->feed = $exticalurl;
                    $event_cache->title = $extevent->title;
                    $event_cache->body = $extevent->body;
                    $event_cache->eventdate = $extevent->eventdate->date;
                    if (isset($extevent->dateFinished))
                        $event_cache->dateFinished = $extevent->dateFinished;
                    $event_cache->eventstart = $extevent->eventstart;
                    if (isset($extevent->eventend))
                        $event_cache->eventend = $extevent->eventend;
                    if (isset($extevent->is_allday))
                        $event_cache->is_allday = $extevent->is_allday;
                    $db->insertObject($event_cache, 'event_cache');
                }
            }
            $cache_contents = serialize(array('start_date'=>$start,'first_date'=>(int)$db->selectValue('event_cache','eventdate','feed="'.$exticalurl.'" ORDER BY eventdate'),'refresh_date'=>time()));
            file_put_contents($cache_fname, $cache_contents);
        }
        flash('message', gt('External Calendar Event cache updated'));
        echo show_msg_queue();
    }

    function import() {
        $pullable_modules = expModules::listInstalledControllers($this->baseclassname);
        $modules = new expPaginator(array(
            'records' => $pullable_modules,
            'controller' => $this->loc->mod,
            'action' => $this->params['action'],
            'order'   => isset($this->params['order']) ? $this->params['order'] : 'section',
            'dir'     => isset($this->params['dir']) ? $this->params['dir'] : '',
            'page'    => (isset($this->params['page']) ? $this->params['page'] : 1),
            'columns' => array(
                gt('Title') => 'title',
                gt('Page')  => 'section'
            ),
        ));

        assign_to_template(array(
            'modules' => $modules,
        ));
    }

    function import_select()
    {
        if (empty($this->params['import_aggregate'])) {
            expValidator::setErrorField('import_aggregate[]');
            expValidator::failAndReturnToForm(gt('You must select a module.'), $this->params);
        }
        $extevents = array();
        unset(
            $this->params['begin'],
            $this->params['end']
        );  // always use date value
        $begin = yuidatetimecontrol::parseData('begin', $this->params);
        $end = yuidatetimecontrol::parseData('end', $this->params);
        if ($this->params['file_type'] == 'file') {
            //Get the temp directory to put the uploaded file
            $directory = "tmp";

            //Get the file save it to the temp directory
            if (!empty($_FILES["import_file"]) && $_FILES["import_file"]["error"] == UPLOAD_ERR_OK) {
                $file = expFile::fileUpload(
                    "import_file",
                    false,
                    false,
                    time() . "_" . $_FILES['import_file']['name'],
                    $directory . '/'
                );
                if ($file === null) {
                    switch ($_FILES["import_file"]["error"]) {
                        case UPLOAD_ERR_INI_SIZE:
                        case UPLOAD_ERR_FORM_SIZE:
                            $this->params['_formError'] = gt(
                                'The file you attempted to upload is too large.  Contact your system administrator if this is a problem.'
                            );
                            break;
                        case UPLOAD_ERR_PARTIAL:
                            $this->params['_formError'] = gt('The file was only partially uploaded.');
                            break;
                        case UPLOAD_ERR_NO_FILE:
                            $this->params['_formError'] = gt('No file was uploaded.');
                            break;
                        default:
                            $this->params['_formError'] = gt(
                                'A strange internal error has occurred.  Please contact the Exponent Developers.'
                            );
                            break;
                    }
                    expSession::set("last_POST", $this->params);
                    header("Location: " . $_SERVER['HTTP_REFERER']);
                    exit("");
                } else {
                    $extevents = $this->get_ical_events($directory . "/" . $file->filename, $begin, $end);
                }
            } else {
               expValidator::setErrorField('import_file');
               expValidator::failAndReturnToForm(gt('File failed to upload.'), $this->params);  // file upload error
            }
        } else {
            if (empty($this->params['ext_feed'])) {
                expValidator::setErrorField('ext_feed');
                expValidator::failAndReturnToForm(gt('You must enter a feed url.'), $this->params);
            }
            $extevents = $this->get_ical_events($this->params['ext_feed'], $begin, $end);
        }

        $src = $this->params['import_aggregate'][0];
        $count = 0;
        foreach ($extevents as $day) {
            foreach ($day as $extevent) {
                $event = array();
                $event['title'] = $extevent->title;
                $event['body'] = $extevent->body;
                $event['eventdate'] = $extevent->eventdate->date;
                $event['eventstart'] = $extevent->eventstart;
                $event['eventstart'] -= $event['eventdate'];
                if (isset($extevent->eventend))
                    $event['eventend'] = $extevent->eventend;
                else
                    $event['eventend'] = $extevent->eventstart;
                $event['eventend'] -= $event['eventdate'];
                if (isset($extevent->is_allday))
                    $event['is_allday'] = $extevent->is_allday;
                $event['module'] = 'event';
                $event['src'] = $src;
                $item = new event();  // create new populated record to auto-set things
                $item->update($event);
                $count++;
            }
        }

        unlink($directory . "/" . $file->filename);

        // update search index
        $this->addContentToSearch();

        flashAndFlow('message', $count . ' ' . gt('events were imported.'));
    }

    /** @deprecated
     * function to build a control requested via ajax
     * we the html just like the control smarty function
     * @deprecated
     */
    public function buildControl() {
        $control = new colorcontrol();
        if (!empty($this->params['value'])) $control->value = $this->params['value'];
        if ($this->params['value'][0] != '#') $this->params['value'] = '#' . $this->params['value'];
        $control->default = $this->params['value'];
        if (!empty($this->params['hide'])) $control->hide = $this->params['hide'];
        if (isset($this->params['flip'])) $control->flip = $this->params['flip'];
        $this->params['name'] = !empty($this->params['name']) ? $this->params['name'] : '';
        $control->name  = $this->params['name'];
        $this->params['id'] = !empty($this->params['id']) ? $this->params['id'] : '';
        $control->id  = isset($this->params['id']) && $this->params['id'] != "" ? $this->params['id'] : "";
        //echo $control->id;
        if (empty($control->id)) $control->id = $this->params['name'];
        if (empty($control->name)) $control->name = $this->params['id'];

        // attempt to translate the label
        if (!empty($this->params['label'])) {
            $this->params['label'] = gt($this->params['label']);
        } else {
            $this->params['label'] = null;
        }
        echo $control->toHTML($this->params['label'], $this->params['name']);
//        $ar = new expAjaxReply(200, gt('The control was created'), json_encode(array('data'=>$code)));
//        $ar->send();
    }

}

                
                
                
    
    protected $add_permissions = array(
//        'picker'=>'Manage Files',
        'import'=>'Import',
        'export'=>'Export',
    );
        'picker'=>'must be logged in',
        'editAlt'=>'must be logged in',
        'editCat'=>'must be logged in',
        'editShare'=>'must be logged in',
        'editTitle'=>'must be logged in',
        
        
    
    
    
    
        
    
            
                  
        
    } 
    
        
    } 
    } 
        global $user;        
    } 
        // }    
        if ($name[0] == '.')
	
        
        $fd = new filedownload($this->params['fileid']); 
        }        
        
        
        parent::downloadfile();        
        
        foreach ($items as $key => $item) { 
	
    protected $add_permissions = array(
        'viewdata'  => "View Data",
        'enter_data' => "Enter Data"  // slight naming variation to not fully restrict enterdata method
    );
                $f = $this->forms->find('first', 'sef_url="' . $this->params['title'] . '"');
                    $where = $this->params['filter'];
                $f = $this->forms->find('first', 'sef_url="' . $this->params['title'] . '"');
                if ($this->config['auto_respond_form']) 
                if ($this->config['auto_respond_form']) 
	
        // pagination parameter..hard coded for now.	    
            $where .= ' AND parent=' . $this->params['parent'];
	    
	    
	    $where = empty($this->params['version']) ? 1 : 'help_version_id='.$this->params['version'];
		    
	    
	    
	    
	    
	    
	    
	    
	    expHistory::back();	    
	    
	    
	        self::copydocs($current_version->id, $version->id);	        
	
        return $db->selectValue('help_version', 'id', 'version="'.$version.'"');
        return $db->selectValue('help_version', 'version', 'id="'.$version_id.'"');
    //protected $permissions = array_merge(array("test"=>'Test'), array('copyProduct'=>"Copy Product"));
    protected $add_permissions = array(
        'import' => 'Import Data',
        'export' => 'Export Data'
    );
        //eDebug($this->params,true); 
        //eDebug($data);        
        $source = '';   
            $dataset[$value] = '';            
        
        
            $extAddy = new external_address();             
                $extAddy->lastname = $bName[2];    
                $extAddy->lastname = '';    
                $extAddy->lastname = $bName[1];        
            
            $extAddy->address2 = $data[6];            
            $extAddy->address2 = $data[6];            
            $extAddy->city = $data[7];            
            
            $extAddy->state = $state->id;                        
            $extAddy->zip = str_ireplace("'",'',$data[9]);            
            $extAddy->phone = $data[20];            
            $extAddy->email = $data[21];            
            
            
                $extAddy->is_shipping = 1;            
                $extAddy->save(false);            
            {                
                $extAddy->is_shipping = 0;            
                $extAddy->save(false);            
                
                $extAddy = new external_address();             
                    $extAddy->lastname = $sName[2];    
                    $extAddy->lastname = '';    
                    $extAddy->lastname = $sName[1];        
                
                $extAddy->address2 = $data[15];                            
                $extAddy->city = $data[16];            
                
                $extAddy->state = $state->id;                        
                $extAddy->zip = str_ireplace("'",'',$data[18]);            
                $extAddy->phone = $data[20];            
                $extAddy->email = $data[21];            
                $extAddy->source = $source;   
                
            
        
        }   
        
        }    
    protected $add_permissions = array(
<?php

##################################################
#
# Copyright (c) 2004-2016 OIC Group, Inc.
#
# This file is part of Exponent
#
# Exponent is free software; you can redistribute
# it and/or modify it under the terms of the GNU
# General Public License as published by the Free
# Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# GPL: http://www.gnu.org/licenses/gpl.txt
#
##################################################
/**
 * @subpackage Controllers
 * @package    Modules
 */
class navigationController extends expController {
    public $basemodel_name = 'section';
    public $useractions = array(
        'showall' => 'Show Navigation',
        'breadcrumb' => 'Breadcrumb',
    );
    public $remove_configs = array(
        'aggregation',
        'categories',
        'comments',
        'ealerts',
        'facebook',
        'files',
        'pagination',
        'rss',
        'tags',
        'twitter',
    );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
    protected $add_permissions = array(
        'view' => "View Page"
    );
    protected $remove_permissions = array(
//        'configure',
//        'create',
//        'delete',
//        'edit'
    );

    static function displayname() { return gt("Navigation"); }

    static function description() { return gt("Places navigation links/menus on the page."); }

    static function isSearchable() { return true; }

    function searchName() { return gt('Webpage'); }

    /**
     * @param null $src
     * @param array $params
     *
     */
    function __construct($src = null, $params = array())
    {
        parent::__construct($src, $params);
        if (!empty($params['id']))  // we normally throw out the $loc->int EXCEPT with navigation pages
            $this->loc = expCore::makeLocation($this->baseclassname, $src, $params['id']);
    }

    public function showall() {
        global $user, $sectionObj, $sections;

        expHistory::set('viewable', $this->params);
        $id      = $sectionObj->id;
        $current = null;
        // all we need to do is determine the current section
        $navsections = $sections;
        if ($sectionObj->parent == -1) {
            $current = $sectionObj;
        } else {
            foreach ($navsections as $section) {
                if ($section->id == $id) {
                    $current = $section;
                    break;
                }
            }
        }
        assign_to_template(array(
            'sections'     => $navsections,
            'current'      => $current,
            'canManage'    => ((isset($user->is_acting_admin) && $user->is_acting_admin == 1) ? 1 : 0),
        ));
    }

    public function breadcrumb() {
        global $sectionObj;

        expHistory::set('viewable', $this->params);
        $id      = $sectionObj->id;
        $current = null;
        // Show not only the location of a page in the hierarchy but also the location of a standalone page
        $current = new section($id);
        if ($current->parent == -1) {  // standalone page
            $navsections = section::levelTemplate(-1, 0);
            foreach ($navsections as $section) {
                if ($section->id == $id) {
                    $current = $section;
                    break;
                }
            }
        } else {
            $navsections = section::levelTemplate(0, 0);
            foreach ($navsections as $section) {
                if ($section->id == $id) {
                    $current = $section;
                    break;
                }
            }
        }
        assign_to_template(array(
            'sections'     => $navsections,
            'current'      => $current,
        ));
    }

    /**
     * @deprecated 2.3.4 moved to section model
     */
    public static function navhierarchy($notyui=false) {
        global $sections;

        $json_array = array();
        for ($i = 0, $iMax = count($sections); $i < $iMax; $i++) {
            if ($sections[$i]->depth == 0) {
                $obj = new stdClass();
//   				$obj->id = $sections[$i]->name.$sections[$i]->id;
                $obj->id   = $sections[$i]->id;
                $obj->text = $sections[$i]->name;
                $obj->title = $sections[$i]->page_title;
                $obj->description = $sections[$i]->description;
                $obj->new_window = $sections[$i]->new_window;
                $obj->expFile = $sections[$i]->expFile;
                $obj->glyph = $sections[$i]->glyph;
                $obj->glyph_only = $sections[$i]->glyph_only;
                $obj->type = $sections[$i]->alias_type;
                if ($sections[$i]->active == 1) {
                    $obj->url = $sections[$i]->link;
                    if ($obj->type == 1 && substr($obj->url, 0, 4) != 'http') {
                        $obj->url = 'http://' . $obj->url;
                    }
                } else {
                    $obj->url     = "#";
                    $obj->onclick = "onclick: { fn: return false }";
                }
                if ($obj->type == 3) {  // mostly a hack instead of adding more table fields
                    $obj->width = $sections[$i]->internal_id;
                    $obj->class = $sections[$i]->external_link;
                }
                /*if ($sections[$i]->active == 1) {
                    $obj->disabled = false;
                } else {
                    $obj->disabled = true;
                }*/
                //$obj->disabled = true;
                $obj->itemdata = self::getChildren($i,$notyui);
                $obj->maxitems = count($obj->itemdata);
                $obj->maxdepth = 0;
                foreach ($obj->itemdata as $menu) {
                    if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
                }
            }
            $json_array[] = $obj;
        }
        return $json_array;
    }

    /**
     * @deprecated 2.3.4 moved to section model
     */
    public static function navtojson() {
        return json_encode(self::navhierarchy());
    }

    /**
     * @deprecated 2.3.4 moved to section model
     */
    public static function getChildren(&$i, $notyui=false) {
        global $sections;

        //		echo "i=".$i."<br>";
        if ($i + 1 == count($sections)) { // last entry
            return array();
        } elseif ($sections[$i]->depth == $sections[$i + 1]->depth) {
            return array();
        } else {
            $ret_depth = $sections[$i]->depth;
            $i++;
            $ret_array = array();
            for ($iMax = count($sections); $i < $iMax; $i++) {
                // start setting up the objects to return
                $obj       = new stdClass();
                $obj->id   = $sections[$i]->id;
                $obj->text = $sections[$i]->name;
                $obj->title = $sections[$i]->page_title;
                $obj->description = $sections[$i]->description;
                $obj->new_window = $sections[$i]->new_window;
                $obj->expFile = $sections[$i]->expFile;
                $obj->glyph = $sections[$i]->glyph;
                $obj->glyph_only = $sections[$i]->glyph_only;
                $obj->depth = $sections[$i]->depth;
                if ($sections[$i]->active == 1) {
                    $obj->url = $sections[$i]->link;
                    if ($sections[$i]->alias_type == 1 && substr($obj->url, 0, 4) != 'http') {
                        $obj->url = 'http://' . $obj->url;
                    }
                } else {
                    $obj->url     = "#";
                    $obj->onclick = "onclick: { fn: return false }";
                }
                //echo "i=".$i."<br>";
                if (self::hasChildren($i)) {
                    if ($notyui) {
                        $obj->itemdata = self::getChildren($i,$notyui);
                        $obj->maxitems = count($obj->itemdata);
                        $obj->maxdepth = 0;
                        foreach ($obj->itemdata as $menu) {
                            if (!empty($menu->maxdepth)) {
                                if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
                            } else {
                                if ($menu->depth > $obj->maxdepth) $obj->maxdepth = $menu->depth;
                            }
                        }
                    } else {
                        $obj->submenu     = new stdClass();
                        $obj->submenu->id = $sections[$i]->name . $sections[$i]->id;
                        //echo "getting children of ".$sections[$i]->name;
                        $obj->submenu->itemdata = self::getChildren($i,$notyui);
                        $obj->maxitems = count($obj->submenu->itemdata);
                        $obj->maxdepth = 0;
                        foreach ($obj->submenu->itemdata as $menu) {
                            if (!empty($menu->maxdepth)) {
                                if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
                            } else {
                                if ($menu->depth > $obj->maxdepth) $obj->maxdepth = $menu->depth;
                            }
                        }
                    }
                    $ret_array[]            = $obj;
                } else {
                    $obj->maxdepth = $obj->depth;
                    $ret_array[] = $obj;
                }
                if (($i + 1) >= count($sections) || $sections[$i + 1]->depth <= $ret_depth) {
                    return $ret_array;
                }
            }
            return array();
        }
    }

    /**
     * @deprecated 2.3.4 moved to section model
     */
    public static function hasChildren($i) {
        global $sections;

        if (($i + 1) >= count($sections)) return false;
        return ($sections[$i]->depth < $sections[$i + 1]->depth) ? true : false;
    }

    /** exdoc
     * Creates a location object, based off of the three arguments passed, and returns it.
     *
     * @return array
     * @deprecated 2.3.4 moved to section model
     */
    public static function initializeNavigation() {
        $sections = section::levelTemplate(0, 0);
        return $sections;
    }

    /**
     * returns all the section's children
     *
     * @static
     *
     * @param int   $parent top level parent id
     * @param int   $depth  variable to hold level of recursion
     * @param array $parents
     *
     * @return array
     * @deprecated 2.3.4 moved to section model
     */
    public static function levelTemplate($parent, $depth = 0, $parents = array()) {
        global $user;

        if ($parent != 0) $parents[] = $parent;
        $nodes = array();
        $cache = expSession::getCacheValue('navigation');
        $sect = new section();
        if (!isset($cache['kids'][$parent])) {
            $kids = $sect->find('all','parent=' . $parent);
            $cache['kids'][$parent] = $kids;
            expSession::setCacheValue('navigation', $cache);
        } else {
            $kids = $cache['kids'][$parent];
        }
        $kids = expSorter::sort(array('array' => $kids, 'sortby' => 'rank', 'order' => 'ASC'));
        for ($i = 0, $iMax = count($kids); $i < $iMax; $i++) {
            $child = $kids[$i];
            //foreach ($kids as $child) {
            if ($child->public == 1 || expPermissions::check('view', expCore::makeLocation('navigation', '', $child->id))) {
                $child->numParents    = count($parents);
                $child->depth         = $depth;
                $child->first         = ($i == 0 ? 1 : 0);
                $child->last          = ($i == count($kids) - 1 ? 1 : 0);
                $child->parents       = $parents;
                $child->canManage     = (isset($user->is_acting_admin) && $user->is_acting_admin == 1 ? 1 : 0);
                $child->canManageRank = $child->canManage;
                if (!isset($child->sef_name)) {
                    $child->sef_name = '';
                }
                // Generate the link attribute base on alias type.
                if ($child->alias_type == 1) {
                    // External link.  Set the link to the configured website URL.
                    // This is guaranteed to be a full URL because of the
                    // section::updateExternalAlias() method in models-1/section.php
                    $child->link = $child->external_link;
                } else if ($child->alias_type == 2) {
                    // Internal link.
                    // Need to check and see if the internal_id is pointing at an external link.
//                    $dest = $db->selectObject('section', 'id=' . $child->internal_id);
                    $dest = $sect->find('first','id=' . $child->internal_id);
                    if (!empty($dest->alias_type) && $dest->alias_type == 1) {
                        // This internal alias is pointing at an external alias.
                        // Use the external_link of the destination section for the link
                        $child->link = $dest->external_link;
                    } else {
                        // Pointing at a regular section.  This is guaranteed to be
                        // a regular section because aliases cannot be turned into sections,
                        // (and vice-versa) and because the section::updateInternalLink
                        // does 'alias to alias' dereferencing before the section is saved
                        // (see models-1/section.php)
                        //added by Tyler to pull the descriptions through for the children view
                        $child->description = !empty($dest->description) ? $dest->description : '';
                        $child->link        = expCore::makeLink(array('section' => $child->internal_id));
                    }
                } else {
                    // Normal link, alias_type == 0.  Just create the URL from the section's id.
                    $child->link = expCore::makeLink(array('section' => $child->id), '', $child->sef_name);
                }
                //$child->numChildren = $db->countObjects('section','parent='.$child->id);
                $nodes[] = $child;
                $nodes   = array_merge($nodes, section::levelTemplate($child->id, $depth + 1, $parents));
            }
        }
        return $nodes;
    }

    /**
     * Returns a flat representation of the full site hierarchy.
     *
     * @param int    $parent         top level parent id
     * @param int    $depth          variable to hold level of recursion
     * @param array  $ignore_ids     array of pages to ignore
     * @param bool   $full           include a 'top' level entry
     * @param string $perm           permission level to build list
     * @param bool   $addstandalones should we add the stand-alone pages also
     * @param bool   $addinternalalias
     *
     * @return array
     * @deprecated 2.3.4 moved to section model, HOWEVER still used in theme config
     */
    public static function levelDropdownControlArray($parent, $depth = 0, $ignore_ids = array(), $full = false, $perm = 'view', $addstandalones = false, $addinternalalias = true) {
        global $db;

        $ar = array();
        if ($parent == 0 && $full) {
            $ar[0] = '&lt;' . gt('Top of Hierarchy') . '&gt;';
        }
        if ($addinternalalias) {
            $intalias = '';
        } else {
            $intalias = ' AND alias_type != 2';
        }
        $nodes = $db->selectObjects('section', 'parent=' . $parent . $intalias, 'rank');
        foreach ($nodes as $node) {
            if ((($perm == 'view' && $node->public == 1) || expPermissions::check($perm, expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
                if ($node->active == 1) {
                    $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . $node->name;
                } else {
                    $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
                }
                $ar[$node->id] = $text;
                foreach (self::levelDropdownControlArray($node->id, $depth + 1, $ignore_ids, $full, $perm, $addstandalones, $addinternalalias) as $id => $text) {
                    $ar[$id] = $text;
                }
            }
        }
        if ($addstandalones && $parent == 0) {
            $sections = $db->selectObjects('section', 'parent=-1');
            foreach ($sections as $node) {
                if ((($perm == 'view' && $node->public == 1) || expPermissions::check($perm, expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
                    if ($node->active == 1) {
                        $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . $node->name;
                    } else {
                        $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
                    }
                    $ar[$node->id] = '(' . gt('Standalone') . ') ' . $text;
                }
            }
//            $ar = array_merge($ar,$sections);
        }
        return $ar;
    }

    /**
     * add all module items to search index
     *
     * @return int
     */
    function addContentToSearch() {
        global $db;

        //global $sections;
        //		global $router;
//        $db->delete('search', "ref_module='navigation' AND ref_type='section'");
        $db->delete('search', "ref_module='".$this->baseclassname."' AND ref_type='section'");
        // this now ensures we get internal pages, instead of relying on the global $sections, which does not.
        $sections = $db->selectObjects('section', 'active=1');
        foreach ($sections as $section) {
            $search_record = new stdClass();
//            $search_record->category = 'Webpages';
//            $search_record->ref_module = 'navigationController';
//            $search_record->ref_type = 'section';
//            $search_record->ref_module  = $this->classname;
            $search_record->ref_module  = $this->baseclassname;
            $search_record->category    = $this->searchName();
            $search_record->ref_type    = $this->searchCategory();
            $search_record->original_id = $section->id;
            $search_record->title       = $section->name;
            //$search_record->view_link = $router->buildUrlByPageId($section->id);
            $link = str_replace(URL_FULL, '', makeLink(array('section' => $section->id)));
            if ($link . '/' == URL_FULL) $link = '';
            $search_record->view_link = $link;
            $search_record->body      = $section->description;
            $search_record->keywords  = $section->keywords;
            // now we're going to grab all the textmodules on this page and build the body for the page based off the content
            // of all the text module added together.
            $loc = expCore::makeLocation('text');
            $controllername = 'text';
            foreach ($db->selectObjects('sectionref', "module='" . $controllername . "' AND section=" . $section->id) as $module) {
                $loc->src   = $module->source;
//                $controller = new $controllername();
                $controller = expModules::getController($controllername);
                $textitems  = $db->selectObjects($controller->model_table, "location_data='" . serialize($loc) . "'");
                foreach ($textitems as $textitem) {
                    if (!empty($textitem)) {
                        $search_record->body .= ' ' . search::removeHTML($textitem->body) . ' ';
                        $search_record->keywords .= " " . $textitem->title;
                    }
                }
            }
            $db->insertObject($search_record, 'search');
        }
        return count($sections);
    }

    /**
     * Retrieve either the entire hierarchy, or a subset of the hierarchy, as an array suitable for use
     * in a dropdowncontrol.  This is used primarily by the section datatype for moving and adding
     * sections to specific parts of the site hierarchy.
     *
     * @param int   $parent     The id of the subtree parent.  If passed as 0 (the default), the entire subtree is parsed.
     * @param int   $depth
     * @param int   $default
     * @param array $ignore_ids a value-array of IDs to be ignored when generating the list.  This is used
     *                          when moving a section, since a section cannot be made a subsection of itself or any of its subsections.
     *
     * @return string
     */
    function levelShowDropdown($parent, $depth = 0, $default = 0, $ignore_ids = array()) {
        global $db;

        $html = '';
        $nodes = $db->selectObjects('section', 'parent=' . $parent, 'rank');
//		$nodes = expSorter::sort(array('array'=>$nodes,'sortby'=>'rank', 'order'=>'ASC'));
        foreach ($nodes as $node) {
            if (($node->public == 1 || expPermissions::check('view', expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
                $html .= '<option value="' . $node->id . '" ';
                if ($default == $node->id) $html .= 'selected';
                $html .= '>';
                if ($node->active == 1) {
                    $html .= str_pad('', $depth * 3, '.', STR_PAD_LEFT) . $node->name;
                } else {
                    $html .= str_pad('', $depth * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
                }
                $html .= '</option>';
                $html .= self::levelShowDropdown($node->id, $depth + 1, $default, $ignore_ids);
            }
        }
        return $html;
    }

    /**
     * recursively lists the template hierarchy
     *
     * @static
     *
     * @param int $parent top level parent id
     * @param int $depth  variable to hold level of recursion
     *
     * @return array
     * @deprecated 2.0.0 this only for deprecated templates
     */
    public static function getTemplateHierarchyFlat($parent, $depth = 1) {
        global $db;

        $arr  = array();
        $kids = $db->selectObjects('section_template', 'parent=' . $parent, 'rank');
//		$kids = expSorter::sort(array('array'=>$kids,'sortby'=>'rank', 'order'=>'ASC'));
        for ($i = 0, $iMax = count($kids); $i < $iMax; $i++) {
            $page        = $kids[$i];
            $page->depth = $depth;
            $page->first = ($i == 0 ? 1 : 0);
            $page->last  = ($i == count($kids) - 1 ? 1 : 0);
            $arr[]       = $page;
            $arr         = array_merge($arr, self::getTemplateHierarchyFlat($page->id, $depth + 1));
        }
        return $arr;
    }

    /**
     * @deprecated 2.0.0 this only for deprecated templates
     */
    public static function process_section($section, $template) {
        global $db;

        if (!is_object($template)) {
            $template          = $db->selectObject('section_template', 'id=' . $template);
            $section->subtheme = $template->subtheme;
            $db->updateObject($section, 'section');
        }
        $prefix = '@st' . $template->id;
        $refs   = $db->selectObjects('sectionref', "source LIKE '$prefix%'");
        // Copy all modules and content for this section
        foreach ($refs as $ref) {
            $src = substr($ref->source, strlen($prefix)) . $section->id;
            if (call_user_func(array($ref->module, 'hasContent'))) {
                $oloc = expCore::makeLocation($ref->module, $ref->source);
                $nloc = expCore::makeLocation($ref->module, $src);
                if ($ref->module != "container") {
                    call_user_func(array($ref->module, 'copyContent'), $oloc, $nloc);
                } else {
                    call_user_func(array($ref->module, 'copyContent'), $oloc, $nloc, $section->id);
                }
            }
        }
        // Grab sub pages
        foreach ($db->selectObjects('section_template', 'parent=' . $template->id) as $t) {
            self::process_subsections($section, $t);
        }

    }

    /**
     * @deprecated 2.0.0 this only for deprecated templates
     */
    function process_subsections($parent_section, $subtpl) {
        global $db, $router;

        $section              = new stdClass();
        $section->parent      = $parent_section->id;
        $section->name        = $subtpl->name;
        $section->sef_name    = $router->encode($section->name);
        $section->subtheme    = $subtpl->subtheme;
        $section->active      = $subtpl->active;
        $section->public      = $subtpl->public;
        $section->rank        = $subtpl->rank;
        $section->page_title  = $subtpl->page_title;
        $section->keywords    = $subtpl->keywords;
        $section->description = $subtpl->description;
        $section->id          = $db->insertObject($section, 'section');
        self::process_section($section, $subtpl);
    }

    /**
     * Delete page and send its contents to the recycle bin
     *
     * @param $parent
     * @deprecated 2.3.4 moved to section model
     */
    public static function deleteLevel($parent) {
        global $db;

        $kids = $db->selectObjects('section', 'parent=' . $parent);
        foreach ($kids as $kid) {
            self::deleteLevel($kid->id);
        }
        $secrefs = $db->selectObjects('sectionref', 'section=' . $parent);
        foreach ($secrefs as $secref) {
            $loc = expCore::makeLocation($secref->module, $secref->source, $secref->internal);
            recyclebin::sendToRecycleBin($loc, $parent);
            //FIXME if we delete the module & sectionref the module completely disappears
//            if (class_exists($secref->module)) {
//                $modclass = $secref->module;
//                //FIXME: more module/controller glue code
//                if (expModules::controllerExists($modclass)) {
//                    $modclass = expModules::getControllerClassName($modclass);
//                    $mod = new $modclass($loc->src);
//                    $mod->delete_instance();
//                } else {
//                    $mod = new $modclass();
//                    $mod->deleteIn($loc);
//                }
//            }
        }
//        $db->delete('sectionref', 'section=' . $parent);
        $db->delete('section', 'parent=' . $parent);
    }

    /**
     * Move content page and its children to stand-alones
     *
     * @param $parent
     * @deprecated 2.3.4 moved to section model
     */
    public static function removeLevel($parent) {
        global $db;

        $kids = $db->selectObjects('section', 'parent=' . $parent);
        foreach ($kids as $kid) {
            $kid->parent = -1;
            $db->updateObject($kid, 'section');
            self::removeLevel($kid->id);
        }
    }

    /**
     * Check for cascading page view permission, esp. if not public
     * @deprecated 2.3.4 moved to section model
     */
    public static function canView($section) {
        global $db;

        if ($section == null) {
            return false;
        }
        if ($section->public == 0) {
            // Not a public section.  Check permissions.
            return expPermissions::check('view', expCore::makeLocation('navigation', '', $section->id));
        } else { // Is public.  check parents.
            if ($section->parent <= 0) {
                // Out of parents, and since we are still checking, we haven't hit a private section.
                return true;
            } else {
                $s = $db->selectObject('section', 'id=' . $section->parent);
                return self::canView($s);
            }
        }
    }

    /**
     * Check to see if page is public with cascading
     * @deprecated 2.3.4 moved to section model
     */
    public static function isPublic($s) {
        if ($s == null) {
            return false;
        }
        while ($s->public && $s->parent > 0) {
            $s = new section($s->parent);
        }
        $lineage = (($s->public) ? 1 : 0);
        return $lineage;
    }

    public static function canManageStandalones() {
        global $user;

        if ($user->isAdmin()) return true;
        $standalones = section::levelTemplate(-1, 0);
        //		$canmanage = false;
        foreach ($standalones as $standalone) {
            $loc = expCore::makeLocation('navigation', '', $standalone->id);
            if (expPermissions::check('manage', $loc)) return true;
        }
        return false;
    }

    /**
     * Reassign permissions based on a check/change in menu/page hierarchy
     *
     * @static
     *
     * @param $id
     */
    public static function checkForSectionalAdmins($id) {
        global $db;

        $section = $db->selectObject('section', 'id=' . $id);
        $branch  = section::levelTemplate($id, 0);
        array_unshift($branch, $section);
        $allusers  = array();
        $allgroups = array();
        while ($section->parent > 0) {
            //			$ploc = expCore::makeLocation('navigationController', null, $section);
            $allusers  = array_merge($allusers, $db->selectColumn('userpermission', 'uid', "permission='manage' AND module='navigation' AND internal=" . $section->parent));
            $allgroups = array_merge($allgroups, $db->selectColumn('grouppermission', 'gid', "permission='manage' AND module='navigation' AND internal=" . $section->parent));
            $section   = $db->selectObject('section', 'id=' . $section->parent);
        }
        foreach ($branch as $section) {
            $sloc = expCore::makeLocation('navigation', null, $section->id);
            // remove any manage permissions for this page and it's children
            // $db->delete('userpermission', "module='navigationController' AND internal=".$section->id);
            // $db->delete('grouppermission', "module='navigationController' AND internal=".$section->id);
            foreach ($allusers as $uid) {
                $u = user::getUserById($uid);
                expPermissions::grant($u, 'manage', $sloc);
            }
            foreach ($allgroups as $gid) {
                $g = group::getGroupById($gid);
                expPermissions::grantGroup($g, 'manage', $sloc);
            }
        }
    }

    function manage() {
        global $db, $router, $user;

        expHistory::set('manageable', $router->params);
        assign_to_template(array(
            'canManageStandalones' => self::canManageStandalones(),
            'sasections'           => $db->selectObjects('section', 'parent=-1'),
            'user'                 => $user,
//            'canManagePagesets'    => $user->isAdmin(),
//            'templates'            => $db->selectObjects('section_template', 'parent=0'),
        ));
    }

    public function manage_sitemap() {
        global $db, $user, $sectionObj, $sections;

        expHistory::set('viewable', $this->params);
        $id      = $sectionObj->id;
        $current = null;
        // all we need to do is determine the current section
        $navsections = $sections;
        if ($sectionObj->parent == -1) {
            $current = $sectionObj;
        } else {
            foreach ($navsections as $section) {
                if ($section->id == $id) {
                    $current = $section;
                    break;
                }
            }
        }
        assign_to_template(array(
            'sasections'   => $db->selectObjects('section', 'parent=-1'),
            'sections'     => $navsections,
            'current'      => $current,
            'canManage'    => ((isset($user->is_acting_admin) && $user->is_acting_admin == 1) ? 1 : 0),
        ));
    }

    /**
     * Ajax request for specific pages as json date to yui tree
     */
    public static function returnChildrenAsJSON() {
        global $db;

        //$nav = section::levelTemplate(intval($_REQUEST['id'], 0));
        $id         = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
        $nav        = $db->selectObjects('section', 'parent=' . $id, 'rank');
        //FIXME $manage_all is moot w/ cascading perms now?
        $manage_all = false;
        if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $id))) {
            $manage_all = true;
        }
        //FIXME recode to use foreach $key=>$value
        $navcount = count($nav);
        for ($i = 0; $i < $navcount; $i++) {
            if ($manage_all || expPermissions::check('manage', expCore::makeLocation('navigation', '', $nav[$i]->id))) {
                $nav[$i]->manage = 1;
                $view = true;
            } else {
                $nav[$i]->manage = 0;
                $view = $nav[$i]->public ? true : expPermissions::check('view', expCore::makeLocation('navigation', '', $nav[$i]->id));
            }
            $nav[$i]->link = expCore::makeLink(array('section' => $nav[$i]->id), '', $nav[$i]->sef_name);
            if (!$view) unset($nav[$i]);
        }
        $nav= array_values($nav);
//        $nav[$navcount - 1]->last = true;
        if (count($nav)) $nav[count($nav) - 1]->last = true;
//        echo expJavascript::ajaxReply(201, '', $nav);
        $ar = new expAjaxReply(201, '', $nav);
        $ar->send();
    }

    /**
     * Ajax request for all pages as json date to jstree
     */
    public static function returnChildrenAsJSON2() {
        global $db;

        $icons = array(
            0 => 'addpage',
            1 => 'addextpage',
            2 => 'addintpage',
            3 => 'addfreeform',
        );

        $navs        = $db->selectObjects('section', 'parent!=-1', 'rank');
        foreach ($navs as $i=>$nav) {
            $navs[$i]->parent = $nav->parent?$nav->parent:'#';
            $navs[$i]->text = $nav->name;
            $navs[$i]->icon = $icons[$nav->alias_type];
            if (!$nav->active) {
                $navs[$i]->icon .= ' inactive';
                $attr = new stdClass();
                $attr->class = 'inactive';  // class to obscure elements
                $navs[$i]->a_attr = $attr;
            }
            if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $navs[$i]->id))) {
                $navs[$i]->manage = 1;
                $view = true;
            } else {
                $navs[$i]->manage = 0;
                $navs[$i]->state->disabled = true;
                $view = $navs[$i]->public ? true : expPermissions::check('view', expCore::makeLocation('navigation', '', $navs[$i]->id));
            }
            $navs[$i]->link = expCore::makeLink(array('section' => $navs[$i]->id), '', $navs[$i]->sef_name);
            if (!$view) {
//                unset($navs[$i]);  //FIXME this breaks jstree if we remove a parent and not the child
                $attr = new stdClass();
                $attr->class = 'hidden';  // bs3 class to hide elements
                $navs[$i]->li_attr = $attr;
            }
        }
        $navs= array_values($navs);
//        header('Content-Type: application/json; charset=utf8');
		echo json_encode($navs);
//        echo expJavascript::ajaxReply(201, '', $navs);
        exit;
    }

    /**
     * Ajax function to reorder page hierarchy from yui tree control
     */
    public static function DragnDropReRank() {
        global $db, $router;

        $move   = $router->params['move'];
        $target = $router->params['target'];
        $type   = $router->params['type'];
        $targSec = $db->selectObject("section","id=".$target);
//        $targSec  = new section($target);
        $check_id = $targSec->parent;
        $moveSec = $db->selectObject("section","id=".$move);
//        $moveSec = new section($move);

        // dropped on top of page
        if ($type == "append") {
            //save the old parent in case we are changing the depth of the moving section
            $oldParent = $moveSec->parent;
            //assign the parent of the moving section to the ID of the target section
            $moveSec->parent = $targSec->id;
            //set the rank of the moving section to 0 since it will appear first in the new order
            $moveSec->rank = 1;
            //select all children currently of the parent we're about to append to
            $targSecChildren = $db->selectObjects("section", "parent=" . $targSec->id . " ORDER BY rank");
            //update the ranks of the children to +1 higher to accommodate our new rank 0 section being moved in.
            $newrank = 1;
            foreach ($targSecChildren as $value) {
                if ($value->id != $moveSec->id) {
                    $value->rank = $newrank;
                    $db->updateObject($value, 'section');
                    $newrank++;
                }
            }
            $db->updateObject($moveSec, 'section');
            if ($oldParent != $moveSec->parent) {
                //we need to re-rank the children of the parent that the miving section has just left
                $childOfLastMove = $db->selectObjects("section", "parent=" . $oldParent . " ORDER BY rank");
                for ($i = 0, $iMax = count($childOfLastMove); $i < $iMax; $i++) {
                    $childOfLastMove[$i]->rank = $i;
                    $db->updateObject($childOfLastMove[$i], 'section');
                }

            }
//            echo $moveSec->name . " was appended to " . $targSec->name;

        } elseif ($type == "after") {  // dropped between (after) pages
            if ($targSec->parent == $moveSec->parent) {
                //are we moving up...
                if ($targSec->rank < $moveSec->rank) {
                    $moveSec->rank    = $targSec->rank + 1;
                    $moveNextSiblings = $db->selectObjects("section", "id!=" . $moveSec->id . " AND parent=" . $targSec->parent . " AND rank>" . $targSec->rank . " ORDER BY rank");
                    $rerank           = $moveSec->rank + 1;
                    foreach ($moveNextSiblings as $value) {
                        if ($value->id != $moveSec->id) {
                            $value->rank = $rerank;
                            $db->updateObject($value, 'section');
                            $rerank++;
                        }
                    }
                    $db->updateObject($targSec, 'section');
//                    $targSec->update();
                    $db->updateObject($moveSec, 'section');
//                    $moveSec->update();
                    //or are we moving down...
                } else {
                    $targSec->rank        = $targSec->rank - 1;
                    $moveSec->rank        = $targSec->rank + 1;
                    $movePreviousSiblings = $db->selectObjects("section", "id!=" . $moveSec->id . " AND parent=" . $targSec->parent . " AND rank<=" . $targSec->rank . " ORDER BY rank");
                    $rerank               = 1;
                    foreach ($movePreviousSiblings as $value) {
                        if ($value->id != $moveSec->id) {
                            $value->rank = $rerank;
                            $db->updateObject($value, 'section');
                            $rerank++;
                        }
                    }
                    $db->updateObject($targSec, 'section');
//                    $targSec->update();
                    $db->updateObject($moveSec, 'section');
//                    $moveSec->update();
                }
            } else {  // 'before', is this used?
                //store ranks from the depth we're moving from.  Used to re-rank the level depth the moving section is moving from.
                $oldRank   = $moveSec->rank;
                $oldParent = $moveSec->parent;
                //select all children of the target sections parent with a rank higher than it's own
                $moveNextSiblings = $db->selectObjects("section", "parent=" . $targSec->parent . " AND rank>" . $targSec->rank . " ORDER BY rank");
                //update moving sections rank and parent
                $moveSec->rank   = $targSec->rank + 1;
                $moveSec->parent = $targSec->parent;
                //$rerank=$moveSec->rank+1;
                foreach ($moveNextSiblings as $value) {
                    $value->rank = $value->rank + 1;
                    $db->updateObject($value, 'section');
                }
                $db->updateObject($moveSec, 'section');
                //handle re-ranking of previous parent
                $oldSiblings = $db->selectObjects("section", "parent=" . $oldParent . " AND rank>" . $oldRank . " ORDER BY rank");
                $rerank      = 1;
                foreach ($oldSiblings as $value) {
                    if ($value->id != $moveSec->id) {
                        $value->rank = $rerank;
                        $db->updateObject($value, 'section');
                        $rerank++;
                    }
                }
                if ($oldParent != $moveSec->parent) {
                    //we need to re-rank the children of the parent that the moving section has just left
                    $childOfLastMove = $db->selectObjects("section", "parent=" . $oldParent . " ORDER BY rank");
                    for ($i = 0, $iMax = count($childOfLastMove); $i < $iMax; $i++) {
                        $childOfLastMove[$i]->rank = $i;
                        $db->updateObject($childOfLastMove[$i], 'section');
                    }
                }
            }
        }
        self::checkForSectionalAdmins($move);
        expSession::clearAllUsersSessionCache('navigation');
    }

    /**
     * Ajax function to reorder page hierarchy from jstree control
     */
    public static function DragnDropReRank2() {
        global $router, $db;

        $id = $router->params['id'];
        $page = new section($id);
        $old_rank = $page->rank;
        $old_parent = $page->parent;
        $new_rank = $router->params['position'] + 1;  // rank
        $new_parent = intval($router->params['parent']);

        $db->decrement($page->tablename, 'rank', 1, 'rank>' . $old_rank . ' AND parent=' . $old_parent);  // close in hole
        $db->increment($page->tablename, 'rank', 1, 'rank>=' . $new_rank . ' AND parent=' . $new_parent);  // make room

        $params = array();
        $params['parent'] = $new_parent;
        $params['rank'] = $new_rank;
        $page->update($params);

        self::checkForSectionalAdmins($id);
        expSession::clearAllUsersSessionCache('navigation');
    }

    function edit_section() {
        global $db, $user;

        $parent = new section($this->params['parent']);
        if (empty($parent->id)) $parent->id = 0;
        assign_to_template(array(
            'haveStandalone'  => ($db->countObjects('section', 'parent=-1') && $parent->id >= 0),
            'parent'          => $parent,
            'isAdministrator' => $user->isAdmin(),
        ));
    }

    function edit_contentpage() {
        //FIXME we come here for new/edit content/standalone pages
        // FIXME: Allow non-administrative users to manage certain parts of the section hierarchy.
        //if ($user->is_acting_admin == 1 /*TODO: section admin*/) {
//        $section = null;
        $section = new stdClass();
        if (isset($this->params['id'])) {
            // Check to see if an id was passed in get.  If so, retrieve that section from
            // the database, and perform an edit on it.
            $section  = $this->section->find($this->params['id']);
        } elseif (isset($this->params['parent'])) {
            // The isset check is merely a precaution.  This action should
            // ALWAYS be invoked with a parent or id value.
            $section  = new section($this->params);
        } else {
            notfoundController::handle_not_found();
            exit;
        }
        if (!empty($section->id)) {
            $check_id = $section->id;
        } else {
            $check_id = $section->parent;
        }
        if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $check_id))) {
            if (empty($section->id)) {
                $section->active = 1;
                $section->public = 1;
                if (!isset($section->parent)) {
                    // This is another precaution.  The parent attribute
                    // should ALWAYS be set by the caller.
                    //FJD - if that's the case, then we should die.
                    notfoundController::handle_not_authorized();
                    exit;
                    //$section->parent = 0;
                }
            }
            assign_to_template(array(
                'section' => $section,
                'glyphs' => self::get_glyphs(),
            ));
        } else {  // User does not have permission to manage sections.  Throw a 403
            notfoundController::handle_not_authorized();
        }
    }

    private static function get_glyphs() {
        if (bs()) {
            require_once(BASE . 'external/font-awesome.class.php');
            $fa = new Smk_FontAwesome;
            if (bs3()) {
                $icons = $fa->getArray(BASE . 'external/font-awesome4/css/font-awesome.css');
                $icons = $fa->sortByName($icons);
                return $fa->nameGlyph($icons);
            } elseif (bs2()) {
                expCSS::auto_compile_less(
                    'external/font-awesome/less/font-awesome.less',
                    'external/font-awesome/css/font-awesome.css'
                ); // font-awesome is included within bootstrap2, but not as a separate .css file
                $icons = $fa->getArray(BASE . 'external/font-awesome/css/font-awesome.css', 'icon-');
                return $fa->nameGlyph($icons, 'icon-');
            }
        } else {
            return array();
        }
    }

    function edit_internalalias() {
        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
        if ($section->parent == -1) {
            notfoundController::handle_not_found();
            exit;
        } // doesn't work for standalone pages
        if (empty($section->id)) {
            $section->public = 1;
            if (!isset($section->parent)) {
                // This is another precaution.  The parent attribute
                // should ALWAYS be set by the caller.
                //FJD - if that's the case, then we should die.
                notfoundController::handle_not_authorized();
                exit;
                //$section->parent = 0;
            }
        }
        assign_to_template(array(
            'section' => $section,
            'glyphs' => self::get_glyphs(),
        ));
    }

    function edit_freeform() {
        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
        if ($section->parent == -1) {
            notfoundController::handle_not_found();
            exit;
        } // doesn't work for standalone pages
        if (empty($section->id)) {
            $section->public = 1;
            if (!isset($section->parent)) {
                // This is another precaution.  The parent attribute
                // should ALWAYS be set by the caller.
                //FJD - if that's the case, then we should die.
                notfoundController::handle_not_authorized();
                exit;
                //$section->parent = 0;
            }
        }
        assign_to_template(array(
            'section' => $section,
            'glyphs' => self::get_glyphs(),
        ));
    }

    function edit_externalalias() {
        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
        if ($section->parent == -1) {
            notfoundController::handle_not_found();
            exit;
        } // doesn't work for standalone pages
        if (empty($section->id)) {
            $section->public = 1;
            if (!isset($section->parent)) {
                // This is another precaution.  The parent attribute
                // should ALWAYS be set by the caller.
                //FJD - if that's the case, then we should die.
                notfoundController::handle_not_authorized();
                exit;
                //$section->parent = 0;
            }
        }
        assign_to_template(array(
            'section' => $section,
            'glyphs' => self::get_glyphs(),
        ));
    }

    function update() {
        parent::update();
        expSession::clearAllUsersSessionCache('navigation');
    }

    function move_standalone() {
        expSession::clearAllUsersSessionCache('navigation');
        assign_to_template(array(
            'parent' => $this->params['parent'],
        ));
    }

    /**
     * Move standalone back to hierarchy
     *
     */
    function reparent_standalone() {
        $standalone = $this->section->find($this->params['page']);
        if ($standalone) {
            $standalone->parent = $this->params['parent'];
            $standalone->update();
            expSession::clearAllUsersSessionCache('navigation');
            expHistory::back();
        } else {
            notfoundController::handle_not_found();
        }
    }

    /**
     * Move content page to standalones
     *
     */
    function remove() {
        global $db;

        $section = $db->selectObject('section', 'id=' . $this->params['id']);
        if ($section) {
            section::removeLevel($section->id);
            $db->decrement('section', 'rank', 1, 'rank > ' . $section->rank . ' AND parent=' . $section->parent);
            $section->parent = -1;
            $db->updateObject($section, 'section');
            expSession::clearAllUsersSessionCache('navigation');
            expHistory::back();
        } else {
            notfoundController::handle_not_authorized();
        }
    }

    function delete_standalones() {
        if (!empty($this->params['deleteit'])) {
            foreach ($this->params['deleteit'] as $page) {
                $section = new section(intval($page));
                if ($section) {
//                    self::deleteLevel($section->id);
                    $section->delete();
                }
            }
        }
        expSession::clearAllUsersSessionCache('navigation');
        expHistory::back();
    }

    // create a psuedo global manage pages permission
    public static function checkPermissions($permission,$location) {
        global $exponent_permissions_r, $router;

        // only applies to the 'manage' method
        if (empty($location->src) && empty($location->int) && (!empty($router->params['action']) && $router->params['action'] == 'manage') || strpos($router->current_url, 'action=manage') !== false) {
            if (!empty($exponent_permissions_r['navigation'])) foreach ($exponent_permissions_r['navigation'] as $page) {
                foreach ($page as $pageperm) {
                    if (!empty($pageperm['manage'])) return true;
                }
            }
        }
        return false;
    }

    /**
     * Rebuild the sectionref table as a list of modules on a page
     * @deprecated 2.3.4 moved to sectionref model
     */
    public static function rebuild_sectionrefs() {
        global $db;

        // recursive run though all the nested containers
        function scan_container($container_id, $page_id) {
            global $db;

            $containers = $db->selectObjects('container',"external='" . $container_id . "'");
            $ret = '';
            foreach ($containers as $container) {
                $iLoc = expUnserialize($container->internal);
                $newret = recyclebin::restoreFromRecycleBin($iLoc, $page_id);
                if (!empty($newret)) $ret .= $newret . '<br>';
                if ($iLoc->mod == 'container') {
                    $ret .= scan_container($container->internal, $page_id);
                }
            }
            return $ret;
        }

        // recursive run through all the nested pages
        function scan_page($parent_id) {
            global $db;

            $sections = $db->selectObjects('section','parent=' . $parent_id);
            $ret = '';
            foreach ($sections as $page) {
                $cLoc = serialize(expCore::makeLocation('container','@section' . $page->id));
                $ret .= scan_container($cLoc, $page->id);
                $ret .= scan_page($page->id);
            }
            return $ret;
        }

        // first remove duplicate records
        $db->sql('DELETE FROM ' . $db->prefix . 'sectionref WHERE id NOT IN (SELECT * FROM (SELECT MIN(n.id) FROM ' . $db->prefix . 'sectionref n GROUP BY n.module, n.source) x)');
        $ret = scan_page(0);  // the page hierarchy
        $ret .= scan_page(-1);  // now the stand alone pages

        // we need to get the non-main containers such as sidebars, footers, etc...
        $hardcodedmods = $db->selectObjects('sectionref',"refcount=1000 AND source NOT LIKE '%@section%' AND source NOT LIKE '%@random%'");
        foreach ($hardcodedmods as $hardcodedmod) {
            if ($hardcodedmod->module == 'container') {
                $page_id = intval(preg_replace('/\D/', '', $hardcodedmod->source));
                if (empty($page_id)) {
                    $page_id = SITE_DEFAULT_SECTION;  // we'll default to the home page
                }
                $ret .= scan_container(serialize(expCore::makeLocation($hardcodedmod->module, $hardcodedmod->source)), $page_id);
            } else {
                $hardcodedmod->section = 0;  // this is a hard-coded non-container module
                $db->updateObject($hardcodedmod, 'sectionref');
            }
        }

        // mark modules in the recycle bin as section 0
        $db->columnUpdate('sectionref', 'section', 0, "refcount=0");
//        $recycledmods = $db->selectObjects('sectionref',"refcount=0");
//        foreach ($recycledmods as $recycledmod) {
//            $recycledmod->section = 0;  // this is a module in the recycle bin
//            $db->updateObject($recycledmod, 'sectionref');
//        }
        return $ret;
    }

}

?>
    protected $add_permissions = array(
        'showUnpublished'=>'View Unpublished News',
        'import'=>'Import News Items',
        'export'=>'Export News Items'
    );
        }       
        
            
            $id = $this->params['title'];
        
            
    
    
    
    public function saveConfig() { 
        
        parent::saveConfig();
    
        foreach ($items as $key => $item) { 
        if (!empty($this->config['pull_rss'])) {    
    
                    
    
        
            $id = $this->params['title'];
    
    
                
        
    }           
        
//    public $cacheDir = "framework/modules/pixidou/images/";
        'editor',
        'exitEditor'
        
        
        $canSaveOg = $user->id==$file->poster || $user->is_admin ? 1 : 0 ;
	    if (file_exists(BASE.$file->directory.$file->filename)) {
			$file->copyToDirectory(BASE.$this->cacheDir);
		    flash('error',gt('The file').' "'.BASE.$file->directory.$file->filename.'" '.gt('does not exist on the server.'));
		    redirect_to(array("controller"=>'file',"action"=>'picker',"ajax_action"=>1,"update"=>$this->params['update'],"filter"=>$this->params['filter']));
    
                $oldimage = new expFile($this->params['fid']);                
                $copyname = expFile::resolveDuplicateFilename($oldimage->path); 
                copy(BASE.$this->cacheDir."/".$this->params['cpi'],$oldimage->directory.$copyname); //copy the edited file over to the files dir
                $newFile->filesize = filesize(BASE.$this->cacheDir."/".$this->params['cpi']);
                $resized = getimagesize(BASE.$this->cacheDir."/".$this->params['cpi']);
                $resized = getimagesize(BASE.$this->cacheDir."/".$this->params['cpi']);
                copy(BASE.$this->cacheDir."/".$this->params['cpi'],$oldimage->directory.$oldimage->filename); //copy the edited file over to the files dir
            
        $types = array(".jpg",".gif",".png");
        
        $cachedir = BASE.$this->cacheDir;
        
                if (in_array(substr($tmpfile,-4,4),$types)) {
                    $filename = $cachedir.$tmpfile;
        
        redirect_to(array("controller"=>'file',"action"=>'picker',"ajax_action"=>1,"update"=>$this->params['update'],"filter"=>$this->params['filter']));
    
?>
    protected $add_permissions = array(
        'import'=>'Import Portfolio Items',
        'export'=>'Export Portfolio Items'
    );
    protected $add_permissions = array(
    protected $add_permissions = array(
        'build_report' => 'Manage',
        'order_report' => 'Generate Order Report',
        'product_report' => 'Generate Product Report',
        'batch_export' => 'Export Products',
        'export_order_items' => 'Export Order Items File');
            [date-startdate] => 
            [time-h-startdate] => 
            [time-m-startdate] => 
            [date-enddate] => 
            [time-h-enddate] =>     
            [time-m-enddate] => 
            [order-range-num] => 
            [order-price-num] => 
            [pnam] => 
            [sku] => 
            [blshpname] => 
            [email] => 
            [zip] => 
        //$items = $prod->find('all', 1, 'id DESC',25);  
        //$items = $order->find('all', 1, 'id DESC',25);  
        $geos = $geo->find('all');        
        //eDebug(strftime("%A, %d %B %Y", mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y"))));  
        //build 
            //get each calculator's id  
            [date-startdate] => 
            [time-h-startdate] => 
            [time-m-startdate] => 
            [date-enddate] => 
            [time-h-enddate] =>     
            [time-m-enddate] => 
            [order-range-num] => 
            [order-price-num] => 
            [pnam] => 
            [sku] => 
            [blshpname] => 
            [email] => 
            [zip] => 
        //$items = $prod->find('all', 1, 'id DESC',25);  
        //$items = $order->find('all', 1, 'id DESC',25);  
        //eDebug($sql . $sqlwhere); 
        //strftime("%a %d-%m-%Y", get_first_day(3, 1, 2007)); Thursday, 1 April 2010  
            //$line = expString::outputField("SMC Inventory - Laurie");         
        //$items = $product->find('all', '', 'id', 25);     
        //$page = new expPaginator();   
        //eDebug($page,true);   
                'Invoice #'=>'invoice_id', 
        // 
        //     
        // assign_to_template(array('page'=>$page)); 
        //echo "1<br>"; eDebug($str); 
            //if HTML, then leave the single quotes alone, otheriwse replace w/ special Char            
        //$str = str_replace(",","\,",$str); 
            * description      
            * id - SKU      
            * link      
            * price      
            * title      
            * brand - manufacturer      
            * image link - fullsized image, up to 10, comma seperated          
            * product type - category - "Electronics > Audio > Audio Accessories MP3 Player Accessories","Health & Beauty > Healthcare > Biometric Monitors > Pedometers"      
        $allOrderCount = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend,null,null,null,true,false,$except,true);            
        
        
                
        $ordersInCheckout = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend . " AND user_id != 0",null,null,null,true,false,$except,true);            
        
        //$ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend . " AND user_id != 0 AND order_type_id = 1",null,null,null,true,false,$except,true);     
        //$ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend . " AND user_id != 0",null,null,null,true,false,$except,true);     
        $ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);     
        $orders = $this->o->find('all','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);     
               
        eDebug("All:" . $allOrderCount);    
        eDebug("Carts w/ Items:" . $allCartsWithItems);           
        eDebug("Carts w/ Items in Checkout:" . $ordersInCheckout);           
        eDebug("Purchased:" . $ordersPurchased);  
        
        
        
  
        
        assign_to_template(array('prev_month'=>$this->prev_month, 'now_date'=>$this->now_date, 'now_hour'=>$this->now_hour, 'now_min'=>$this->now_min, 'now_ampm'=>$this->now_ampm, 'prev_hour'=>$this->prev_hour, 'prev_min'=>$this->prev_min, 'prev_ampm'=>$this->prev_ampm)); 
        /*OPTIONALLY ENCLOSED BY '" . '"' . 
        /*OPTIONALLY ENCLOSED BY '" . '"' . 
    protected $add_permissions = array(
        'spider'=>'Spider Site'

    
	
        
    
        
        
	
		
		
		
		
		
		
		
		
			
			
			
	
	
		
		
	
		
	
		
            $answer = new simplepoll_answer($this->params['choice']);
		user::login(expString::sanitize($_POST['username']),expString::sanitize($_POST['password']));
    protected $add_permissions = array(
    );
    protected $remove_permissions = array(
        'create',
        'edit'
        // if this is a new user account we need to check the password.  
        // if this is a new account then we will check to see if we need to send 
        $tok = $db->selectObject('passreset_token', 'uid=' . $this->params['uid'] . " AND token='" . preg_replace('/[^A-Za-z0-9]/', '', $this->params['token']) . "'");
        $u = new user($this->params['uid']);

Fixed code:
    );
    protected $m_permissions = array(  // standard set of actions requiring manage permission for all modules
        'activate'  => 'Activate',
        'approve'   => 'Approve',
        'merge'     => 'Merge',
        'rerank'    => 'ReRank',
        'import'    => 'Import Items',
        'export'    => 'Export Items'
    protected $add_permissions = array();  // additional $permissions processed and visible  for this module
    protected $manage_permissions = array();  // additional actions requiring manage permission in addition to $m_permissions
    public $requires_login = array();  // actions/methods which ONLY require user be logged in to access...$permissions take priority
        if (ENABLE_WORKFLOW)
            $this->permissions = array_merge($this->permissions, array('approve'=>'Approval'));
        $tag = new expTag(expString::escape($this->params['tag']));
            'moduletitle' => ucfirst($modelname) . ' ' . gt('items tagged with') . ' "' . expString::escape($this->params['tag']) . '"',
            $id = expString::escape($this->params['title']);
        $this->params['title'] = expString::escape($this->params['title']);  // escape title to prevent sql injection
        $id = isset($this->params['title']) ? expString::escape($this->params['title']) : (isset($this->params['id']) ? $this->params['id'] : null);
     * permission functions to aggregate a module's visible permissions based on add/remove permissions
    /**
     * permission functions to aggregate a module's permissions based on add/remove and manage permissions
     *
     * @return array
     */
    public function permissions_all() {
        //set the permissions array
        $perms = array();
        foreach ($this->permissions as $perm => $name) {
            if (!in_array($perm, $this->remove_permissions)) $perms[$perm] = $name;
        }
        $perms = array_merge($perms, $this->m_permissions, $this->add_permissions, $this->manage_permissions);
        return $perms;
    }

    $controller = new $fullControllerName($src, $parms);


    $perms = $controller->permissions_all();

    $common_action = null;
    // action convention for controllers that manage more than one model (datatype).
    // if you preface the name action name with a common crud action name we can check perms on
    // it with the developer needing to specify any...better safe than sorry.
    // i.e if the action is edit_mymodel it will be checked against the edit permission
    if (stristr($parms['action'], '_'))
        $parts = explode("_", $parms['action']);
    else
        $parts = preg_split('/(?=[A-Z])/', $parms['action']);  // account for actions with camelCase action/perm such as editItem
    $common_action = isset($parts[0]) ? $parts[0] : null;
    if ($parms['action'] == 'update' || $common_action == 'update') {
    } elseif (($parms['action'] == 'edit' || $common_action == 'edit') && (!isset($parms['id']) || $parms['id'] == 0)) {
            $msg = empty($controller->requires_login[$perm_action]) ? gt("You must be logged in to perform this action") : gt($controller->requires_login[$perm_action]);
            $msg = empty($controller->requires_login[$common_action]) ? gt("You must be logged in to perform this action") : gt($controller->requires_login[$common_action]);
    }


}





    // get the common configuration files
    // look for a config form for this module's current view


    // set path information



        // retrieve objects
            // Otherwise we assume that in inbound is an array or Object to be processed as is.
        // setup the exception array if it's not there.  This array tells the getAssociatedObjectsForThisModel() function which
        $order = expString::escape($order);
        if ($limit !== null)
            $limit = intval($limit);
        if ($limitstart !== null)
            $limitstart = intval($limitstart);
            // if not, then we check to see if we had a previous value in this particular
            // this is good for when the developer is trying to update just a field or two
            // in an existing record.
        //$this->saveAssociatedObjects();
        // mapped view and src hasn't been passed in via link to the form
    function columnUpdate($table, $col, $val, $where=1) {
        //fwrite($lfh, $sql . "\n");
        //fclose($lfh);

        $res = mysqli_query($this->connection, $sql);


        //if ($table=="text") eDebug($object,true);
            //if ($table=="text") eDebug($object,true);
                    $val = serialize($val);
        //if ($table == 'text') eDebug($sql,true);
	 * Escape a string based on the database connection
    function selectArraysBySql($sql) {

	 * Escape a string based on the database connection
   	 * Attempt to prevent a sql injection
 *
 *
 *      'where'=>1,
 *
	public $where = '';
     */
		global $router, $db;
        $this->limit = empty($params['limit']) ? 0 : intval($params['limit']);
		$this->order = empty($params['order']) ? 'id' : expString::escape($params['order']);
		$this->dir = empty($params['dir']) || !in_array($params['dir'], array('ASC', 'DESC')) ? 'ASC' : $params['dir'];
		$this->src = empty($params['src']) ? null : expString::escape($params['src']);



		$this->order_direction = $this->dir;
        if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $this->order))
            $this->order = 'id';
        if (!in_array($this->order_direction, array('ASC', 'DESC')))
            $this->order_direction = 'ASC';


		}

                    if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $this->order))
                        $this->order = 'id';
                    if (!in_array($this->order_direction, array('ASC', 'DESC')))
                        $this->order_direction = 'ASC';




		        $this->last_pagelink = $this->total_pages;
		for($i=$this->first_pagelink; $i<=$this->last_pagelink; $i++) {
		}






        $func = new ReflectionClass($this);
                $newParams[$propname] = $params[$propname];
            }
        }
                $newParams[$propname] = $params[$propname];
            }
        }






                }




        }





				}
				$params['order'] = $col;

				if (!empty($col)) {
                        $params['dir'] = 'ASC';
                        $params['dir'] = 'DESC';
                        $params['dir'] = 'ASC';
                    }
				}

                $str .= "'" . intval($value) . "'";
                    $str .= "'" . expString::escape(str_replace("'", "\'", $value)) . "'";  //FIXME is this still necessary since we stripslashes above???
                    $str .= "'" . expString::escape(str_replace("'", '', $value)) . "'";
        if (!empty($profile) && (strpos($profile, '..') !== false || strpos($profile, '/') !== false)) {
            header('Location: ' . URL_FULL);
            exit();  // attempt to hack the site
        }
?>
	}
		}

			$str = stripcslashes($str);
        $str = str_replace("&lsquo;","'",$str);
        $str = str_replace("�","-", $str);
        $str = str_replace("\r\n"," ",$str);
        $str = str_replace("�","(R)",$str);
        $str = str_replace("&","&amp;",$str);
		$str = str_replace(">","&gt;",$str);
//        global $db;
//	        $str = self::escape(trim(str_replace("�", "&trade;", $str)));
//            $str = self::escape(trim(str_replace("�", "&trade;", $str)));
        $str = self::escape(trim(str_replace("�", "&trade;", $str)));
        $str = '';
            $str .= '<meta charset="' . LANG_CHARSET . XHTML_CLOSING . '>' . "\n";  // html5
            $str .= "\t" . '<meta http-equiv="Content-Type" content="text/html; charset=' . LANG_CHARSET . '" ' . XHTML_CLOSING . '>' . "\n";  // html4 or xhtml?
        if ($config['meta']['ie_compat']) {
            // turn off ie compatibility mode which will break the display
            $str .= "\t" . '<meta http-equiv="X-UA-Compatible" content="IE=edge"' . XHTML_CLOSING . '>' . "\n";
        }
        $str .= "\t" . '<title>' . $metainfo['title'] . "</title>\n";
            $str .= "\t" . '<meta http-equiv="Content-Language" content="' . $locale . '" ' . XHTML_CLOSING . '>' . "\n";
?>
//	public $useractions = array(
//    );
    protected $manage_permissions = array(
//        'import' => 'Import External Addresses',
        'process' => 'Import External Addresses'



			if ($count == 0)
            //user is not logged in, but allow anonymous checkout is enabled so we'll check
            $this->params['is_shipping'] = 1;
		expHistory::back();

        {
                if ($address->is_shipping)

        $db->setUniqueFlag($object, 'addresses', expString::escape($this->params['is_what']), "user_id=" . $user->id);
        expHistory::back();


        $gr = new geoRegion();


            $gc->active = true;
            $gc->save();
            $gc = new geoCountry(intval($this->params['country_default']));
            $db->setUniqueFlag($gc,'geo_country','is_default','id=' . $gc->id);
            $gc->refresh();
            $gr->save();
    protected $manage_permissions = array(
        'change'=>'Change Settings',
        'mass'=>'Mass Mailing',
        'save'=>'Save Settings',
//        'update'=>'Update Settings',




//	public function fix_sessions() {
//	    global $db;
//
////		$test = $db->sql('CHECK TABLE '.$db->prefix.'sessionticket');
//		$fix = $db->sql('REPAIR TABLE '.$db->prefix.'sessionticket');
//		flash('message', gt('Sessions Table was Repaired'));
//		expHistory::back();
//	}
		ksort($menu);






    }







    public $useractions = array(
        'showall'=>'Display Banner(s)'
    );
    protected $manage_permissions = array(
        'reset' => 'Reset Stats'
    );

            // randomly grab one banner to be displayed
            $where = 'id IN ('.implode(',', $this->config['banners']).')';
            foreach($banners as $banner) {







        }



        $filename = 'banner_export' . date("m-d-Y") . '.csv';
        fclose($fh);

        // let the user know we did stuff.
    protected $manage_permissions = array(
//        'approve'=>"Approve Comments",
    );
        $this->params['author'] = expString::escape($this->params['author']);
            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>expString::escape($this->params['title'])));
        $modelname = empty($this->params['model']) ? $this->basemodel_name : expString::escape($this->params['model']);
    protected $manage_permissions = array(
        'change' => 'Change Cats'
    );
    protected $remove_permissions = array(
    protected $add_permissions = array(
        'approve'=>"Approve Comments",
        'bulk'=>"Bulk Actions"
    );

            expHistory::back();
	    }


	}


            'sql'=>$sql,
        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : intval($this->params['require_login']);
        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : intval($this->params['require_approval']);
        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : intval($this->params['require_notification']);
        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : expString::escape($this->params['notification_email']);
        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
            'sql'=>$sql,

            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
        }

			'content_id'=>$this->params['content_id'],








        /* The global constants can be overriden by passing appropriate params */




        /* The global constants can be overriden by passing appropriate params */



        /* The global constants can be overriden by passing appropriate params */

        /* The global constants can be overriden by passing appropriate params */



        $db->delete($comment->attachable_table, 'expcomments_id='.$this->params['id']);



        /* The global constants can be overriden by passing appropriate params */



        $mail = new expMail();


        /* The global constants can be overriden by passing appropriate params */

        $mail = new expMail();

//        assign_to_template(array('record'=>$record,'tag'=>$tag));  //FIXME $record & $tag are undefined



		if ($ctl) {
		assign_to_template(array('form_html'=>$form->toHTML(), 'types'=>$types[$control_type]));

	function save() {
		if (call_user_func(array($_POST['control_type'],'useGeneric')) == true) {





    protected $manage_permissions = array(
        'activate' => "Activate",
        'preview'  => "Preview Editor Toolbars"
    );
    public $requires_login = array(
        'preview'=>'Preview Editor',
    );

    protected $manage_permissions = array(
        'approve'=>"Approve Notes"


        /* The global constants can be overriden by passing appropriate params */

        if (empty($this->params['formtitle']))

    }


        /* The global constants can be overriden by passing appropriate params */


            'sql'=>$sql,



        /* The global constants can be overriden by passing appropriate params */
        $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : intval($this->params['require_login']);
        $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : intval($this->params['require_approval']);
        $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : intval($this->params['require_notification']);
        $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : expString::escape($this->params['notification_email']);


        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";

            'sql'=>$sql,

        // count the unapproved notes
            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
        }

            'unapproved'=>$unapproved,
            'content_id'=>$this->params['content_id'],

        /* The global constants can be overriden by passing appropriate params */


        // if simplenotes are configed to require approvals set this to 0 otherwise we








        /* The global constants can be overriden by passing appropriate params */





        /* The global constants can be overriden by passing appropriate params */





        /* The global constants can be overriden by passing appropriate params */





        /* The global constants can be overriden by passing appropriate params */



        $db->delete($simplenote->attachable_table, 'expsimplenote_id='.$this->params['id']);



        /* The global constants can be overriden by passing appropriate params */
        $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : intval($this->params['require_login']);
        $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : intval($this->params['require_approval']);
        $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : intval($this->params['require_notification']);
        $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : expString::escape($this->params['notification_email']);



        $mail = new expMail();

    protected $manage_permissions = array(
//        'import' => 'Import Tags',
//        'importTags' => 'Import Tags',
//        'export' => 'Export Tags',
        'change' => 'Change Tags',
    );
            $id = expString::escape($this->params['title']);
    protected $manage_permissions = array(
        'send'=>'Send E-Alert',
    );



        $src = empty($this->params['src']) ? null : expString::escape($this->params['src']);






        $src = empty($this->params['src']) ? null : expString::escape($this->params['src']);





        }

//    public function subscriptions() {
//        global $db;
//
//        expHistory::set('manageable', $this->params);
//        // make sure we have what we need.
//        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
//        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
//
//        // verify the id/key pair
//        $sub = new subscribers($this->params['id']);
//        if (empty($sub->id)) expQueue::flashAndFlow('error', gt('We could not find any subscriptions matching the ID and Key you provided.'));
//
//        // get this users subscriptions
//        $subscriptions = $db->selectColumn('expeAlerts_subscribers', 'expeAlerts_id', 'subscribers_id='.$sub->id);
//
//        // get a list of all available E-Alerts
//        $ealerts = new expeAlerts();
//        assign_to_template(array(
//            'subscriber'=>$sub,
//            'subscriptions'=>$subscriptions,
//            'ealerts'=>$ealerts->find('all')
//        ));
//    }

//    public function subscription_update() {
//        global $db;
//
//        // make sure we have what we need.
//        if (empty($this->params['email'])) expQueue::flashAndFlow('error', gt('You must supply an email address to sign up for email alerts.'));
//        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
//        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
//
//        // find the subscriber and validate the security key
//        $subscriber = new subscribers($this->params['id']);
//        if ($subscriber->hash != $this->params['key']) expQueue::flashAndFlow('error', gt('The security key you supplied does not match the one we have on file.'));
//
//        // delete any old subscriptions and add the user to new subscriptions
//        $db->delete('expeAlerts_subscribers', 'subscribers_id='.$subscriber->id);
//        foreach($this->params['ealerts'] as $ea_id) {
//            $obj = new stdClass();
//            $obj->subscribers_id = $subscriber->id;
//            $obj->expeAlerts_id = $ea_id;
//            $db->insertObject($obj, 'expeAlerts_subscribers');
//        }
//
//        $count = count($this->params['ealerts']);
//
//        if ($count > 0) {
//            flash('message', gt("Your subscriptions have been updated.  You are now subscriber to")." ".$count.' '.gt('E-Alerts.'));
//        } else {
//            flash('error', gt("You have been unsubscribed from all E-Alerts."));
//        }
//
//        expHistory::back();
//    }

//    public function signup() {
//        global $db;
//        // check the anti-spam control
//        expValidator::check_antispam($this->params, gt("Anti-spam verification failed.  Please try again."));
//
//        // make sure we have what we need.
//        if (empty($this->params['email'])) expQueue::flashAndFlow('error', gt('You must supply an email address to sign up for email alerts.'));
//        if (empty($this->params['ealerts'])) expQueue::flashAndFlow('error', gt('You did not select any E-Alert topics to subscribe to.'));
//
//        // find or create the subscriber
//        $id = $db->selectValue('subscribers', 'id', 'email="'.$this->params['email'].'"');
//        $subscriber = new subscribers($id);
//        if (empty($subscriber->id)) {
//            $subscriber->email = trim($this->params['email']);
//            $subscriber->hash = md5($subscriber->email.time());
//            $subscriber->save();
//        }
//
//        // delete any old subscriptions and add the user to new subscriptions
//        $db->delete('expeAlerts_subscribers', 'subscribers_id='.$subscriber->id);
//        foreach($this->params['ealerts'] as $ea_id) {
//            $obj = new stdClass();
//            $obj->subscribers_id = $subscriber->id;
//            $obj->expeAlerts_id = $ea_id;
//            $db->insertObject($obj, 'expeAlerts_subscribers');
//        }
//
//        // send a confirmation email to the user.
//        $ealerts = $db->selectObjects('expeAlerts', 'id IN ('.implode(',', $this->params['ealerts']).')');
//        $body = expTemplate::get_template_for_action($this, 'email/confirmation_email', $this->loc);
//        $body->assign('ealerts', $ealerts);
//        $body->assign('subscriber', $subscriber);
//
//        $mail = new expMail();
//        $mail->quickSend(array(
//                'html_message'=>$body->render(),
//		        'to'=>$subscriber->email,
//                'from'=>array(trim(SMTP_FROMADDRESS) => trim(ORGANIZATION_NAME)),
//		        'subject'=>gt('Please confirm your E-Alert subscriptions'),
//        ));
//
//        redirect_to(array('controller'=>'ealert', 'action'=>'pending', 'id'=>$subscriber->id));
//    }

//    public function pending() {
////        global $db;
//
//        // make sure we have what we need.
//        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('Your subscriber ID was not supplied.'));
//
//        // find the subscriber and their pending subscriptions
//        $ealerts = expeAlerts::getPendingBySubscriber($this->params['id']);
//        $subscriber = new subscribers($this->params['id']);
//
//        // render the template
//        assign_to_template(array(
//            'subscriber'=>$subscriber,
//            'ealerts'=>$ealerts
//        ));
//    }

    /**
     * @deprecated
     */
//    public function confirm() {
//
//        // make sure we have what we need.
//        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
//        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
//
//        // verify the id/key pair
//        $id = $db->selectValue('subscribers','id', 'id='.$this->params['id'].' AND hash="'.$this->params['key'].'"');
//        if (empty($id)) expQueue::flashAndFlow('error', gt('We could not find any subscriptions matching the ID and Key you provided.'));
//
//        // activate this users pending subscriptions
//        $sub = new stdClass();
//        $sub->enabled = 1;
//        $db->updateObject($sub, 'expeAlerts_subscribers', 'subscribers_id='.$id);
//
//        // find the users active subscriptions
//        $ealerts = expeAlerts::getBySubscriber($id);
//        assign_to_template(array(
//            'ealerts'=>$ealerts
//        ));
//    }
    protected $manage_permissions = array(
        'select'=>'Select Feature',
        'toggle'=>'Toggle Feature',





                                'body'=>$calcobj->description(),


	public function activate(){

    protected $manage_permissions = array(
        'options'=>'Display Options'
    );



        $record = new optiongroup_master($id);












        $record = new option_master($params);

    function update_option_master() {











        $groups = array(
       // eDebug($discount);






    public function activate_discount(){








        $gc = new geoCountry();

        $gr = new geoRegion();

    }

		$gc = new geoCountry();

        $gr = new geoRegion();




    protected $add_permissions = array(
//        'emailRegistrants'=> 'Email Registrants',
    );
    protected $manage_permissions = array(
        'emailRegistrants'=> 'Email Registrants',
    );
    protected $manage_permissions = array(
        'add_order_item'      => 'Add Order Item',
        'download'      => 'Download Label',
//        'create_new_order'    => 'Create A New Order',
//        'createReferenceOrder'=> 'Create Reference Order',
//        'edit_address'        => 'Edit Address',
//        'edit_invoice_id'     => 'Edit Invoice Id',
//        'edit_order_item'     => 'Edit Order Item',
//        'edit_payment_info'   => 'Edit Payment Info',
//        'edit_shipping_method'=> 'Edit Shipping Method',
//        'edit_totals'         => 'Edit Totals',
        'email'         => 'Send Email',
        'quickfinder'=> 'Do a quick order lookup',
//        'save_new_order_item'=> 'Save New Order Item',
        'save_reference_order'=> 'Save Reference Order',
        'set'           => 'Change Status',
        'showall'             => 'Manage',
        'show'                => 'View Orders',
        'update'                => 'update order',

                    $db->delete('orderitems', 'orders_id='.$cart->id);

            }

        //viewing of the order?
                    //eDebug($order['id'] . ": " . $timer->mark());

            //eDebug($note,true);
        // figure out what metadata to pass back based on the action
        /*eDebug($this->params);
        //eDebug($order,true);
        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));
        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true);
            //$newOi->products_tax = 0;
        //eDebug($order,true);
        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));
        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true);
            //$oi->product->optiongroup = $parProd->optiongroup;
            /*if ($uif['is_required'] || (!$uif['is_required'] && strlen($params['user_input_fields'][$uifkey]) > 0))
                    //flash('error', 'test');
                    //redirect_to(array('controller'=>cart, 'action'=>'displayForm', 'form'=>'addToCart', 'product_id'=>$this->id, 'product_type'=>$this->product_type));

                    //flash('error', );
                    //redirect_to(array('controller'=>cart, 'action'=>'displayForm', 'form'=>'addToCart', 'product_id'=>$this->id, 'product_type'=>$this->product_type));
                }
        //eDebug($oi);
            //we'll send over the product_id of the parent, along with id's and quantities of children we're adding

                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order[0]->id));
                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order->id));
            flashAndFlow('message','Invalid order number.');
                //eDebug($tmpCart,true);
        $sql .= "from " . $db->prefix . "addresses as a "; //R JOIN " .
        $sql .= "from " . $db->prefix . "external_addresses as a "; //R JOIN " .
    protected $manage_permissions = array(
        'toggle'=>'Toggle Status'
    );












	protected $manage_permissions = array(




















    protected $manage_permissions = array(
        'editspeed'=>'Edit Shipping Speed',
        'save'=>'Save Configuration',
        'select'=>'Select Feature',
        'toggle'=>'Enable/Disable Options',





		        $sm->to = empty($this->params['shpmessageto']) ? null : $this->params['shpmessageto'];
		        $sm->from = empty($this->params['shpmessagefrom']) ? null : $this->params['shpmessagefrom'];
		        $sm->message = empty($this->params['shpmessage']) ? null : $this->params['shpmessage'];

		$ar->send();






                    $id = $db->selectValue('shippingcalculator', 'id', 'calculator_name="'.$classname.'"');
                        if ($calcobj->isSelectable() == true) {



        $conf = serialize($calc->parseConfig($this->params));




    protected $manage_permissions = array(
//        'import' => 'Import Category',
//        'importCategory' => 'Import Category',
    static function displayname() {
        return gt("e-Commerce Category Manager");
    }

    static function description() {
        return gt("This module is for managing categories in your store.");
    }

        //
        //         //  $this->tags[$i]->draggable = $this->draggable;
        //         //  $this->tags[$i]->checkable = $this->checkable;
        // $obj = json_encode($categories);
            // Trees mapped

                }

        //
        //
        //
        //
        //
        //
        //
        //
    protected $manage_permissions = array(
        'batch_process'               => 'Batch capture order transactions',
        'cleanNonUnicodeProducts'     => 'Clean all non-unicode charset products',
        'copyProduct'                 => "Copy Product",
//        'delete_children'             => "Delete Children",
        'reimport'                    => 'ReImport Products',
        'findDupes'                   => 'Fix Duplicate SEF Names',
//        'manage_sales_reps'           => 'Manage Sales Reps',
//        'import_external_addresses'   => 'Import addresses from other sources',
        'showallImpropercategorized'  => 'View products in top level categories that should not be',
        'showallUncategorized'        => 'View all uncategorized products',
        'nonUnicodeProducts'          => 'View all non-unicode charset products',
        'process_orders'              => 'Batch capture order transactions',
        'processModelAliases'         => 'Process uploaded model aliases',
        'saveModelAliases'            => 'Save uploaded model aliases',
//        'deleteProcessedModelAliases' => 'Delete processed uploaded model aliases',
//        'delete_model_alias'          => 'Process model aliases',
//        'update_model_alias'          => 'Save model aliases',
//        'edit_model_alias'            => 'Delete model aliases',
//        'import'                      => 'Import Products',
//        'importProduct'               => 'Import Products',
//        'export'                      => 'Export Products',
        'uploadModelAliases'          => 'Upload model aliases',
    );
            $ancestors = $this->category->pathToNode();
            {
            $ancestors = $this->category->pathToNode();
            //eDebug($editable_options[$group->title]);
        //eDebug($product_type);
        //eDebug($this->params,true);
        if (empty($product->id)) // || empty($product->previous_id))
            //fwrite($lfh, "Deleting:" . $ctd->id . "\n");
        //$sql .= "GROUP BY p.id ";
        $req = 'a29f9shsgh32hsf80s7';
        {
            $successSet[$count]['message'] = "Sucessfully imported row " . $count . ", order: " . $data[2] . "<br/>";
            $successSet[$count]['shipping_tracking_number'] = '1ZNF453937547';
        {
            $data[2] = $inv + $count;
            $amt += $count*$count;

        assign_to_template(array('errorSet'=>$errorSet, 'successSet'=>$successSet));
        //eDebug($this->params,true);
        //eDebug($data);
                        //just need to set the order shipping info, check and see if we send user an email, and set statuses.
                        //shipping info:
                        //$failMessage = "Attempted to delay capture order " . $data[2] . " and it failed with the following error: " . $result->errorCode . " - " .$result->message;

                            $order->save();
                        //continue;
                    //dont suppose we do anything here, as it may be set to approved manually
                    //$errorSet[$count] = "Order " . $data[2] . " does not use a billing method with delayed capture ability.";
            //eDebug($product);
        //eDebug($data);
        $sql .= empty($order) ? '' : ' ORDER BY ' . expString::escape($order);
            $sql .= empty($limit) ? '' : ' LIMIT ' . intval($limitstart) . ',' . intval($limit);
<?php

##################################################
#
# Copyright (c) 2004-2016 OIC Group, Inc.
#
# This file is part of Exponent
#
# Exponent is free software; you can redistribute
# it and/or modify it under the terms of the GNU
# General Public License as published by the Free
# Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# GPL: http://www.gnu.org/licenses/gpl.txt
#
##################################################

/**
 * @subpackage Controllers
 * @package    Modules
 */

class eventController extends expController {
//    public $basemodel_name = 'event';
    public $useractions = array(
        'showall' => 'Show Calendar',
    );
//    protected $manage_permissions = array(
//        'import' => 'Import Calendar',
//    );
    public $remove_configs = array(
        'comments',
        'ealerts',
//        'facebook',
        'files',
        'pagination',
        'rss',
//        'twitter',
    );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)

    static function displayname() {
        return "Events";
    }

    static function description() {
        return "Manage events and schedules, and optionally publish them.";
    }

    static function author() {
        return "Dave Leffler";
    }

    static function isSearchable() {
        return true;
    }

    function searchName() {
        return gt("Calendar Event");
    }

    function searchCategory() {
        return gt('Event');
    }

    /**
     * can this module import data?
     *
     * @return bool
     */
    public static function canImportData() {
        return true;
    }

    function showall() {
        global $user;

        expHistory::set('viewable', $this->params);
        $locsql = $this->aggregateWhereClause();
        $time = (isset($this->params['time']) ? intval($this->params['time']) : time());
        assign_to_template(array(
            'time' => $time,
            'daynames' => event::dayNames(),
        ));

        $regcolor = !empty($this->config['registrations_color']) ? $this->config['registrations_color'] : null;

        $ed = new eventdate();
        $viewtype = 'default';
        $viewrange = 'all';
        $view = !empty($this->params['view']) ? $this->params['view'] : 'showall';
        switch ($view) {
            case 'showall_Administration':
                $viewtype = "administration";
                break;
            case 'showall_Past Events':
                $viewrange = "past";
                break;
            case 'showall_Monthly Summary':
            case 'showall_Mini-Calendar':
            case 'minical':
                $viewtype = "minical";
                break;
            case 'showall_Monthly List':
            case 'showall_List':
            case 'monthlist':
                $viewtype = "byday";
                $viewrange = "month";
                break;
            case 'showall_Week':
            case 'week':
                $viewtype = "byday";
                $viewrange = "week";
                break;
            case 'showall_Day':
            case 'day':
                $viewtype = "byday";
                $viewrange = "day";
                break;
            case 'showall_announcement':
            case 'showall_Upcoming Events':
            case 'showall_Upcoming Events - Headlines':
                $viewrange = "upcoming";
                break;
            case 'showall':
            case 'month':
                $viewtype = "monthly";
                break;
            default :
                $view_params = explode('_',$view);
                if (!empty($view_params[1])) $viewtype = $view_params[1];
                if (!empty($view_params[2])) $viewrange = $view_params[2];
        }  // end switch $view

        switch ($viewtype) {
            case "minical":
                $monthly = expDateTime::monthlyDaysTimestamp($time);
                $info = getdate($time);
                $timefirst = mktime(0, 0, 0, $info['mon'], 1, $info['year']);
                $now = getdate(time());
                $currentday = $now['mday'];
                $endofmonth = date('t', $time);
                foreach ($monthly as $weekNum => $week) {
                    foreach ($week as $dayNum => $day) {
                        if ($dayNum == $now['mday']) {
                            $currentweek = $weekNum;
                        }
                        if ($dayNum <= $endofmonth) {
//                            $monthly[$weekNum][$dayNum]['number'] = ($monthly[$weekNum][$dayNum]['ts'] != -1) ? $db->countObjects("eventdate", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($day['ts']) . " AND date <= " . expDateTime::endOfDayTimestamp($day['ts'])) : -1;
                            $monthly[$weekNum][$dayNum]['number'] = ($monthly[$weekNum][$dayNum]['ts'] != -1) ? $ed->find("count", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($day['ts']) . " AND date <= " . expDateTime::endOfDayTimestamp($day['ts'])) : -1;
                        }
                    }
                }
                $prevmonth = mktime(0, 0, 0, date("m", $timefirst) - 1, date("d", $timefirst) + 10, date("Y", $timefirst));
                $nextmonth = mktime(0, 0, 0, date("m", $timefirst) + 1, date("d", $timefirst) + 10, date("Y", $timefirst));
                assign_to_template(array(
                    "monthly"     => $monthly,
                    "currentweek" => $currentweek,
                    "currentday"  => $currentday,
                    "now"         => $timefirst,
                    "prevmonth"   => $prevmonth,
                    "thismonth"   => $timefirst,
                    "nextmonth"   => $nextmonth,
                ));
                break;  // end switch $viewtype minicalendar
            case "byday":  //note aggregates events by groups of days
                // Remember this is the code for weekly view and monthly listview
                // Test your fixes on both views
                //   		$startperiod = 0;
                //			$totaldays = 0;
                switch ($viewrange) {
                    case "day":
                        $startperiod = expDateTime::startOfDayTimestamp($time);
                        $totaldays = 1;
                        $next = expDateTime::endOfDayTimestamp($startperiod);
                        if (!empty($this->config['starttype'])) $startperiod = $time;
                        $this->params['time'] = $time;
                        assign_to_template(array(
                            "prev_timestamp3" => strtotime('-3 days', $startperiod),
                            "prev_timestamp2" => strtotime('-2 days', $startperiod),
                            "prev_timestamp"  => strtotime('-1 days', $startperiod),
                            "next_timestamp"  => strtotime('+1 days', $startperiod),
                            "next_timestamp2" => strtotime('+2 days', $startperiod),
                            "next_timestamp3" => strtotime('+3 days', $startperiod),
                            'params'      => $this->params
                        ));
                        break;
                    case "week":
                        $startperiod = expDateTime::startOfWeekTimestamp($time);
                        $totaldays = 7;
                        $next = strtotime('+7 days', $startperiod);
//                        $next = expDateTime::endOfWeekTimestamp($startperiod);
                        if (!empty($this->config['starttype'])) $startperiod = $time;
                        $this->params['time'] = $time;
                        assign_to_template(array(
                            "prev_timestamp3" => strtotime('-21 days', $startperiod),
                            "prev_timestamp2" => strtotime('-14 days', $startperiod),
                            "prev_timestamp"  => strtotime('-7 days', $startperiod),
                            "next_timestamp"  => $next,
                            "next_timestamp2" => strtotime('+14 days', $startperiod),
                            "next_timestamp3" => strtotime('+21 days', $startperiod),
                            'params'      => $this->params
                        ));
                        break;
                    case "twoweek":
                        $startperiod = expDateTime::startOfWeekTimestamp($time);
                        $totaldays = 14;
                        $next = strtotime('+14 days', $startperiod);
                        if (!empty($this->config['starttype'])) $startperiod = $time;
                        assign_to_template(array(
                            "prev_timestamp3" => strtotime('-42 days', $startperiod),
                            "prev_timestamp2" => strtotime('-28 days', $startperiod),
                            "prev_timestamp"  => strtotime('-14 days', $startperiod),
                            "next_timestamp"  => $next,
                            "next_timestamp2" => strtotime('+28 days', $startperiod),
                            "next_timestamp3" => strtotime('+42 days', $startperiod),
                        ));
                        break;
                    case "month":
                    default: // range = month
                        $startperiod = expDateTime::startOfMonthTimestamp($time);
                        $totaldays = date('t', $time);
                        $next = strtotime('+1 months', $startperiod);
//                        $next = expDateTime::endOfMonthTimestamp($startperiod);
                        $this->params['time'] = $time;
                        assign_to_template(array(
                            "prev_timestamp3" => strtotime('-3 months', $startperiod),
                            "prev_timestamp2" => strtotime('-2 months', $startperiod),
                            "prev_timestamp"  => strtotime('-1 months', $startperiod),
                            "next_timestamp"  => $next,
                            "next_timestamp2" => strtotime('+2 months', $startperiod),
                            "next_timestamp3" => strtotime('+3 months', $startperiod),
                            'params'      => $this->params
                        ));
                        break;
                }  // end switch $viewrange

                //                $days = array();
                // added per Ignacio
                //			$endofmonth = date('t', $time);
                $extitems = $this->getExternalEvents($startperiod, $next);
                if (!empty($this->config['aggregate_registrations']))
                    $regitems = eventregistrationController::getRegEventsForDates($startperiod, $next, $regcolor);
                for ($i = 1; $i <= $totaldays; $i++) {
                    //                    $info = getdate($time);
                    //                    switch ($viewrange) {
                    //                        case "week":
                    //                            $start = mktime(0,0,0,$info['mon'],$i,$info['year']);  //FIXME this can't be right?
                    //                            break;
                    //                        case "twoweek":
                    ////                            $start = mktime(0,0,0,$info['mon'],$info['mday']+($i-1),$info['year']);  //FIXME this can't be right?
                    //                  		    $start = $startperiod + ($i*86400);
                    //                            break;
                    //                        default:  // range = month
                    //                            $start = mktime(0,0,0,$info['mon'],$i,$info['year']);
                    //                    }
                    $start = expDateTime::startOfDayTimestamp($startperiod + ($i * 86400) - 86400);
                    $edates = $ed->find("all", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start));
//                    $days[$start] = $this->getEventsForDates($edates, true, isset($this->config['only_featured']) ? true : false);
                    $days[$start] = $this->event->getEventsForDates($edates, true, isset($this->config['only_featured']) ? true : false);
                    //                    for ($j = 0; $j < count($days[$start]); $j++) {
                    //                        $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$days[$start][$j]->id);
                    //                        $days[$start][$j]->permissions = array(
                    //                            "manage"=>(expPermissions::check("manage",$thisloc) || expPermissions::check("manage",$this->loc)),
                    //                            "edit"=>(expPermissions::check("edit",$thisloc) || expPermissions::check("edit",$this->loc)),
                    //                            "delete"=>(expPermissions::check("delete",$thisloc) || expPermissions::check("delete",$this->loc))
                    //                        );
                    //                    }
                    if (!empty($extitems[$start]))
                        $days[$start] = array_merge($extitems[$start], $days[$start]);
                    if (!empty($regitems[$start]))
                        $days[$start] = array_merge($regitems[$start], $days[$start]);
                    $days[$start] = expSorter::sort(array('array' => $days[$start], 'sortby' => 'eventstart', 'order' => 'ASC'));
                }
                assign_to_template(array(
                    "time" => $startperiod,
                    'days' => $days,
                    "now"  => $startperiod,
                ));
                break;  // end switch $viewtype byday
            case "monthly":  //note this is a simply array of events for the requested month
                // build a month array of weeks with an array of days
                //                $monthly = array();
                //                $counts = array();
                $info = getdate($time);
                $nowinfo = getdate(time());
                if ($info['mon'] != $nowinfo['mon']) $nowinfo['mday'] = -10;
                // Grab non-day numbers only (before end of month)
//                $week = 0;
                $currentweek = -1;
                $timefirst = mktime(0, 0, 0, $info['mon'], 1, $info['year']);
                $week = (int)date('W',$timefirst);
                if ($week >= 52 && $info['mon'] == 1) $week = 1;
                $infofirst = getdate($timefirst);
                $monthly[$week] = array(); // initialize for non days
                $counts[$week] = array();
                if (($infofirst['wday'] == 0) && (DISPLAY_START_OF_WEEK == 1)) {
                    for ($i = -6; $i < (1 - DISPLAY_START_OF_WEEK); $i++) {
                        $monthly[$week][$i] = array();
                        $counts[$week][$i] = -1;
                    }
                    $weekday = $infofirst['wday'] + 7; // day number in grid.  if 7+, switch weeks
                } else {
                    for ($i = 1 - $infofirst['wday']; $i < (1 - DISPLAY_START_OF_WEEK); $i++) {
                        $monthly[$week][$i] = array();
                        $counts[$week][$i] = -1;
                    }
                    $weekday = $infofirst['wday']; // day number in grid.  if 7+, switch weeks
                }
                // Grab day counts
                $endofmonth = date('t', $time);
                $extitems = $this->getExternalEvents($timefirst, expDateTime::endOfMonthTimestamp($timefirst));
                if (!empty($this->config['aggregate_registrations']))
                    $regitems = eventregistrationController::getRegEventsForDates($timefirst, expDateTime::endOfMonthTimestamp($timefirst), $regcolor);
                for ($i = 1; $i <= $endofmonth; $i++) {
                    $start = mktime(0, 0, 0, $info['mon'], $i, $info['year']);
                    if ($i == $nowinfo['mday']) $currentweek = $week;
                    $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start) . ")");
//                    $monthly[$week][$i] = $this->getEventsForDates($dates, true, isset($this->config['only_featured']) ? true : false);
                    $monthly[$week][$i] = $this->event->getEventsForDates($dates, true, isset($this->config['only_featured']) ? true : false);
                    if (!empty($extitems[$start]))
                        $monthly[$week][$i] = array_merge($extitems[$start], $monthly[$week][$i]);
                    if (!empty($regitems[$start]))
                        $monthly[$week][$i] = array_merge($regitems[$start], $monthly[$week][$i]);
                    $monthly[$week][$i] = expSorter::sort(array('array' => $monthly[$week][$i], 'sortby' => 'eventstart', 'order' => 'ASC'));
                    $counts[$week][$i] = count($monthly[$week][$i]);
                    if ($weekday >= (6 + DISPLAY_START_OF_WEEK)) {
                        $week++;
                        $monthly[$week] = array(); // allocate an array for the next week
                        $counts[$week] = array();
                        $weekday = DISPLAY_START_OF_WEEK;
                    } else $weekday++;
                }
                // Grab non-day numbers only (after end of month)
                for ($i = 1; $weekday && $i < (8 + DISPLAY_START_OF_WEEK - $weekday); $i++) {
                    $monthly[$week][$i + $endofmonth] = array();
                    $counts[$week][$i + $endofmonth] = -1;
                }
                $this->params['time'] = $time;
                assign_to_template(array(
                    "currentweek" => $currentweek,
                    "monthly"     => $monthly,
                    "counts"      => $counts,
                    "prevmonth3"  => strtotime('-3 months', $timefirst),
                    "prevmonth2"  => strtotime('-2 months', $timefirst),
                    "prevmonth"   => strtotime('-1 months', $timefirst),
                    "nextmonth"   => strtotime('+1 months', $timefirst),
                    "nextmonth2"  => strtotime('+2 months', $timefirst),
                    "nextmonth3"  => strtotime('+3 months', $timefirst),
                    "now"         => $timefirst,
                    "today"       => expDateTime::startOfDayTimestamp(time()),
                    'params'      => $this->params
                ));
                break;  // end switch $viewtype monthly
            case "administration":  //note a simple list of all upcoming events, except no external nor registration events
                // Check perms and return if cant view
                if (!$user) return;
                $continue = (expPermissions::check("manage", $this->loc) ||
                    expPermissions::check("create", $this->loc) ||
                    expPermissions::check("edit", $this->loc) ||
                    expPermissions::check("delete", $this->loc)
                ) ? 1 : 0;
                $dates = $ed->find("all", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp(time()));
//                $items = $this->getEventsForDates($dates);
                $items = $this->event->getEventsForDates($dates);
                //                if (!$continue) {
                //                    foreach ($items as $i) {
                //                        $iloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$i->id);
                //                        if (expPermissions::check("edit",$iloc) ||
                //                            expPermissions::check("delete",$iloc) ||
                //                            expPermissions::check("manage",$iloc)
                //                        ) {
                //                            $continue = true;
                //                        }
                //                    }
                //                }
                if (!$continue) return;
                //                for ($i = 0; $i < count($items); $i++) {
                //                    $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$items[$i]->id);
                //    //				if ($user && $items[$i]->poster == $user->id) $canviewapproval = 1;
                //                    $items[$i]->permissions = array(
                //                        "manage"=>(expPermissions::check("manage",$thisloc) || expPermissions::check("manage",$this->loc)),
                //                        "edit"=>(expPermissions::check("edit",$thisloc) || expPermissions::check("edit",$this->loc)),
                //                        "delete"=>(expPermissions::check("delete",$thisloc) || expPermissions::check("delete",$this->loc))
                //                    );
                //                }
                $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
                assign_to_template(array(
                    'items' => $items,
                ));
                break;  // end switch $viewtype administration
            case "default":  //note a simple list of events based on $viewrange
            default;
                //                $items = null;
                //                $dates = null;
                $day = expDateTime::startOfDayTimestamp(time());
                $sort_asc = true; // For the getEventsForDates call
                //                $moreevents = false;
                switch ($viewrange) {
                    case "upcoming":  // events in the future
                        if (!empty($this->config['enable_ical']) && !empty($this->config['rss_limit']) && $this->config['rss_limit'] > 0) {
                            $eventlimit = " AND date <= " . ($day + ($this->config['rss_limit'] * 86400));
                        } else {
                            $eventlimit = "";
                        }
                        $dates = $ed->find("all", $locsql . " AND date >= " . $day . $eventlimit . " ORDER BY date ASC ");
                        $begin = $day;
                        $end = null;
                        //					$moreevents = count($dates) < $db->countObjects("eventdate",$locsql." AND date >= $day");
                        break;
                    case "past":  // events in the past
                        $dates = $ed->find("all", $locsql . " AND date < $day ORDER BY date DESC ");
                        //					$moreevents = count($dates) < $db->countObjects("eventdate",$locsql." AND date < $day");
                        $sort_asc = false;
                        $begin = null;
                        $end = $day;
                        break;
                    case "today":  // events occuring today
                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($day) . " AND date <= " . expDateTime::endOfDayTimestamp($day) . ")");
                        $begin = $day;
                        $end = expDateTime::endOfDayTimestamp($day);
                        break;
                    case "day":  // events for a specific day (same as byday day?)
                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($time) . " AND date <= " . expDateTime::endOfDayTimestamp($time) . ")");
                        $begin = expDateTime::startOfDayTimestamp($time);
                        $end = expDateTime::endOfDayTimestamp($time);
                        break;
                    case "next":  // future events
                        $dates = array($ed->find("all", $locsql . " AND date >= $time"));
                        $begin = expDateTime::startOfDayTimestamp($time);
                        $end = null;
                        break;
                    case "month": // events for a specific month (same as monthly?)
//                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp(time()) . " AND date <= " . expDateTime::endOfMonthTimestamp(time()) . ")");
                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp($time) . " AND date <= " . expDateTime::endOfMonthTimestamp($time) . ")");
                        $begin = expDateTime::startOfMonthTimestamp($time);
                        $end = expDateTime::endOfMonthTimestamp($time);
                        break;
                    case "all":  // all events
                    default;
                        $dates = $ed->find("all", $locsql);
                        $begin = null;
                        $end = null;
                }
//                $items = $this->getEventsForDates($dates, $sort_asc, isset($this->config['only_featured']) ? true : false, true);
                $items = $this->event->getEventsForDates($dates, $sort_asc, isset($this->config['only_featured']) ? true : false, true);
                if ($viewrange != 'past') {
                    $extitems = $this->getExternalEvents($begin, $end);
                    // we need to flatten these down to simple array of events
                    $extitem = array();
                    foreach ($extitems as $days) {
                        foreach ($days as $event) {
                            if (empty($event->eventdate->date) || ($viewrange == 'upcoming' && $event->eventdate->date < time()))
                                break;
                            if (empty($event->eventstart))
                                $event->eventstart = $event->eventdate->date;
                            $extitem[] = $event;
                        }
                    }
                    $items = array_merge($items, $extitem);

                    if (!empty($this->config['aggregate_registrations']))
                        $regitems = eventregistrationController::getRegEventsForDates($begin, $end, $regcolor);
                    // we need to flatten these down to simple array of events
                    $regitem = array();
                    if (!empty($regitems)) foreach ($regitems as $days) {
                        foreach ($days as $value) {
                            $regitem[] = $value;
                        }
                    }
                    $items = array_merge($items, $regitem);

                    // remove today's events that have already ended
                    if ($viewtype == 'default' && $viewrange == 'upcoming') {
                        foreach ($items as $key=>$item) {
                            if (!$item->is_allday && $item->eventend < time()) {
                                //fixme we've left events ending earlier in the day, but already cancelled out tomorrow's event
                                unset($items[$key]);
                            } else {
                                break;  // they are chronological so we can end
                            }
                        }
                    }
                }
                $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
                // Upcoming events can be configured to show a specific number of events.
                // The previous call gets all events in the future from today
                // If configured, cut the array to the configured number of events
                //			if ($template->viewconfig['num_events']) {
                //				switch ($viewrange) {
                //					case "upcoming":
                //					case "past":
                //						$moreevents = $template->viewconfig['num_events'] < count($items);
                //						break;
                //				}
                //				$items = array_slice($items, 0, $template->viewconfig['num_events']);
                //			}
                //                for ($i = 0; $i < count($items); $i++) {
                //                    $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$items[$i]->id);
                //                    $items[$i]->permissions = array(
                //                        'manage'=>(expPermissions::check('manage',$thisloc) || expPermissions::check('manage',$this->loc)),
                //                        'edit'=>(expPermissions::check('edit',$thisloc) || expPermissions::check('edit',$this->loc)),
                //                        'delete'=>(expPermissions::check('delete',$thisloc) || expPermissions::check('delete',$this->loc))
                //                    );
                //                }
                assign_to_template(array(
                    'items' => $items,
                    "now"   => $day,
                ));
        }
    }

    /**
     * default view for individual item
     */
    function show() {
        expHistory::set('viewable', $this->params);
        if (!empty($this->params['date_id'])) {  // specific event instance
            $eventdate = new eventdate($this->params['date_id']);
            $eventdate->event = new event($eventdate->event_id);
        } else {  // we'll default to the first event of this series
            $event = new event($this->params['id']);
            $eventdate = new eventdate($event->eventdate[0]->id);
        }
        if (empty($eventdate->id))
            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>'event'));

        if (!empty($eventdate->event->feedback_form) && $eventdate->event->feedback_form != 'Disallow Feedback') {
            assign_to_template(array(
                'feedback_form' => $eventdate->event->feedback_form,
            ));
        }

        assign_to_template(array(
            'event' => $eventdate,
        ));
    }

    function edit() {
        global $template;

        parent::edit();
        $allforms = array();
        $allforms[""] = gt('Disallow Feedback');
        // calculate which event date is the one being edited
        $event_key = 0;
        foreach ($template->tpl->tpl_vars['record']->value->eventdate as $key=>$d) {
       	    if ($d->id == $this->params['date_id']) $event_key = $key;
       	}

        assign_to_template(array(
            'allforms'     => array_merge($allforms, expTemplate::buildNameList("forms", "event/email", "tpl", "[!_]*")),
            'checked_date' => !empty($this->params['date_id']) ? $this->params['date_id'] : null,
            'event_key'    => $event_key,
        ));
    }

    /**
     * Delete a recurring event by asking for which event dates to delete
     *
     */
    function delete_recurring() {
        $item = $this->event->find('first', 'id=' . $this->params['id']);
        if ($item->is_recurring == 1) { // need to give user options
            expHistory::set('editable', $this->params);
            assign_to_template(array(
                'checked_date' => $this->params['date_id'],
                'event'        => $item,
            ));
        } else { // Process a regular delete
            $item->delete();
        }
    }

    /**
     * Delete selected event dates for a recurring event and event if all event dates deleted
     *
     */
    function delete_selected() {
        $item = $this->event->find('first', 'id=' . $this->params['id']);
        if ($item && $item->is_recurring == 1) {
            $event_remaining = false;
            $eventdates = $item->eventdate[0]->find('all', 'event_id=' . $item->id);
            foreach ($eventdates as $ed) {
                if (array_key_exists($ed->id, $this->params['dates'])) {
                    $ed->delete();
                } else {
                    $event_remaining = true;
                }
            }
            if (!$event_remaining) {
                $item->delete(); // model will also ensure we delete all event dates
            }
            expHistory::back();
        } else {
            notfoundController::handle_not_found();
        }
    }

    function delete_all_past() {
        $locsql = $this->aggregateWhereClause();
        $ed = new eventdate();
        $dates = $ed->find("all", $locsql . " AND date < " . strtotime('-1 months', time()));
        foreach ($dates as $date) {
            $date->delete(); // event automatically deleted if all assoc eventdates are deleted
        }
        expHistory::back();
    }

    /**
   	 * get the metainfo for this module
   	 * @return array
   	 */
   	function metainfo() {
       global $router;

        $action = $router->params['action'];
        $metainfo = array('title' => '', 'keywords' => '', 'description' => '', 'canonical'=> '', 'noindex' => false, 'nofollow' => false);
        // look for event date_id which expController::metainfo won't detect
//        if (!empty($router->params['action']) && $router->params['action'] == 'show' && !isset($router->params['id']) && isset($router->params['date_id'])) {
        switch ($action) {
            case 'show':
                if (!isset($router->params['id']) && isset($router->params['date_id'])) {
                    // look up the record.
                    $object = new eventdate((int)$router->params['date_id']);
                    // set the meta info
                    if (!empty($object)) {
                        if (!empty($object->event->body)) {
                            $desc = str_replace('"',"'",expString::summarize($object->event->body,'html','para'));
                        } else {
                            $desc = SITE_DESCRIPTION;
                        }
                        if (!empty($object->expTag)) {
                            $keyw = '';
                            foreach ($object->expTag as $tag) {
                                if (!empty($keyw)) $keyw .= ', ';
                                $keyw .= $tag->title;
                            }
                        } else {
                            $keyw = SITE_KEYWORDS;
                        }
                        $metainfo['title'] = empty($object->event->meta_title) ? $object->event->title : $object->event->meta_title;
                        $metainfo['keywords'] = empty($object->event->meta_keywords) ? $keyw : $object->event->meta_keywords;
                        $metainfo['description'] = empty($object->event->meta_description) ? $desc : $object->event->meta_description;
                        $metainfo['canonical'] = empty($object->event->canonical) ? $router->plainPath() : $object->event->canonical;
                        $metainfo['noindex'] = empty($object->event->meta_noindex) ? false : $object->event->meta_noindex;
                        $metainfo['nofollow'] = empty($object->event->meta_nofollow) ? false : $object->event->meta_nofollow;
                        return $metainfo;
                        break;
                    }
                }
            default:
                return parent::metainfo();
        }
    }

    /**
     * function to build a string to pull in all events within requested date range
     */
    function build_daterange_sql($timestamp, $endtimestamp=null, $field='date', $multiday=false) {
        if (empty($endtimestamp)) {
            $date_sql = "((".$field." >= " . expDateTime::startOfDayTimestamp($timestamp) . " AND ".$field." <= " . expDateTime::endOfDayTimestamp($timestamp) . ")";
        } else {
            $date_sql = "((".$field." >= " . expDateTime::startOfDayTimestamp($timestamp) . " AND ".$field." <= " . expDateTime::endOfDayTimestamp($endtimestamp) . ")";
        }
        if ($multiday)
            $date_sql .= " OR (" . expDateTime::startOfDayTimestamp($timestamp) . " BETWEEN ".$field." AND dateFinished)";
        $date_sql .= ")";
        return $date_sql;
    }

    function send_feedback() {
        $success = false;
        if (isset($this->params['id'])) {
            $ed = new eventdate($this->params['id']);
//            $email_addrs = array();
            if ($ed->event->feedback_email != '') {
                $msgtemplate = expTemplate::get_template_for_action($this, 'email/_' . expString::escape($this->params['formname']), $this->loc);
                $msgtemplate->assign('params', $this->params);
                $msgtemplate->assign('event', $ed);
                $email_addrs = explode(',', $ed->event->feedback_email);
                //This is an easy way to remove duplicates
                $email_addrs = array_flip(array_flip($email_addrs));
                $email_addrs = array_map('trim', $email_addrs);
                $mail = new expMail();
                $success += $mail->quickSend(array(
                    "text_message" => $msgtemplate->render(),
                    'to'           => $email_addrs,
                    'from'         => !empty($this->params['email']) ? $this->params['email'] : trim(SMTP_FROMADDRESS),
                    'subject'      => $this->params['subject'],
                ));
            }
        }

        if ($success) {
            flashAndFlow('message', gt('Your feedback was successfully sent.'));
        } else {
            flashAndFlow('error', gt('We could not send your feedback.  Please contact your administrator.'));
        }
    }

    function ical() {
        if (isset($this->params['date_id']) || isset($this->params['title']) || isset($this->params['src'])) {
            $cfg = new expConfig();
            $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
            foreach ($configs as $config) {
                $loc = expUnserialize($config->location_data);
                if (!empty($this->params['title'])) {
                    if ($this->params['title'] == $config->config['feed_sef_url']) {
                        $this->config = $config->config;
                        break;
                    }
                } elseif (!empty($this->params['src'])) {
                    if ($this->params['src'] == $loc->src) {
                        $this->config = $config->config;
                        break;
                    }
                }
            }
            $this->loc = $loc;

            if ($this->config['enable_ical']) {
                $ed = new eventdate();
                if (isset($this->params['date_id'])) { // get single specific event only
//                    $dates = array($db->selectObject("eventdate","id=".$this->params['date_id']));
                    $dates = $ed->find('first', "id=" . $this->params['date_id']);
                    $Filename = "Event-" . $this->params['date_id'];
                } else {
                    $locsql = $this->aggregateWhereClause();

                    $day = expDateTime::startOfDayTimestamp(time());
                    if (!empty($this->config['enable_ical']) && isset($this->config['rss_limit']) && ($this->config['rss_limit'] > 0)) {
                        $rsslimit = " AND date <= " . ($day + ($this->config['rss_limit'] * 86400));
                    } else {
                        $rsslimit = "";
                    }

                    if (isset($this->params['time'])) {
                        $time = intval($this->params['time']); // get current month's events
//                        $dates = $db->selectObjects("eventdate",$locsql." AND (date >= ".expDateTime::startOfMonthTimestamp($time)." AND date <= ".expDateTime::endOfMonthTimestamp($time).")");
                        $dates = $ed->find('all', $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp($time) . " AND date <= " . expDateTime::endOfMonthTimestamp($time) . ")");
                    } else {
                        $time = date('U', strtotime("midnight -1 month", time())); // previous month also
//                        $dates = $db->selectObjects("eventdate",$locsql." AND date >= ".expDateTime::startOfDayTimestamp($time).$rsslimit);
                        $dates = $ed->find('all', $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($time) . $rsslimit);
                    }
                    //			$title = $db->selectValue('container', 'title', "internal='".serialize($loc)."'");
                    $title = $this->config['feed_title'];
                    $Filename = preg_replace('/\s+/', '', $title); // without whitespace
                }

                if (!function_exists("quoted_printable_encode")) { // function added in php v5.3.0
                    function quoted_printable_encode($input, $line_max = 75) {
                        $hex = array('0', '1', '2', '3', '4', '5', '6', '7',
                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
                        $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
                        $linebreak = "=0D=0A=\r\n";
                        /* the linebreak also counts as characters in the mime_qp_long_line
                         * rule of spam-assassin */
                        $line_max = $line_max - strlen($linebreak);
                        $escape = "=";
                        $output = "";
                        $cur_conv_line = "";
                        $length = 0;
                        $whitespace_pos = 0;
                        $addtl_chars = 0;

                        // iterate lines
                        for ($j = 0, $jMax = count($lines); $j < $jMax; $j++) {
                            $line = $lines[$j];
                            $linlen = strlen($line);

                            // iterate chars
                            for ($i = 0; $i < $linlen; $i++) {
                                $c = substr($line, $i, 1);
                                $dec = ord($c);

                                $length++;

                                if ($dec == 32) {
                                    // space occurring at end of line, need to encode
                                    if (($i == ($linlen - 1))) {
                                        $c = "=20";
                                        $length += 2;
                                    }

                                    $addtl_chars = 0;
                                    $whitespace_pos = $i;
                                } elseif (($dec == 61) || ($dec < 32) || ($dec > 126)) {
                                    $h2 = floor($dec / 16);
                                    $h1 = floor($dec % 16);
                                    $c = $escape . $hex["$h2"] . $hex["$h1"];
                                    $length += 2;
                                    $addtl_chars += 2;
                                }

                                // length for wordwrap exceeded, get a newline into the text
                                if ($length >= $line_max) {
                                    $cur_conv_line .= $c;

                                    // read only up to the whitespace for the current line
                                    $whitesp_diff = $i - $whitespace_pos + $addtl_chars;

                                    /* the text after the whitespace will have to be read
                                     * again ( + any additional characters that came into
                                     * existence as a result of the encoding process after the whitespace)
                                     *
                                     * Also, do not start at 0, if there was *no* whitespace in
                                     * the whole line */
                                    if (($i + $addtl_chars) > $whitesp_diff) {
                                        $output .= substr($cur_conv_line, 0, (strlen($cur_conv_line) -
                                            $whitesp_diff)) . $linebreak;
                                        $i = $i - $whitesp_diff + $addtl_chars;
                                    } else {
                                        $output .= $cur_conv_line . $linebreak;
                                    }

                                    $cur_conv_line = "";
                                    $length = 0;
                                    $whitespace_pos = 0;
                                } else {
                                    // length for wordwrap not reached, continue reading
                                    $cur_conv_line .= $c;
                                }
                            } // end of for

                            $length = 0;
                            $whitespace_pos = 0;
                            $output .= $cur_conv_line;
                            $cur_conv_line = "";

                            if ($j <= count($lines) - 1) {
                                $output .= $linebreak;
                            }
                        } // end for

                        return trim($output);
                    } // end quoted_printable_encode
                }

                $tz = DISPLAY_DEFAULT_TIMEZONE;
                $msg = "BEGIN:VCALENDAR\n";
                $msg .= "VERSION:2.0\n"; // version for iCalendar files vs vCalendar files
                $msg .= "CALSCALE:GREGORIAN\n";
                $msg .= "METHOD: PUBLISH\n";
                $msg .= "PRODID:<-//ExponentCMS//EN>\n";
                if (isset($this->config['rss_cachetime']) && ($this->config['rss_cachetime'] > 0)) {
                    $msg .= "X-PUBLISHED-TTL:PT" . $this->config['rss_cachetime'] . "M\n";
                }
                $msg .= "X-WR-CALNAME:$Filename\n";

//                $items = $this->getEventsForDates($dates);
                $items = $this->event->getEventsForDates($dates);

                for ($i = 0, $iMax = count($items); $i < $iMax; $i++) {

                    // Convert events stored in local time to GMT
                    $eventstart = new DateTime(date('r', $items[$i]->eventstart), new DateTimeZone($tz));
                    $eventstart->setTimezone(new DateTimeZone('GMT'));
                    $eventend = new DateTime(date('r', $items[$i]->eventend), new DateTimeZone($tz));
                    $eventend->setTimezone(new DateTimeZone('GMT'));
                    if ($items[$i]->is_allday) {
                        $dtstart = "DTSTART;VALUE=DATE:" . date("Ymd", $items[$i]->eventstart) . "\n";
                        $dtend = "DTEND;VALUE=DATE:" . date("Ymd", strtotime("midnight +1 day", $items[$i]->eventstart)) . "\n";
                    } else {
                        $dtstart = "DTSTART;VALUE=DATE-TIME:" . $eventstart->format("Ymd\THi00") . "Z\n";
                        if ($items[$i]->eventend) {
                            $dtend = "DTEND;VALUE=DATE-TIME:" . $eventend->format("Ymd\THi00") . "Z\n";
                        } else {
                            $dtend = "DTEND;VALUE=DATE-TIME:" . $eventstart->format("Ymd\THi00") . "Z\n";
                        }
                    }

                    $body = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>", "</p>"), "\n", $items[$i]->body)));
                    if ($items[$i]->is_cancelled) $body = gt('This Event Has Been Cancelled') . ' - ' . $body;
                    $body = str_replace(array("\r"), "", $body);
                    $body = str_replace(array("&#160;"), " ", $body);
                    $body = expString::convertSmartQuotes($body);
                    if (!isset($this->params['style'])) {
                        // it's going to Outlook so remove all formatting from body text
                        $body = quoted_printable_encode($body);
                    } elseif ($this->params['style'] == "g") {
                        // It's going to Google (doesn't like quoted-printable, but likes html breaks)
                        $body = str_replace(array("\n"), "<br />", $body);
                    } else {
                        // It's going elsewhere (doesn't like quoted-printable)
                        $body = str_replace(array("\n"), " -- ", $body);
                    }
                    $title = $items[$i]->title;

                    $msg .= "BEGIN:VEVENT\n";
                    $msg .= $dtstart . $dtend;
                    $msg .= "UID:" . $items[$i]->date_id . "\n";
                    $msg .= "DTSTAMP:" . date("Ymd\THis", time()) . "Z\n";
                    if ($title) {
                        $msg .= "SUMMARY:$title\n";
                    }
                    if ($body) {
                        $msg .= "DESCRIPTION;ENCODING=QUOTED-PRINTABLE:" . $body . "\n";
                    }
                    //	if($link_url) { $msg .= "URL: $link_url\n";}
                    if (!empty($this->config['usecategories'])) {
                        if (!empty($items[$i]->expCat[0]->title)) {
                            $msg .= "CATEGORIES:".$items[$i]->expCat[0]->title."\n";
                        } else {
                            $msg .= "CATEGORIES:".$this->config['uncat']."\n";
                        }
                    }
                    $msg .= "END:VEVENT\n";
                }
                $msg .= "END:VCALENDAR";

                // Kick it out as a file download
                ob_end_clean();

                //	$mime_type = (EXPONENT_USER_BROWSER == 'IE' || EXPONENT_USER_BROWSER == 'OPERA') ? 'application/octet-stream;' : "text/x-vCalendar";
                //	$mime_type = "text/x-vCalendar";
                $mime_type = 'text/Calendar';
                header('Content-Type: ' . $mime_type);
                header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT');
                header('Content-length: ' . strlen($msg));
                header('Content-Transfer-Encoding: binary');
                header('Content-Encoding:');
                //	header("Content-Disposition: inline; filename=".$Filename.".ics");
                header('Content-Disposition: attachment; filename="' . $Filename . '.ics"');
                // IE need specific headers
                //	if (EXPONENT_USER_BROWSER == 'IE') {
                header('Cache-Control: no-cache, must-revalidate');
                header('Pragma: public');
                header('Vary: User-Agent');
                //	} else {
                header('Pragma: no-cache');
                //	}
                echo $msg;
                exit();
            } else {
                notfoundController::handle_not_found();
            }
        } else {
            notfoundController::handle_not_found();
        }
    }

    function send_reminders() {
        if (isset($this->params['title']) || isset($this->params['src'])) {
            $cfg = new expConfig();
            $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
            foreach ($configs as $config) {
                $loc = expUnserialize($config->location_data);
                if (!empty($this->params['title'])) {
                    if ($this->params['title'] == $config->config['feed_sef_url']) {
                        $this->config = $config->config;
                        break;
                    }
                } elseif (!empty($this->params['src'])) {
                    if ($this->params['src'] == $loc->src) {
                        $this->config = $config->config;
                        break;
                    }
                }
            }

            if (empty($this->config['reminder_active'])) {
                notfoundController::handle_not_found();
                return;
            }
            if (!empty($this->config['reminder_code']) && (empty($this->params['code']) || ($this->params['code'] != $this->config['reminder_code']))) {
                notfoundController::handle_not_authorized();
                return;
            }

            $this->loc = $loc;
            $locsql = $this->aggregateWhereClause();

            $view = (isset($this->params['view']) ? $this->params['view'] : '');
            if ($view == "") {
                $view = "send_reminders"; // default reminder view
            }

//            $template = expTemplate::get_template_for_action($this, $view, $this->loc);
            global $template;

            $title = $this->config['feed_title'];
            $template->assign('moduletitle', $title);

            $time = (isset($this->params['time']) ? intval($this->params['time']) : time());
            $time = (int)$time;

            $template->assign("time", $time);

            $startperiod = expDateTime::startOfDayTimestamp($time);
            if (!empty($this->params['days'])) {
                $totaldays = $this->params['days'];
            } else {
                $totaldays = 7; // default 7 days of events
            }

            $count = 0;
            $info = getdate($startperiod);
            for ($i = 0; $i < $totaldays; $i++) {
                $start = mktime(0, 0, 0, $info['mon'], $info['mday'] + $i, $info['year']);
                $ed = new eventdate();
                $edates = $ed->find('all', $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start) . ")");
                $days[$start] = array();
//                $days[$start] = $this->getEventsForDates($edates);
                $days[$start] = $this->event->getEventsForDates($edates);
                for ($j = 0, $jMax = count($days[$start]); $j < $jMax; $j++) {
                    $thisloc = expCore::makeLocation($loc->mod, $loc->src, $days[$start][$j]->id);
                    $days[$start][$j]->permissions = array(
                        "manage" => (expPermissions::check("manage", $thisloc) || expPermissions::check("manage", $loc)),
                        "edit"   => (expPermissions::check("edit", $thisloc) || expPermissions::check("edit", $loc)),
                        "delete" => (expPermissions::check("delete", $thisloc) || expPermissions::check("delete", $loc))
                    );
                }
                $counts[$start] = count($days[$start]);
                $count += count($days[$start]);
                $days[$start] = expSorter::sort(array('array' => $days[$start], 'sortby' => 'eventstart', 'order' => 'ASC'));
            }
            $template->assign("days", $days);
            $template->assign("counts", $counts);
            $template->assign("start", $startperiod);
            $template->assign("totaldays", $totaldays);

            if ($count == 0) {
                flash('error',gt('No Events to Send!'));
                echo show_msg_queue('error');
                return;
            }

            if (bs3())
                $css = file_get_contents(BASE . "external/bootstrap3/css/bootstrap.css");
            elseif (bs2())
                $css = file_get_contents(BASE . "external/bootstrap/css/bootstrap.css");
            else
                $css = file_get_contents(BASE . "framework/modules/events/assets/css/calendar.css");
            $template->assign("css", $css);
            $template->assign("config", $this->config);
            $template->assign("src", $loc->src);

            // format and send email
            $subject = $this->config['email_title_reminder'] . " - $title";
            $from_addr = $this->config['email_address_reminder'];
            $headers = array(
                "From"     => $from = $this->config['email_from_reminder'],
                "Reply-to" => $reply = $this->config['email_reply_reminder']
            );

            // set up the html message
            $template->assign("showdetail", !empty($this->config['email_showdetail']));
            $htmlmsg = $template->render();

            // now the same thing for the text message
            $msg = preg_replace('/(<script[^>]*>.+?<\/script>|<style[^>]*>.+?<\/style>)/s', '', $htmlmsg); // remove any script or style blocks
            $msg = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>"), "\n", $msg)));

            // Saved.  do notifs
            $emails = array();
            if (!empty($this->config['user_list'])) foreach ($this->config['user_list'] as $c) {
                $u = user::getUserById($c);
                $emails[$u->email] = trim(user::getUserAttribution($u->id));
            }
            if (!empty($this->config['group_list'])) foreach ($this->config['group_list'] as $c) {
                $grpusers = group::getUsersInGroup($c);
                foreach ($grpusers as $u) {
                    $emails[$u->email] = trim(user::getUserAttribution($u->id));
                }
            }
            if (!empty($this->config['address_list'])) foreach ($this->config['address_list'] as $c) {
                $emails[] = $c;
            }
            if (empty($emails)) {
                flash('error',gt('No One to Send Reminders to!'));
                echo show_msg_queue('error');
                return;
            }

            $emails = array_flip(array_flip($emails));
            $emails = array_map('trim', $emails);
//            $headers = array(
//                "MIME-Version" => "1.0",
//                "Content-type" => "text/html; charset=" . LANG_CHARSET
//            );
            $mail = new expMail();
            $mail->quickSend(array(
//                'headers'      => $headers,
                'html_message' => $htmlmsg,
                "text_message" => $msg,
                'to'           => $emails,
                'from'         => array(trim($this->config['email_address_reminder']) => $this->config['email_from_reminder']),
                'subject'      => $subject,
            ));

            flash('message',gt('The following reminder was sent via email'));
            echo show_msg_queue();
//            echo($htmlmsg);
        } else {
            flash('error',gt('No Calendar Selected!'));
            echo show_msg_queue('error');
        }
    }

    /** @deprecated moved to event model
     * @param $edates
     * @param bool $sort_asc
     * @param bool $featuredonly
     * @param bool $condense
     * @return array
     */
    function getEventsForDates($edates, $sort_asc = true, $featuredonly = false, $condense = false) {
        global $eventid;

        $events = array();
        $featuresql = "";
        if ($featuredonly) $featuresql = " AND is_featured=1";
        foreach ($edates as $edate) {
            $evs = $this->event->find('all', "id=" . $edate->event_id . $featuresql);
            foreach ($evs as $key=>$event) {
                if ($condense) {
                    $eventid = $event->id;
                    $multiday_event = array_filter($events, create_function('$event', 'global $eventid; return $event->id === $eventid;'));
                    if (!empty($multiday_event)) {
                        unset($evs[$key]);
                        continue;
                    }
                }
                $evs[$key]->eventstart += $edate->date;
                $evs[$key]->eventend += $edate->date;
                $evs[$key]->date_id = $edate->id;
                if (!empty($event->expCat)) {
                    $catcolor = empty($event->expCat[0]->color) ? null : trim($event->expCat[0]->color);
//                    if (substr($catcolor,0,1)=='#') $catcolor = '" style="color:'.$catcolor.';';
                    $evs[$key]->color = $catcolor;
                }
            }
            if (count($events) < 500) {  // magic number to not crash loop?
                $events = array_merge($events, $evs);
            } else {
//                $evs[$key]->title = gt('Too many events to list').', '.(count($edates)-count($events)).' '.gt('not displayed!');
//                $events = array_merge($events, $evs);
                flash('notice',gt('Too many events to list').', '.(count($edates)-count($events)).' '.gt('not displayed!'));
                break; // keep from breaking system by too much data
            }
        }
        $events = expSorter::sort(array('array' => $events, 'sortby' => 'eventstart', 'order' => $sort_asc ? 'ASC' : 'DESC'));
        return $events;
    }

    function getExternalEvents($startdate, $enddate, $multiday = false) {
        global $db;

        $extevents = array();
        $dy = 0;  // index of events array
        if (!empty($this->config['pull_gcal'])) foreach ($this->config['pull_gcal'] as $key=>$extgcalurl) {
//            $dy = count($extevents);  // index of events array
            $cache_hit = false;
            $gcal_cname = str_replace(array("/",":","&","?"),"_",$extgcalurl);
            $cache_fname = BASE.'tmp/cache/'.$gcal_cname.".cache";
            if (file_exists($cache_fname)) {
                $cache = unserialize(file_get_contents($cache_fname));
                if ($startdate >= $cache['start_date'] || $startdate >= $cache['first_date']) {
                    $events = $db->selectObjects('event_cache','feed="'.$extgcalurl.'" AND ' . self::build_daterange_sql($startdate,$enddate,'eventdate',true));
                    foreach ($events as $event) {
                        if ($multiday) {
                            $extevents[$event->eventdate][$dy] = $event;
                            $extevents[$event->eventdate][$dy]->feedkey = $key;
                            $extevents[$event->eventdate][$dy]->location_data = 'gcalevent' . $key;
                            $extevents[$event->eventdate][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
                            if ($event->is_allday) {
                                $extevents[$event->eventdate][$dy]->eventstart = $event->eventdate;
                            }
                            $dy++;
                        } else {
                            $endit = !empty($event->dateFinished) ? $event->dateFinished : $event->eventdate;
//                            for ($i = $startdate; $i < $enddate; $i += 86400) {
                            for ($i = $event->eventdate; $i <= $endit; $i += 86400) {
                                if ((!empty($event->dateFinished) && $i > $event->dateFinished) || (empty($event->dateFinished) && $i > $event->eventdate)) {
                                    break;
                                } else {
                                    $extevents[$i][$dy] = clone($event);
                                    $extevents[$i][$dy]->eventdate = (int)$i;
                                    $extevents[$i][$dy]->eventstart = ($event->eventstart - $event->eventdate);
                                    $extevents[$i][$dy]->eventend = ($event->eventend - (!empty($event->dateFinished)?$event->dateFinished:$event->eventdate));
                                    $extevents[$i][$dy]->eventstart = ($extevents[$i][$dy]->eventstart) + $i;
                                    $extevents[$i][$dy]->eventend = ($extevents[$i][$dy]->eventend) + $i;
                                    $extevents[$i][$dy]->feedkey = $key;
                                    $extevents[$i][$dy]->location_data = 'gcalevent' . $key;
                                    $extevents[$i][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
                                    $dy++;
                                }
                            }
                        }
                    }
                    $cache_hit = true;
                }
            }
            if (!$cache_hit) { // pull in the external events
                foreach ($this->get_gcal_events($extgcalurl, $startdate, $enddate, $dy, $key, $multiday) as $date=>$events) {
                    foreach ($events as $event) {
                        $extevents[$date][] = $event;
                    }
                }
            }
        }
        if (!empty($this->config['pull_ical'])) foreach ($this->config['pull_ical'] as $key=>$exticalurl) {
//            $dy = count($extevents);  // index of events array
            $cache_hit = false;
            $ical_cname = str_replace(array("/",":","&","?"),"_",$exticalurl);
            $cache_fname = BASE.'tmp/cache/'.$ical_cname.".cache";
            if (file_exists($cache_fname)) {
                $cache = unserialize(file_get_contents($cache_fname));
                if ($startdate >= $cache['start_date'] || $startdate >= $cache['first_date']) {
                    $events = $db->selectObjects('event_cache','feed="'.$exticalurl.'" AND ' . self::build_daterange_sql($startdate,$enddate,'eventdate',true));
                    foreach ($events as $event) {
                        $extevents[$event->eventdate][$dy] = $event;
                        $extevents[$event->eventdate][$dy]->location_data = 'icalevent' . $key;
                        $extevents[$event->eventdate][$dy]->color = !empty($this->config['pull_ical_color'][$key]) ? $this->config['pull_ical_color'][$key] : null;
                        $dy++;
                    }
                    $cache_hit = true;
                }
            }
            if (!$cache_hit) {  // pull in the external events
                foreach ($this->get_ical_events($exticalurl, $startdate, $enddate, $dy, $key, $multiday) as $date=>$events) {
                    foreach ($events as $event) {
                        $extevents[$date][] = $event;
                    }
                }
            }
        }
        return $extevents;
    }

    public function get_gcal_events($extgcalurl, $startdate, $enddate=null, &$dy=0, $key=0, $multiday=false) {
        $extevents = array();
        if (!empty($startdate)) $begin = date("Y-m-d\Th:i:sP", expDateTime::startOfDayTimestamp($startdate));
        if (!empty($enddate)) $end = date("Y-m-d\Th:i:sP", expDateTime::endOfDayTimestamp($enddate));
            else $end = date("Y-m-d\Th:i:sP", (expDateTime::endOfDayTimestamp($startdate + ((3600*24)*30))));

        if (substr($extgcalurl, -5) == 'basic') {
            $extgcalurl = substr($extgcalurl, 0, - 5) . 'full';
        }
        $feed = $extgcalurl . "?orderby=starttime&singleevents=true";
        if (!empty($startdate)) $feed .= "&start-min=" . $begin;
        if (!empty($enddate)) $feed .= "&start-max=" . $end;

        // XML method
//            $s = simplexml_load_file($feed);
//            foreach ($s->entry as $item) {
//                $gd = $item->children('http://schemas.google.com/g/2005');
//                if (!empty($gd->when)) {
//                   $dtstart = $gd->when->attributes()->startTime;
//                } elseif (!empty($gd->recurrence)){
//                   $dtstart = $gd->recurrence->when->attributes()->startTime;
//                } else {
//                    $dtstart = $item->attributes()->When;
//                }
//                //FIXME must convert $dtstart timezone
//                $eventdate = expDateTime::startOfDayTimestamp(strtotime($dtstart));
//                $ourtzoffsets = (int)(date('O',$eventdate)) * 36;
//                $theirtzoffset = -((int)(substr($dtstart,-5,2)) * 3600);
//                $tzoffset = $ourtzoffsets - $theirtzoffset;
//                $extevents[$eventdate][$dy] = new stdClass();
//                $extevents[$eventdate][$dy]->eventdate = $eventdate;
//                $extevents[$eventdate][$dy]->eventstart += strtotime($dtstart) + $tzoffset;
//                if (!empty($gd->when)) {
//                    $dtend = $gd->when->attributes()->endTime;
//                } elseif (!empty($gd->recurrence)) {
//                    $dtend = $gd->recurrence->when->attributes()->endTime;
//                }
//                //FIXME must convert $dtend timezone
//                if (!empty($dtend)) $extevents[$eventdate][$dy]->eventend += strtotime($dtend) + $tzoffset;
//                // dtstart required, one occurrence, (orig. start date)
//                $extevents[$eventdate][$dy]->title = $item->title;
//                $extevents[$eventdate][$dy]->body = $item->content;
        // End XML method

        // DOM method
        $doc = new DOMDocument();
        $doc->load($feed);
        $entries = $doc->getElementsByTagName("entry");
        foreach ($entries as $item) {
            $times = $item->getElementsByTagName("when");
            $dtstart = $times->item(0)->getAttributeNode("startTime")->value;
            $eventdate = expDateTime::startOfDayTimestamp(strtotime($dtstart));
            $extevents[$eventdate][$dy] = new stdClass();
            $extevents[$eventdate][$dy]->eventdate = $eventdate;
            $dtend = @$times->item(0)->getAttributeNode("endTime")->value;
            $ourtzoffsets = (int)date('O',$eventdate) * 36;
            $theirtzoffset = -((int)substr($dtstart,-5,2) * 3600);
            $tzoffset = $ourtzoffsets - $theirtzoffset;
            if (strlen($dtstart) > 10) {
                $extevents[$eventdate][$dy]->eventstart = ((int)substr($dtstart, 11, 2) * 3600) + ((int)substr($dtstart, 14, 2) * 60) + $tzoffset;
//                    if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventstart += 3600;
                $extevents[$eventdate][$dy]->eventend = ((int)substr($dtend, 11, 2) * 3600) + ((int)substr($dtend, 14, 2) * 60) + $tzoffset;
//                    if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventend += 3600;
            } else {
                $extevents[$eventdate][$dy]->eventstart = null;
                $extevents[$eventdate][$dy]->is_allday = 1;
            }
            $extevents[$eventdate][$dy]->eventstart += $eventdate;
            $extevents[$eventdate][$dy]->eventend += $eventdate;
            if (empty($dtend)) $extevents[$eventdate][$dy]->eventend = $extevents[$eventdate][$dy]->eventstart;

            $titles = $item->getElementsByTagName("title");
            $extevents[$eventdate][$dy]->title = $titles->item(0)->nodeValue;
            $contents = $item->getElementsByTagName("content");
            $extevents[$eventdate][$dy]->body = $contents->item(0)->nodeValue;
            // End DOM method

//                    $extevents[$eventdate][$dy]->location_data = serialize(expCore::makeLocation('extevent',$extcal->id));
            $extevents[$eventdate][$dy]->location_data = 'gcalevent' . $key;
            $extevents[$eventdate][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
            $dy++;
        }
        return $extevents;
    }

    public function get_ical_events($exticalurl, $startdate=null, $enddate=null, &$dy=0, $key=0, $multiday=false) {
        $extevents = array();
//            require_once BASE . 'external/iCalcreator.class.php';
        require_once BASE . 'external/iCalcreator-2.22/iCalcreator.php';
        $v = new vcalendar(); // initiate new CALENDAR
        if (stripos($exticalurl, 'http') === 0) {
            $v->setConfig('url', $exticalurl);
        } else {
            $v->setConfig('directory', dirname($exticalurl));
            $v->setConfig('filename', basename($exticalurl));
        }
        $v->parse();
        if ($startdate === null) {
            $startYear = false;
            $startMonth = false;
            $startDay = false;
        } else {
            $startYear = date('Y', $startdate);
            $startMonth = date('n', $startdate);
            $startDay = date('j', $startdate);
        }
        if ($enddate === null) {
            $endYear = $startYear+1;
            $endMonth = $startMonth;
            $endDay = $startDay;
        } else {
            $endYear = date('Y', $enddate);
            $endMonth = date('n', $enddate);
            $endDay = date('j', $enddate);
        }
        // get all events within period split out recurring events as single events per each day
        $eventArray = $v->selectComponents($startYear, $startMonth, $startDay, $endYear, $endMonth, $endDay, 'vevent');
        // Set the timezone to GMT
        @date_default_timezone_set('GMT');
        $tzarray = getTimezonesAsDateArrays($v);
        // Set the default timezone
        @date_default_timezone_set(DISPLAY_DEFAULT_TIMEZONE);
        if (!empty($eventArray)) foreach ($eventArray as $year => $yearArray) {
            if (!empty($yearArray)) foreach ($yearArray as $month => $monthArray) {
                if (!empty($monthArray)) foreach ($monthArray as $day => $dailyEventsArray) {
                    if (!empty($dailyEventsArray)) foreach ($dailyEventsArray as $vevent) {
                        // process each event
                        $yesterday = false;
                        $currdate = $vevent->getProperty('x-current-dtstart');
                        $thisday = explode('-', $currdate[1]);
                        $thisday2 = substr($thisday[2], 0, 2);
                        // if member of a recurrence set,
                        // returns array( 'x-current-dtstart', <DATE>)
                        // <DATE> = (string) date("Y-m-d [H:i:s][timezone/UTC offset]")
                        $dtstart = $vevent->getProperty('dtstart', false, true);
                        $dtend = $vevent->getProperty('dtend', false, true);
                        if (empty($dtend))
                            $dtend = $dtstart;

                        // calculate the cumulative timezone offset in seconds to convert to local/system time
                        $tzoffsets = array();
                        $date_tzoffset = 0;
                        if (!empty($tzarray)) {
//                                $ourtzoffsets = -(iCalUtilityFunctions::_tz2offset(date('O',time())));
                            $ourtzoffsets = -(iCalUtilityFunctions::_tz2offset(date('O',self::_date2timestamp($dtstart['value']))));
                            // Set the timezone to GMT
                            @date_default_timezone_set('GMT');
                            if (!empty($dtstart['params']['TZID'])) $tzoffsets = getTzOffsetForDate($tzarray, $dtstart['params']['TZID'], $dtstart['value']);
                            // Set the default timezone
                            @date_default_timezone_set(DISPLAY_DEFAULT_TIMEZONE);
                            if (isset($tzoffsets['offsetSec'])) $date_tzoffset = $ourtzoffsets + $tzoffsets['offsetSec'];
                        }
                        if (empty($tzoffsets)) {
                            $date_tzoffset = -(iCalUtilityFunctions::_tz2offset(date('O',self::_date2timestamp($dtstart['value']))));
                        }
                        //FIXME we must have the real timezone offset for the date by this point

                        //FIXME this is for the google ical feed which is bad!
                        if ($dtstart['value']['day'] != (int)$thisday2 && (isset($dtstart['value']['day']) && isset($dtend['value']['hour']))&&
                            !((int)$dtstart['value']['hour'] == 0 && (int)$dtstart['value']['min'] == 0  && (int)$dtstart['value']['sec'] == 0
                                && (int)$dtend['value']['hour'] == 0 && (int)$dtend['value']['min'] == 0  && (int)$dtend['value']['sec'] == 0
                                && ((((int)$dtstart['value']['day'] - (int)$dtend['value']['day']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -11)))) {
                            $dtst = strtotime($currdate[1]);
                            $dtst1 = iCalUtilityFunctions::_timestamp2date($dtst);
                            $dtstart['value']['year'] = $dtst1['year'];
                            $dtstart['value']['month'] = $dtst1['month'];
                            $dtstart['value']['day'] = $dtst1['day'];
                            $currenddate = $vevent->getProperty('x-current-dtend');
                            $dtet = strtotime($currenddate[1]);
                            $dtet1 = iCalUtilityFunctions::_timestamp2date($dtet);
                            $dtend['value']['year'] = $dtet1['year'];
                            $dtend['value']['month'] = $dtet1['month'];
                            $dtend['value']['day'] = $dtet1['day'];
//                                $date_tzoffset = 0;
                        }

                        if (!empty($dtstart['value']['hour']) && !((int)$dtstart['value']['hour'] == 0 && (int)$dtstart['value']['min'] == 0  && (int)$dtstart['value']['sec'] == 0
                                                            && (int)$dtend['value']['hour'] == 0 && (int)$dtend['value']['min'] == 0  && (int)$dtend['value']['sec'] == 0
                                                            && ((((int)$dtstart['value']['day'] - (int)$dtend['value']['day']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -11)))) {
                            $eventdate = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtstart['value']) - $date_tzoffset);
//                                $eventend = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtend['value']) - $date_tzoffset);
                            $extevents[$eventdate][$dy] = new stdClass();
                            $extevents[$eventdate][$dy]->eventdate = new stdClass();
                            $extevents[$eventdate][$dy]->eventdate->date = $eventdate;
//                                if ((int)($dtstart['value']['hour']) == 0 && (int)($dtstart['value']['min']) == 0  && (int)($dtstart['value']['sec']) == 0
//                                    && (int)($dtend['value']['hour']) == 0 && (int)($dtend['value']['min']) == 0  && (int)($dtend['value']['sec']) == 0
//                                    && ((((int)($dtstart['value']['day']) - (int)($dtend['value']['day'])) == -1) || (((int)($dtstart['value']['month']) - (int)($dtend['value']['month'])) == -1) || (((int)($dtstart['value']['month']) - (int)($dtend['value']['month'])) == -11))) {
////                                    if ($dtstart['value']['day'] != (int)($thisday2)) {
//                                    if (date('d',$eventdate) != $thisday2) {
////                                    if (date('d',$eventdate) != date('d',$eventend)) {
//                                        $yesterday = true;
//                                    } else {
//                                        $extevents[$eventdate][$dy]->eventstart = null;
//                                        $extevents[$eventdate][$dy]->is_allday = 1;
//                                    }
//                                } else {
                                if (date('d',$eventdate) != $thisday2) {
//                                    if (date('d',$eventdate) != date('d',$eventend)) {
                                    $yesterday = true;
                                } else {
                                    $extevents[$eventdate][$dy]->eventstart = ($dtstart['value']['hour'] * 3600) + ($dtstart['value']['min'] * 60) - $date_tzoffset;
//                                        if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventstart += 3600; // adjust for daylight savings time
                                }
//                                }
                        } else {
                            // this is an all day event
                            $eventdate = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtstart['value']));
//                                $eventend = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtend['value']));
                            $extevents[$eventdate][$dy] = new stdClass();
                            $extevents[$eventdate][$dy]->eventdate = new stdClass();
                            $extevents[$eventdate][$dy]->eventdate->date = $eventdate;
//                                if ($dtstart['value']['day'] != (int)($thisday2)) {
                            if (date('d',$eventdate) != $thisday2) {
//                                if (date('d',$eventdate) != date('d',$eventend)) {
                                $yesterday = true;
                            } else {
                                $extevents[$eventdate][$dy]->eventstart = null;
                                $extevents[$eventdate][$dy]->is_allday = 1;
                            }
                        }

                        // set the end time if needed
                        if (!$yesterday && isset($dtend['value']['hour']) && empty($extevents[$eventdate][$dy]->is_allday)) {
//                                if ($dtend['value']['day'] != (int)($thisday2)) {
//                                if ((date('d',$eventend) != $thisday2)) {
//                                    $yesterday = true;
//                                } else {
                            $extevents[$eventdate][$dy]->eventend = ($dtend['value']['hour'] * 3600) + ($dtend['value']['min'] * 60) - $date_tzoffset;
//                                if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventend += 3600; // adjust for daylight savings time
//                                }
                        }

                        // convert the start and end times to a full date
                        if (isset($extevents[$eventdate][$dy]->eventstart) && $extevents[$eventdate][$dy]->eventstart != null)
                            $extevents[$eventdate][$dy]->eventstart += $eventdate;
                        if (isset($extevents[$eventdate][$dy]->eventend))
                            $extevents[$eventdate][$dy]->eventend += $eventdate;

                        // dtstart required, one occurrence, (orig. start date)
                        $extevents[$eventdate][$dy]->title = $vevent->getProperty('summary');
                        $body = $vevent->getProperty('description');
                        // convert end of lines
                        $body = nl2br(str_replace("\\n"," <br>\n",$body));
                        $body = str_replace("\n"," <br>\n",$body);
                        $body = str_replace(array('==0A','=0A','=C2=A0')," <br>\n",$body);
                        $extevents[$eventdate][$dy]->body = $body;
                        $extevents[$eventdate][$dy]->location_data = 'icalevent' . $key;
                        $extevents[$eventdate][$dy]->color = !empty($this->config['pull_ical_color'][$key]) ? $this->config['pull_ical_color'][$key] : null;
                        if (!$yesterday && $eventdate >= $startdate) {
                            $dy++;
                        } else {
                            unset($extevents[$eventdate][$dy]);
                        }
                    }
                }
            }
        }
        return $extevents;
    }

    public static function _date2timestamp( $datetime, $wtz=null ) {
      if( !isset( $datetime['hour'] )) $datetime['hour'] = 0;
      if( !isset( $datetime['min'] ))  $datetime['min']  = 0;
      if( !isset( $datetime['sec'] ))  $datetime['sec']  = 0;
      if( empty( $wtz ) && ( !isset( $datetime['tz'] ) || empty(  $datetime['tz'] )))
        return mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
      $output = $offset = 0;
      if( empty( $wtz )) {
        if( iCalUtilityFunctions::_isOffset( $datetime['tz'] )) {
          $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) * -1;
          $wtz    = 'UTC';
        }
        else
          $wtz    = $datetime['tz'];
      }
      if(( 'Z' == $wtz ) || ( 'GMT' == strtoupper( $wtz )))
        $wtz      = 'UTC';
      try {
        $strdate  = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['min'], $datetime['sec'] );
        $d        = new DateTime( $strdate, new DateTimeZone( $wtz ));
        if( 0    != $offset )  // adjust for offset
          $d->modify( $offset.' seconds' );
        $output   = $d->format( 'U' );
        unset( $d );
      }
      catch( Exception $e ) {
        $output = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
      }
      return $output;
    }

    /**
     * build/update the external event cache
     *
     */
    public function build_cache() {
        global $db;

        // get our requested config
        $cfg = new expConfig();
        $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
        foreach ($configs as $config) {
            $loc = expUnserialize($config->location_data);
            if (!empty($this->params['title'])) {
                if ($this->params['title'] == $config->config['feed_sef_url']) {
                    $this->config = $config->config;
                    break;
                }
            } elseif (!empty($this->params['src'])) {
                if ($this->params['src'] == $loc->src) {
                    $this->config = $config->config;
                    break;
                }
            }
        }

        // next loop through our config pull urls

        // google xml pull
        if (!empty($this->config['pull_gcal'])) foreach ($this->config['pull_gcal'] as $key=>$extgcalurl) {
            $start = expDateTime::startOfMonthTimestamp(time());
            $gcal_cname = str_replace(array("/",":","&","?"),"_",$extgcalurl);
            $cache_fname = BASE.'tmp/cache/'.$gcal_cname.".cache";
            $db->delete('event_cache', "feed='" . $extgcalurl . "' AND eventdate > " . $start);  // replace future events
            // loop through 12 months, 1 month at a time
            for ($i=1; $i < 13; $i++) {
                $end = expDateTime::endOfMonthTimestamp($start);
                $tmp = 0;
                $extevents = $this->get_gcal_events($extgcalurl, $start, $end, $tmp, 0, true);
//                $extevents = $this->get_gcal_events($extgcalurl, null, null, 0, 0, 0, true);
                foreach ($extevents as $day) {
                    foreach ($day as $extevent) {
                        $event_cache = new stdClass();
                        $event_cache->feed = $extgcalurl;
                        $event_cache->event_id = $extevent->event_id;
                        $event_cache->title = $extevent->title;
                        $event_cache->body = $extevent->body;
                        $event_cache->eventdate = $extevent->eventdate->date;
                        if (isset($extevent->dateFinished) && $extevent->dateFinished != -68400)
                            $event_cache->dateFinished = $extevent->dateFinished;
                        if (isset($extevent->eventstart))
                            $event_cache->eventstart = $extevent->eventstart;
                        if (isset($extevent->eventend))
                            $event_cache->eventend = $extevent->eventend;
                        if (isset($extevent->is_allday))
                            $event_cache->is_allday = $extevent->is_allday;
                        $found = false;
                        if ($extevent->eventdate->date < $start)   // prevent duplicating events crossing month boundaries
                            $found = $db->selectObject('event_cache','feed="'.$extgcalurl.'" AND event_id="'.$event_cache->event_id.'" AND eventdate='.$event_cache->eventdate);
                        if (!$found)
                            $db->insertObject($event_cache,'event_cache');
                    }
                }
                $start = expDateTime::startOfMonthTimestamp($end + 1024);
            }
            $cache_contents = serialize(array('start_date'=>$start,'first_date'=>(int)$db->selectValue('event_cache','eventdate','feed="'.$extgcalurl.'" ORDER BY eventdate'),'refresh_date'=>time()));
            file_put_contents($cache_fname, $cache_contents);
        }

        // ical pull
        $start = expDateTime::startOfMonthTimestamp(time());
        if (!empty($this->config['pull_ical'])) foreach ($this->config['pull_ical'] as $key=>$exticalurl) {
            $ical_cname = str_replace(array("/",":","&","?"),"_",$exticalurl);
            $cache_fname = BASE.'tmp/cache/'.$ical_cname.".cache";
            $db->delete('event_cache', "feed='" . $exticalurl . "' AND eventdate > " . $start);
            // get 1 years worth of events
            $extevents = $this->get_ical_events($exticalurl, $start);
            foreach ($extevents as $day) {
                foreach ($day as $extevent) {
                    $event_cache = new stdClass();
                    $event_cache->feed = $exticalurl;
                    $event_cache->title = $extevent->title;
                    $event_cache->body = $extevent->body;
                    $event_cache->eventdate = $extevent->eventdate->date;
                    if (isset($extevent->dateFinished))
                        $event_cache->dateFinished = $extevent->dateFinished;
                    $event_cache->eventstart = $extevent->eventstart;
                    if (isset($extevent->eventend))
                        $event_cache->eventend = $extevent->eventend;
                    if (isset($extevent->is_allday))
                        $event_cache->is_allday = $extevent->is_allday;
                    $db->insertObject($event_cache, 'event_cache');
                }
            }
            $cache_contents = serialize(array('start_date'=>$start,'first_date'=>(int)$db->selectValue('event_cache','eventdate','feed="'.$exticalurl.'" ORDER BY eventdate'),'refresh_date'=>time()));
            file_put_contents($cache_fname, $cache_contents);
        }
        flash('message', gt('External Calendar Event cache updated'));
        echo show_msg_queue();
    }

    function import() {
        $pullable_modules = expModules::listInstalledControllers($this->baseclassname);
        $modules = new expPaginator(array(
            'records' => $pullable_modules,
            'controller' => $this->loc->mod,
            'action' => $this->params['action'],
            'order'   => isset($this->params['order']) ? $this->params['order'] : 'section',
            'dir'     => isset($this->params['dir']) ? $this->params['dir'] : '',
            'page'    => (isset($this->params['page']) ? $this->params['page'] : 1),
            'columns' => array(
                gt('Title') => 'title',
                gt('Page')  => 'section'
            ),
        ));

        assign_to_template(array(
            'modules' => $modules,
        ));
    }

    function import_select()
    {
        if (empty($this->params['import_aggregate'])) {
            expValidator::setErrorField('import_aggregate[]');
            expValidator::failAndReturnToForm(gt('You must select a module.'), $this->params);
        }
        $extevents = array();
        unset(
            $this->params['begin'],
            $this->params['end']
        );  // always use date value
        $begin = yuidatetimecontrol::parseData('begin', $this->params);
        $end = yuidatetimecontrol::parseData('end', $this->params);
        if ($this->params['file_type'] == 'file') {
            //Get the temp directory to put the uploaded file
            $directory = "tmp";

            //Get the file save it to the temp directory
            if (!empty($_FILES["import_file"]) && $_FILES["import_file"]["error"] == UPLOAD_ERR_OK) {
                $file = expFile::fileUpload(
                    "import_file",
                    false,
                    false,
                    time() . "_" . $_FILES['import_file']['name'],
                    $directory . '/'
                );
                if ($file === null) {
                    switch ($_FILES["import_file"]["error"]) {
                        case UPLOAD_ERR_INI_SIZE:
                        case UPLOAD_ERR_FORM_SIZE:
                            $this->params['_formError'] = gt(
                                'The file you attempted to upload is too large.  Contact your system administrator if this is a problem.'
                            );
                            break;
                        case UPLOAD_ERR_PARTIAL:
                            $this->params['_formError'] = gt('The file was only partially uploaded.');
                            break;
                        case UPLOAD_ERR_NO_FILE:
                            $this->params['_formError'] = gt('No file was uploaded.');
                            break;
                        default:
                            $this->params['_formError'] = gt(
                                'A strange internal error has occurred.  Please contact the Exponent Developers.'
                            );
                            break;
                    }
                    expSession::set("last_POST", $this->params);
                    header("Location: " . $_SERVER['HTTP_REFERER']);
                    exit("");
                } else {
                    $extevents = $this->get_ical_events($directory . "/" . $file->filename, $begin, $end);
                }
            } else {
               expValidator::setErrorField('import_file');
               expValidator::failAndReturnToForm(gt('File failed to upload.'), $this->params);  // file upload error
            }
        } else {
            if (empty($this->params['ext_feed'])) {
                expValidator::setErrorField('ext_feed');
                expValidator::failAndReturnToForm(gt('You must enter a feed url.'), $this->params);
            }
            $extevents = $this->get_ical_events($this->params['ext_feed'], $begin, $end);
        }

        $src = $this->params['import_aggregate'][0];
        $count = 0;
        foreach ($extevents as $day) {
            foreach ($day as $extevent) {
                $event = array();
                $event['title'] = $extevent->title;
                $event['body'] = $extevent->body;
                $event['eventdate'] = $extevent->eventdate->date;
                $event['eventstart'] = $extevent->eventstart;
                $event['eventstart'] -= $event['eventdate'];
                if (isset($extevent->eventend))
                    $event['eventend'] = $extevent->eventend;
                else
                    $event['eventend'] = $extevent->eventstart;
                $event['eventend'] -= $event['eventdate'];
                if (isset($extevent->is_allday))
                    $event['is_allday'] = $extevent->is_allday;
                $event['module'] = 'event';
                $event['src'] = $src;
                $item = new event();  // create new populated record to auto-set things
                $item->update($event);
                $count++;
            }
        }

        unlink($directory . "/" . $file->filename);

        // update search index
        $this->addContentToSearch();

        flashAndFlow('message', $count . ' ' . gt('events were imported.'));
    }

    /** @deprecated
     * function to build a control requested via ajax
     * we the html just like the control smarty function
     * @deprecated
     */
    public function buildControl() {
        $control = new colorcontrol();
        if (!empty($this->params['value'])) $control->value = $this->params['value'];
        if ($this->params['value'][0] != '#') $this->params['value'] = '#' . $this->params['value'];
        $control->default = $this->params['value'];
        if (!empty($this->params['hide'])) $control->hide = $this->params['hide'];
        if (isset($this->params['flip'])) $control->flip = $this->params['flip'];
        $this->params['name'] = !empty($this->params['name']) ? $this->params['name'] : '';
        $control->name  = $this->params['name'];
        $this->params['id'] = !empty($this->params['id']) ? $this->params['id'] : '';
        $control->id  = isset($this->params['id']) && $this->params['id'] != "" ? $this->params['id'] : "";
        //echo $control->id;
        if (empty($control->id)) $control->id = $this->params['name'];
        if (empty($control->name)) $control->name = $this->params['id'];

        // attempt to translate the label
        if (!empty($this->params['label'])) {
            $this->params['label'] = gt($this->params['label']);
        } else {
            $this->params['label'] = null;
        }
        echo $control->toHTML($this->params['label'], $this->params['name']);
//        $ar = new expAjaxReply(200, gt('The control was created'), json_encode(array('data'=>$code)));
//        $ar->send();
    }

}

            $order = expString::escape($order);
            if ($limit !== null)
                $limit = intval($limit);
            if ($limitstart !== null)
                $limitstart = intval($limitstart);




//    protected $manage_permissions = array(
//        'picker'=>'Manage Files',
//        'import'=>'Import',
//        'export'=>'Export',
//    );
        'picker'=>'You must be logged in to perform this action',
        'adder'=>'You must be logged in to perform this action',
        'addit'=>'You must be logged in to perform this action',
        'batchDelete'=>'You must be logged in to perform this action',
        'createFolder'=>'You must be logged in to perform this action',
        'deleter'=>'You must be logged in to perform this action',
        'deleteit'=>'You must be logged in to perform this action',
        'edit'=>'You must be logged in to perform this action',
        'quickUpload'=>'You must be logged in to perform this action',
        'upload'=>'You must be logged in to perform this action',
        'uploader'=>'You must be logged in to perform this action',











    }


    }
    }
        global $user;
    }
        // }
        if ($name[0] == '.')  // attempt to upload a dot file
        $name = str_replace('_', '..', $name);  // attempt to upload with redirection to new folder


        $fd = new filedownload(intval($this->params['fileid']));
        }


        parent::downloadfile();

        foreach ($items as $key => $item) {

    protected $add_permissions = array(
        'viewdata'  => "View Data",
        'enter_data' => "Enter Data",  // slight naming variation to not fully restrict enterdata method
    );
    protected $manage_permissions = array(
        'design' => 'Design Form',
    );
                $f = $this->forms->find('first', 'sef_url="' . expString::escape($this->params['title']) . '"');
                    $where = expString::escape($this->params['filter']);
                $f = $this->forms->find('first', 'sef_url="' . expString::escape($this->params['title']) . '"');
                if ($this->config['auto_respond_form'])
                if ($this->config['auto_respond_form'])
        if (!empty($this->params['filename']) && (strpos($this->params['filename'], 'tmp/') === false || strpos($this->params['folder'], '..') !== false)) {
            header('Location: ' . URL_FULL);
            exit();  // attempt to hack the site
        }

        // pagination parameter..hard coded for now.
            $where .= ' AND parent=' . intval($this->params['parent']);
	    $this->params['title'] = expString::escape($this->params['title']);  // escape title to prevent sql injection


	    $where = empty($this->params['version']) ? 1 : 'help_version_id='.intval($this->params['version']);








	    expHistory::back();


	        self::copydocs($current_version->id, $version->id);

        return $db->selectValue('help_version', 'id', 'version="'.$db->escapeString($version).'"');
        return $db->selectValue('help_version', 'version', 'id="'.intval($version_id).'"');
    protected $add_permissions = array(
        'import' => 'Import Data',
        'export' => 'Export Data'
    );
    protected $manage_permissions = array(
        'importProduct' => 'Import Product',
    );
        if (!empty($this->params['filename']) && (strpos($this->params['filename'], 'tmp/') === false || strpos($this->params['folder'], '..') !== false)) {
            header('Location: ' . URL_FULL);
            exit();  // attempt to hack the site
        }

        //eDebug($this->params,true);
        //eDebug($data);
        $source = '';
            $dataset[$value] = '';


            $extAddy = new external_address();
                $extAddy->lastname = $bName[2];
                $extAddy->lastname = '';
                $extAddy->lastname = $bName[1];

            $extAddy->address2 = $data[6];
            $extAddy->address2 = $data[6];
            $extAddy->city = $data[7];

            $extAddy->state = $state->id;
            $extAddy->zip = str_ireplace("'",'',$data[9]);
            $extAddy->phone = $data[20];
            $extAddy->email = $data[21];


                $extAddy->is_shipping = 1;
                $extAddy->save(false);
            {
                $extAddy->is_shipping = 0;
                $extAddy->save(false);

                $extAddy = new external_address();
                    $extAddy->lastname = $sName[2];
                    $extAddy->lastname = '';
                    $extAddy->lastname = $sName[1];

                $extAddy->address2 = $data[15];
                $extAddy->city = $data[16];

                $extAddy->state = $state->id;
                $extAddy->zip = str_ireplace("'",'',$data[18]);
                $extAddy->phone = $data[20];
                $extAddy->email = $data[21];
                $extAddy->source = $source;



        }

        }
    protected $manage_permissions = array(
<?php

##################################################
#
# Copyright (c) 2004-2016 OIC Group, Inc.
#
# This file is part of Exponent
#
# Exponent is free software; you can redistribute
# it and/or modify it under the terms of the GNU
# General Public License as published by the Free
# Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# GPL: http://www.gnu.org/licenses/gpl.txt
#
##################################################
/**
 * @subpackage Controllers
 * @package    Modules
 */
class navigationController extends expController {
    public $basemodel_name = 'section';
    public $useractions = array(
        'showall' => 'Show Navigation',
        'breadcrumb' => 'Breadcrumb',
    );
    protected $remove_permissions = array(
//        'configure',
//        'create',
//        'delete',
//        'edit'
    );
    protected $add_permissions = array(
        'manage'    => 'Manage',
        'view'      => "View Page"
    );
    protected $manage_permissions = array(
        'move'      => 'Move Page',
        'remove'    => 'Remove Page',
        'reparent'    => 'Reparent Page',
    );
    public $remove_configs = array(
        'aggregation',
        'categories',
        'comments',
        'ealerts',
        'facebook',
        'files',
        'pagination',
        'rss',
        'tags',
        'twitter',
    );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)

    static function displayname() { return gt("Navigation"); }

    static function description() { return gt("Places navigation links/menus on the page."); }

    static function isSearchable() { return true; }

    function searchName() { return gt('Webpage'); }

    /**
     * @param null $src
     * @param array $params
     *
     */
    function __construct($src = null, $params = array())
    {
        parent::__construct($src, $params);
        if (!empty($params['id']))  // we normally throw out the $loc->int EXCEPT with navigation pages
            $this->loc = expCore::makeLocation($this->baseclassname, $src, $params['id']);
    }

    public function showall() {
        global $user, $sectionObj, $sections;

        expHistory::set('viewable', $this->params);
        $id      = $sectionObj->id;
        $current = null;
        // all we need to do is determine the current section
        $navsections = $sections;
        if ($sectionObj->parent == -1) {
            $current = $sectionObj;
        } else {
            foreach ($navsections as $section) {
                if ($section->id == $id) {
                    $current = $section;
                    break;
                }
            }
        }
        assign_to_template(array(
            'sections'     => $navsections,
            'current'      => $current,
            'canManage'    => ((isset($user->is_acting_admin) && $user->is_acting_admin == 1) ? 1 : 0),
        ));
    }

    public function breadcrumb() {
        global $sectionObj;

        expHistory::set('viewable', $this->params);
        $id      = $sectionObj->id;
        $current = null;
        // Show not only the location of a page in the hierarchy but also the location of a standalone page
        $current = new section($id);
        if ($current->parent == -1) {  // standalone page
            $navsections = section::levelTemplate(-1, 0);
            foreach ($navsections as $section) {
                if ($section->id == $id) {
                    $current = $section;
                    break;
                }
            }
        } else {
            $navsections = section::levelTemplate(0, 0);
            foreach ($navsections as $section) {
                if ($section->id == $id) {
                    $current = $section;
                    break;
                }
            }
        }
        assign_to_template(array(
            'sections'     => $navsections,
            'current'      => $current,
        ));
    }

    /**
     * @deprecated 2.3.4 moved to section model
     */
    public static function navhierarchy($notyui=false) {
        global $sections;

        $json_array = array();
        for ($i = 0, $iMax = count($sections); $i < $iMax; $i++) {
            if ($sections[$i]->depth == 0) {
                $obj = new stdClass();
//   				$obj->id = $sections[$i]->name.$sections[$i]->id;
                $obj->id   = $sections[$i]->id;
                $obj->text = $sections[$i]->name;
                $obj->title = $sections[$i]->page_title;
                $obj->description = $sections[$i]->description;
                $obj->new_window = $sections[$i]->new_window;
                $obj->expFile = $sections[$i]->expFile;
                $obj->glyph = $sections[$i]->glyph;
                $obj->glyph_only = $sections[$i]->glyph_only;
                $obj->type = $sections[$i]->alias_type;
                if ($sections[$i]->active == 1) {
                    $obj->url = $sections[$i]->link;
                    if ($obj->type == 1 && substr($obj->url, 0, 4) != 'http') {
                        $obj->url = 'http://' . $obj->url;
                    }
                } else {
                    $obj->url     = "#";
                    $obj->onclick = "onclick: { fn: return false }";
                }
                if ($obj->type == 3) {  // mostly a hack instead of adding more table fields
                    $obj->width = $sections[$i]->internal_id;
                    $obj->class = $sections[$i]->external_link;
                }
                /*if ($sections[$i]->active == 1) {
                    $obj->disabled = false;
                } else {
                    $obj->disabled = true;
                }*/
                //$obj->disabled = true;
                $obj->itemdata = self::getChildren($i,$notyui);
                $obj->maxitems = count($obj->itemdata);
                $obj->maxdepth = 0;
                foreach ($obj->itemdata as $menu) {
                    if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
                }
            }
            $json_array[] = $obj;
        }
        return $json_array;
    }

    /**
     * @deprecated 2.3.4 moved to section model
     */
    public static function navtojson() {
        return json_encode(self::navhierarchy());
    }

    /**
     * @deprecated 2.3.4 moved to section model
     */
    public static function getChildren(&$i, $notyui=false) {
        global $sections;

        //		echo "i=".$i."<br>";
        if ($i + 1 == count($sections)) { // last entry
            return array();
        } elseif ($sections[$i]->depth == $sections[$i + 1]->depth) {
            return array();
        } else {
            $ret_depth = $sections[$i]->depth;
            $i++;
            $ret_array = array();
            for ($iMax = count($sections); $i < $iMax; $i++) {
                // start setting up the objects to return
                $obj       = new stdClass();
                $obj->id   = $sections[$i]->id;
                $obj->text = $sections[$i]->name;
                $obj->title = $sections[$i]->page_title;
                $obj->description = $sections[$i]->description;
                $obj->new_window = $sections[$i]->new_window;
                $obj->expFile = $sections[$i]->expFile;
                $obj->glyph = $sections[$i]->glyph;
                $obj->glyph_only = $sections[$i]->glyph_only;
                $obj->depth = $sections[$i]->depth;
                if ($sections[$i]->active == 1) {
                    $obj->url = $sections[$i]->link;
                    if ($sections[$i]->alias_type == 1 && substr($obj->url, 0, 4) != 'http') {
                        $obj->url = 'http://' . $obj->url;
                    }
                } else {
                    $obj->url     = "#";
                    $obj->onclick = "onclick: { fn: return false }";
                }
                //echo "i=".$i."<br>";
                if (self::hasChildren($i)) {
                    if ($notyui) {
                        $obj->itemdata = self::getChildren($i,$notyui);
                        $obj->maxitems = count($obj->itemdata);
                        $obj->maxdepth = 0;
                        foreach ($obj->itemdata as $menu) {
                            if (!empty($menu->maxdepth)) {
                                if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
                            } else {
                                if ($menu->depth > $obj->maxdepth) $obj->maxdepth = $menu->depth;
                            }
                        }
                    } else {
                        $obj->submenu     = new stdClass();
                        $obj->submenu->id = $sections[$i]->name . $sections[$i]->id;
                        //echo "getting children of ".$sections[$i]->name;
                        $obj->submenu->itemdata = self::getChildren($i,$notyui);
                        $obj->maxitems = count($obj->submenu->itemdata);
                        $obj->maxdepth = 0;
                        foreach ($obj->submenu->itemdata as $menu) {
                            if (!empty($menu->maxdepth)) {
                                if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
                            } else {
                                if ($menu->depth > $obj->maxdepth) $obj->maxdepth = $menu->depth;
                            }
                        }
                    }
                    $ret_array[]            = $obj;
                } else {
                    $obj->maxdepth = $obj->depth;
                    $ret_array[] = $obj;
                }
                if (($i + 1) >= count($sections) || $sections[$i + 1]->depth <= $ret_depth) {
                    return $ret_array;
                }
            }
            return array();
        }
    }

    /**
     * @deprecated 2.3.4 moved to section model
     */
    public static function hasChildren($i) {
        global $sections;

        if (($i + 1) >= count($sections)) return false;
        return ($sections[$i]->depth < $sections[$i + 1]->depth) ? true : false;
    }

    /** exdoc
     * Creates a location object, based off of the three arguments passed, and returns it.
     *
     * @return array
     * @deprecated 2.3.4 moved to section model
     */
    public static function initializeNavigation() {
        $sections = section::levelTemplate(0, 0);
        return $sections;
    }

    /**
     * returns all the section's children
     *
     * @static
     *
     * @param int   $parent top level parent id
     * @param int   $depth  variable to hold level of recursion
     * @param array $parents
     *
     * @return array
     * @deprecated 2.3.4 moved to section model
     */
    public static function levelTemplate($parent, $depth = 0, $parents = array()) {
        global $user;

        if ($parent != 0) $parents[] = $parent;
        $nodes = array();
        $cache = expSession::getCacheValue('navigation');
        $sect = new section();
        if (!isset($cache['kids'][$parent])) {
            $kids = $sect->find('all','parent=' . $parent);
            $cache['kids'][$parent] = $kids;
            expSession::setCacheValue('navigation', $cache);
        } else {
            $kids = $cache['kids'][$parent];
        }
        $kids = expSorter::sort(array('array' => $kids, 'sortby' => 'rank', 'order' => 'ASC'));
        for ($i = 0, $iMax = count($kids); $i < $iMax; $i++) {
            $child = $kids[$i];
            //foreach ($kids as $child) {
            if ($child->public == 1 || expPermissions::check('view', expCore::makeLocation('navigation', '', $child->id))) {
                $child->numParents    = count($parents);
                $child->depth         = $depth;
                $child->first         = ($i == 0 ? 1 : 0);
                $child->last          = ($i == count($kids) - 1 ? 1 : 0);
                $child->parents       = $parents;
                $child->canManage     = (isset($user->is_acting_admin) && $user->is_acting_admin == 1 ? 1 : 0);
                $child->canManageRank = $child->canManage;
                if (!isset($child->sef_name)) {
                    $child->sef_name = '';
                }
                // Generate the link attribute base on alias type.
                if ($child->alias_type == 1) {
                    // External link.  Set the link to the configured website URL.
                    // This is guaranteed to be a full URL because of the
                    // section::updateExternalAlias() method in models-1/section.php
                    $child->link = $child->external_link;
                } else if ($child->alias_type == 2) {
                    // Internal link.
                    // Need to check and see if the internal_id is pointing at an external link.
//                    $dest = $db->selectObject('section', 'id=' . $child->internal_id);
                    $dest = $sect->find('first','id=' . $child->internal_id);
                    if (!empty($dest->alias_type) && $dest->alias_type == 1) {
                        // This internal alias is pointing at an external alias.
                        // Use the external_link of the destination section for the link
                        $child->link = $dest->external_link;
                    } else {
                        // Pointing at a regular section.  This is guaranteed to be
                        // a regular section because aliases cannot be turned into sections,
                        // (and vice-versa) and because the section::updateInternalLink
                        // does 'alias to alias' dereferencing before the section is saved
                        // (see models-1/section.php)
                        //added by Tyler to pull the descriptions through for the children view
                        $child->description = !empty($dest->description) ? $dest->description : '';
                        $child->link        = expCore::makeLink(array('section' => $child->internal_id));
                    }
                } else {
                    // Normal link, alias_type == 0.  Just create the URL from the section's id.
                    $child->link = expCore::makeLink(array('section' => $child->id), '', $child->sef_name);
                }
                //$child->numChildren = $db->countObjects('section','parent='.$child->id);
                $nodes[] = $child;
                $nodes   = array_merge($nodes, section::levelTemplate($child->id, $depth + 1, $parents));
            }
        }
        return $nodes;
    }

    /**
     * Returns a flat representation of the full site hierarchy.
     *
     * @param int    $parent         top level parent id
     * @param int    $depth          variable to hold level of recursion
     * @param array  $ignore_ids     array of pages to ignore
     * @param bool   $full           include a 'top' level entry
     * @param string $perm           permission level to build list
     * @param bool   $addstandalones should we add the stand-alone pages also
     * @param bool   $addinternalalias
     *
     * @return array
     * @deprecated 2.3.4 moved to section model, HOWEVER still used in theme config
     */
    public static function levelDropdownControlArray($parent, $depth = 0, $ignore_ids = array(), $full = false, $perm = 'view', $addstandalones = false, $addinternalalias = true) {
        global $db;

        $ar = array();
        if ($parent == 0 && $full) {
            $ar[0] = '&lt;' . gt('Top of Hierarchy') . '&gt;';
        }
        if ($addinternalalias) {
            $intalias = '';
        } else {
            $intalias = ' AND alias_type != 2';
        }
        $nodes = $db->selectObjects('section', 'parent=' . $parent . $intalias, 'rank');
        foreach ($nodes as $node) {
            if ((($perm == 'view' && $node->public == 1) || expPermissions::check($perm, expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
                if ($node->active == 1) {
                    $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . $node->name;
                } else {
                    $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
                }
                $ar[$node->id] = $text;
                foreach (self::levelDropdownControlArray($node->id, $depth + 1, $ignore_ids, $full, $perm, $addstandalones, $addinternalalias) as $id => $text) {
                    $ar[$id] = $text;
                }
            }
        }
        if ($addstandalones && $parent == 0) {
            $sections = $db->selectObjects('section', 'parent=-1');
            foreach ($sections as $node) {
                if ((($perm == 'view' && $node->public == 1) || expPermissions::check($perm, expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
                    if ($node->active == 1) {
                        $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . $node->name;
                    } else {
                        $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
                    }
                    $ar[$node->id] = '(' . gt('Standalone') . ') ' . $text;
                }
            }
//            $ar = array_merge($ar,$sections);
        }
        return $ar;
    }

    /**
     * add all module items to search index
     *
     * @return int
     */
    function addContentToSearch() {
        global $db;

        //global $sections;
        //		global $router;
//        $db->delete('search', "ref_module='navigation' AND ref_type='section'");
        $db->delete('search', "ref_module='".$this->baseclassname."' AND ref_type='section'");
        // this now ensures we get internal pages, instead of relying on the global $sections, which does not.
        $sections = $db->selectObjects('section', 'active=1');
        foreach ($sections as $section) {
            $search_record = new stdClass();
//            $search_record->category = 'Webpages';
//            $search_record->ref_module = 'navigationController';
//            $search_record->ref_type = 'section';
//            $search_record->ref_module  = $this->classname;
            $search_record->ref_module  = $this->baseclassname;
            $search_record->category    = $this->searchName();
            $search_record->ref_type    = $this->searchCategory();
            $search_record->original_id = $section->id;
            $search_record->title       = $section->name;
            //$search_record->view_link = $router->buildUrlByPageId($section->id);
            $link = str_replace(URL_FULL, '', makeLink(array('section' => $section->id)));
            if ($link . '/' == URL_FULL) $link = '';
            $search_record->view_link = $link;
            $search_record->body      = $section->description;
            $search_record->keywords  = $section->keywords;
            // now we're going to grab all the textmodules on this page and build the body for the page based off the content
            // of all the text module added together.
            $loc = expCore::makeLocation('text');
            $controllername = 'text';
            foreach ($db->selectObjects('sectionref', "module='" . $controllername . "' AND section=" . $section->id) as $module) {
                $loc->src   = $module->source;
//                $controller = new $controllername();
                $controller = expModules::getController($controllername);
                $textitems  = $db->selectObjects($controller->model_table, "location_data='" . serialize($loc) . "'");
                foreach ($textitems as $textitem) {
                    if (!empty($textitem)) {
                        $search_record->body .= ' ' . search::removeHTML($textitem->body) . ' ';
                        $search_record->keywords .= " " . $textitem->title;
                    }
                }
            }
            $db->insertObject($search_record, 'search');
        }
        return count($sections);
    }

    /**
     * Retrieve either the entire hierarchy, or a subset of the hierarchy, as an array suitable for use
     * in a dropdowncontrol.  This is used primarily by the section datatype for moving and adding
     * sections to specific parts of the site hierarchy.
     *
     * @param int   $parent     The id of the subtree parent.  If passed as 0 (the default), the entire subtree is parsed.
     * @param int   $depth
     * @param int   $default
     * @param array $ignore_ids a value-array of IDs to be ignored when generating the list.  This is used
     *                          when moving a section, since a section cannot be made a subsection of itself or any of its subsections.
     *
     * @return string
     */
    function levelShowDropdown($parent, $depth = 0, $default = 0, $ignore_ids = array()) {
        global $db;

        $html = '';
        $nodes = $db->selectObjects('section', 'parent=' . $parent, 'rank');
//		$nodes = expSorter::sort(array('array'=>$nodes,'sortby'=>'rank', 'order'=>'ASC'));
        foreach ($nodes as $node) {
            if (($node->public == 1 || expPermissions::check('view', expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
                $html .= '<option value="' . $node->id . '" ';
                if ($default == $node->id) $html .= 'selected';
                $html .= '>';
                if ($node->active == 1) {
                    $html .= str_pad('', $depth * 3, '.', STR_PAD_LEFT) . $node->name;
                } else {
                    $html .= str_pad('', $depth * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
                }
                $html .= '</option>';
                $html .= self::levelShowDropdown($node->id, $depth + 1, $default, $ignore_ids);
            }
        }
        return $html;
    }

    /**
     * recursively lists the template hierarchy
     *
     * @static
     *
     * @param int $parent top level parent id
     * @param int $depth  variable to hold level of recursion
     *
     * @return array
     * @deprecated 2.0.0 this only for deprecated templates
     */
    public static function getTemplateHierarchyFlat($parent, $depth = 1) {
        global $db;

        $arr  = array();
        $kids = $db->selectObjects('section_template', 'parent=' . $parent, 'rank');
//		$kids = expSorter::sort(array('array'=>$kids,'sortby'=>'rank', 'order'=>'ASC'));
        for ($i = 0, $iMax = count($kids); $i < $iMax; $i++) {
            $page        = $kids[$i];
            $page->depth = $depth;
            $page->first = ($i == 0 ? 1 : 0);
            $page->last  = ($i == count($kids) - 1 ? 1 : 0);
            $arr[]       = $page;
            $arr         = array_merge($arr, self::getTemplateHierarchyFlat($page->id, $depth + 1));
        }
        return $arr;
    }

    /**
     * @deprecated 2.0.0 this only for deprecated templates
     */
    public static function process_section($section, $template) {
        global $db;

        if (!is_object($template)) {
            $template          = $db->selectObject('section_template', 'id=' . $template);
            $section->subtheme = $template->subtheme;
            $db->updateObject($section, 'section');
        }
        $prefix = '@st' . $template->id;
        $refs   = $db->selectObjects('sectionref', "source LIKE '$prefix%'");
        // Copy all modules and content for this section
        foreach ($refs as $ref) {
            $src = substr($ref->source, strlen($prefix)) . $section->id;
            if (call_user_func(array($ref->module, 'hasContent'))) {
                $oloc = expCore::makeLocation($ref->module, $ref->source);
                $nloc = expCore::makeLocation($ref->module, $src);
                if ($ref->module != "container") {
                    call_user_func(array($ref->module, 'copyContent'), $oloc, $nloc);
                } else {
                    call_user_func(array($ref->module, 'copyContent'), $oloc, $nloc, $section->id);
                }
            }
        }
        // Grab sub pages
        foreach ($db->selectObjects('section_template', 'parent=' . $template->id) as $t) {
            self::process_subsections($section, $t);
        }

    }

    /**
     * @deprecated 2.0.0 this only for deprecated templates
     */
    function process_subsections($parent_section, $subtpl) {
        global $db, $router;

        $section              = new stdClass();
        $section->parent      = $parent_section->id;
        $section->name        = $subtpl->name;
        $section->sef_name    = $router->encode($section->name);
        $section->subtheme    = $subtpl->subtheme;
        $section->active      = $subtpl->active;
        $section->public      = $subtpl->public;
        $section->rank        = $subtpl->rank;
        $section->page_title  = $subtpl->page_title;
        $section->keywords    = $subtpl->keywords;
        $section->description = $subtpl->description;
        $section->id          = $db->insertObject($section, 'section');
        self::process_section($section, $subtpl);
    }

    /**
     * Delete page and send its contents to the recycle bin
     *
     * @param $parent
     * @deprecated 2.3.4 moved to section model
     */
    public static function deleteLevel($parent) {
        global $db;

        $kids = $db->selectObjects('section', 'parent=' . $parent);
        foreach ($kids as $kid) {
            self::deleteLevel($kid->id);
        }
        $secrefs = $db->selectObjects('sectionref', 'section=' . $parent);
        foreach ($secrefs as $secref) {
            $loc = expCore::makeLocation($secref->module, $secref->source, $secref->internal);
            recyclebin::sendToRecycleBin($loc, $parent);
            //FIXME if we delete the module & sectionref the module completely disappears
//            if (class_exists($secref->module)) {
//                $modclass = $secref->module;
//                //FIXME: more module/controller glue code
//                if (expModules::controllerExists($modclass)) {
//                    $modclass = expModules::getControllerClassName($modclass);
//                    $mod = new $modclass($loc->src);
//                    $mod->delete_instance();
//                } else {
//                    $mod = new $modclass();
//                    $mod->deleteIn($loc);
//                }
//            }
        }
//        $db->delete('sectionref', 'section=' . $parent);
        $db->delete('section', 'parent=' . $parent);
    }

    /**
     * Move content page and its children to stand-alones
     *
     * @param $parent
     * @deprecated 2.3.4 moved to section model
     */
    public static function removeLevel($parent) {
        global $db;

        $kids = $db->selectObjects('section', 'parent=' . $parent);
        foreach ($kids as $kid) {
            $kid->parent = -1;
            $db->updateObject($kid, 'section');
            self::removeLevel($kid->id);
        }
    }

    /**
     * Check for cascading page view permission, esp. if not public
     * @deprecated 2.3.4 moved to section model
     */
    public static function canView($section) {
        global $db;

        if ($section == null) {
            return false;
        }
        if ($section->public == 0) {
            // Not a public section.  Check permissions.
            return expPermissions::check('view', expCore::makeLocation('navigation', '', $section->id));
        } else { // Is public.  check parents.
            if ($section->parent <= 0) {
                // Out of parents, and since we are still checking, we haven't hit a private section.
                return true;
            } else {
                $s = $db->selectObject('section', 'id=' . $section->parent);
                return self::canView($s);
            }
        }
    }

    /**
     * Check to see if page is public with cascading
     * @deprecated 2.3.4 moved to section model
     */
    public static function isPublic($s) {
        if ($s == null) {
            return false;
        }
        while ($s->public && $s->parent > 0) {
            $s = new section($s->parent);
        }
        $lineage = (($s->public) ? 1 : 0);
        return $lineage;
    }

    public static function canManageStandalones() {
        global $user;

        if ($user->isAdmin()) return true;
        $standalones = section::levelTemplate(-1, 0);
        //		$canmanage = false;
        foreach ($standalones as $standalone) {
            $loc = expCore::makeLocation('navigation', '', $standalone->id);
            if (expPermissions::check('manage', $loc)) return true;
        }
        return false;
    }

    /**
     * Reassign permissions based on a check/change in menu/page hierarchy
     *
     * @static
     *
     * @param $id
     */
    public static function checkForSectionalAdmins($id) {
        global $db;

        $section = $db->selectObject('section', 'id=' . $id);
        $branch  = section::levelTemplate($id, 0);
        array_unshift($branch, $section);
        $allusers  = array();
        $allgroups = array();
        while ($section->parent > 0) {
            //			$ploc = expCore::makeLocation('navigationController', null, $section);
            $allusers  = array_merge($allusers, $db->selectColumn('userpermission', 'uid', "permission='manage' AND module='navigation' AND internal=" . $section->parent));
            $allgroups = array_merge($allgroups, $db->selectColumn('grouppermission', 'gid', "permission='manage' AND module='navigation' AND internal=" . $section->parent));
            $section   = $db->selectObject('section', 'id=' . $section->parent);
        }
        foreach ($branch as $section) {
            $sloc = expCore::makeLocation('navigation', null, $section->id);
            // remove any manage permissions for this page and it's children
            // $db->delete('userpermission', "module='navigationController' AND internal=".$section->id);
            // $db->delete('grouppermission', "module='navigationController' AND internal=".$section->id);
            foreach ($allusers as $uid) {
                $u = user::getUserById($uid);
                expPermissions::grant($u, 'manage', $sloc);
            }
            foreach ($allgroups as $gid) {
                $g = group::getGroupById($gid);
                expPermissions::grantGroup($g, 'manage', $sloc);
            }
        }
    }

    function manage() {
        global $db, $router, $user;

        expHistory::set('manageable', $router->params);
        assign_to_template(array(
            'canManageStandalones' => self::canManageStandalones(),
            'sasections'           => $db->selectObjects('section', 'parent=-1'),
            'user'                 => $user,
//            'canManagePagesets'    => $user->isAdmin(),
//            'templates'            => $db->selectObjects('section_template', 'parent=0'),
        ));
    }

    public function manage_sitemap() {
        global $db, $user, $sectionObj, $sections;

        expHistory::set('viewable', $this->params);
        $id      = $sectionObj->id;
        $current = null;
        // all we need to do is determine the current section
        $navsections = $sections;
        if ($sectionObj->parent == -1) {
            $current = $sectionObj;
        } else {
            foreach ($navsections as $section) {
                if ($section->id == $id) {
                    $current = $section;
                    break;
                }
            }
        }
        assign_to_template(array(
            'sasections'   => $db->selectObjects('section', 'parent=-1'),
            'sections'     => $navsections,
            'current'      => $current,
            'canManage'    => ((isset($user->is_acting_admin) && $user->is_acting_admin == 1) ? 1 : 0),
        ));
    }

    /**
     * Ajax request for specific pages as json date to yui tree
     */
    public static function returnChildrenAsJSON() {
        global $db;

        //$nav = section::levelTemplate(intval($_REQUEST['id'], 0));
        $id         = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
        $nav        = $db->selectObjects('section', 'parent=' . $id, 'rank');
        //FIXME $manage_all is moot w/ cascading perms now?
        $manage_all = false;
        if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $id))) {
            $manage_all = true;
        }
        //FIXME recode to use foreach $key=>$value
        $navcount = count($nav);
        for ($i = 0; $i < $navcount; $i++) {
            if ($manage_all || expPermissions::check('manage', expCore::makeLocation('navigation', '', $nav[$i]->id))) {
                $nav[$i]->manage = 1;
                $view = true;
            } else {
                $nav[$i]->manage = 0;
                $view = $nav[$i]->public ? true : expPermissions::check('view', expCore::makeLocation('navigation', '', $nav[$i]->id));
            }
            $nav[$i]->link = expCore::makeLink(array('section' => $nav[$i]->id), '', $nav[$i]->sef_name);
            if (!$view) unset($nav[$i]);
        }
        $nav= array_values($nav);
//        $nav[$navcount - 1]->last = true;
        if (count($nav)) $nav[count($nav) - 1]->last = true;
//        echo expJavascript::ajaxReply(201, '', $nav);
        $ar = new expAjaxReply(201, '', $nav);
        $ar->send();
    }

    /**
     * Ajax request for all pages as json date to jstree
     */
    public static function returnChildrenAsJSON2() {
        global $db;

        $icons = array(
            0 => 'addpage',
            1 => 'addextpage',
            2 => 'addintpage',
            3 => 'addfreeform',
        );

        $navs        = $db->selectObjects('section', 'parent!=-1', 'rank');
        foreach ($navs as $i=>$nav) {
            $navs[$i]->parent = $nav->parent?$nav->parent:'#';
            $navs[$i]->text = $nav->name;
            $navs[$i]->icon = $icons[$nav->alias_type];
            if (!$nav->active) {
                $navs[$i]->icon .= ' inactive';
                $attr = new stdClass();
                $attr->class = 'inactive';  // class to obscure elements
                $navs[$i]->a_attr = $attr;
            }
            if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $navs[$i]->id))) {
                $navs[$i]->manage = 1;
                $view = true;
            } else {
                $navs[$i]->manage = 0;
                $navs[$i]->state->disabled = true;
                $view = $navs[$i]->public ? true : expPermissions::check('view', expCore::makeLocation('navigation', '', $navs[$i]->id));
            }
            $navs[$i]->link = expCore::makeLink(array('section' => $navs[$i]->id), '', $navs[$i]->sef_name);
            if (!$view) {
//                unset($navs[$i]);  //FIXME this breaks jstree if we remove a parent and not the child
                $attr = new stdClass();
                $attr->class = 'hidden';  // bs3 class to hide elements
                $navs[$i]->li_attr = $attr;
            }
        }
        $navs= array_values($navs);
//        header('Content-Type: application/json; charset=utf8');
		echo json_encode($navs);
//        echo expJavascript::ajaxReply(201, '', $navs);
        exit;
    }

    /**
     * Ajax function to reorder page hierarchy from yui tree control
     */
    public static function DragnDropReRank() {
        global $db, $router;

        $move   = $router->params['move'];
        $target = $router->params['target'];
        $type   = $router->params['type'];
        $targSec = $db->selectObject("section","id=".$target);
//        $targSec  = new section($target);
        $check_id = $targSec->parent;
        $moveSec = $db->selectObject("section","id=".$move);
//        $moveSec = new section($move);

        // dropped on top of page
        if ($type == "append") {
            //save the old parent in case we are changing the depth of the moving section
            $oldParent = $moveSec->parent;
            //assign the parent of the moving section to the ID of the target section
            $moveSec->parent = $targSec->id;
            //set the rank of the moving section to 0 since it will appear first in the new order
            $moveSec->rank = 1;
            //select all children currently of the parent we're about to append to
            $targSecChildren = $db->selectObjects("section", "parent=" . $targSec->id . " ORDER BY rank");
            //update the ranks of the children to +1 higher to accommodate our new rank 0 section being moved in.
            $newrank = 1;
            foreach ($targSecChildren as $value) {
                if ($value->id != $moveSec->id) {
                    $value->rank = $newrank;
                    $db->updateObject($value, 'section');
                    $newrank++;
                }
            }
            $db->updateObject($moveSec, 'section');
            if ($oldParent != $moveSec->parent) {
                //we need to re-rank the children of the parent that the miving section has just left
                $childOfLastMove = $db->selectObjects("section", "parent=" . $oldParent . " ORDER BY rank");
                for ($i = 0, $iMax = count($childOfLastMove); $i < $iMax; $i++) {
                    $childOfLastMove[$i]->rank = $i;
                    $db->updateObject($childOfLastMove[$i], 'section');
                }

            }
//            echo $moveSec->name . " was appended to " . $targSec->name;

        } elseif ($type == "after") {  // dropped between (after) pages
            if ($targSec->parent == $moveSec->parent) {
                //are we moving up...
                if ($targSec->rank < $moveSec->rank) {
                    $moveSec->rank    = $targSec->rank + 1;
                    $moveNextSiblings = $db->selectObjects("section", "id!=" . $moveSec->id . " AND parent=" . $targSec->parent . " AND rank>" . $targSec->rank . " ORDER BY rank");
                    $rerank           = $moveSec->rank + 1;
                    foreach ($moveNextSiblings as $value) {
                        if ($value->id != $moveSec->id) {
                            $value->rank = $rerank;
                            $db->updateObject($value, 'section');
                            $rerank++;
                        }
                    }
                    $db->updateObject($targSec, 'section');
//                    $targSec->update();
                    $db->updateObject($moveSec, 'section');
//                    $moveSec->update();
                    //or are we moving down...
                } else {
                    $targSec->rank        = $targSec->rank - 1;
                    $moveSec->rank        = $targSec->rank + 1;
                    $movePreviousSiblings = $db->selectObjects("section", "id!=" . $moveSec->id . " AND parent=" . $targSec->parent . " AND rank<=" . $targSec->rank . " ORDER BY rank");
                    $rerank               = 1;
                    foreach ($movePreviousSiblings as $value) {
                        if ($value->id != $moveSec->id) {
                            $value->rank = $rerank;
                            $db->updateObject($value, 'section');
                            $rerank++;
                        }
                    }
                    $db->updateObject($targSec, 'section');
//                    $targSec->update();
                    $db->updateObject($moveSec, 'section');
//                    $moveSec->update();
                }
            } else {  // 'before', is this used?
                //store ranks from the depth we're moving from.  Used to re-rank the level depth the moving section is moving from.
                $oldRank   = $moveSec->rank;
                $oldParent = $moveSec->parent;
                //select all children of the target sections parent with a rank higher than it's own
                $moveNextSiblings = $db->selectObjects("section", "parent=" . $targSec->parent . " AND rank>" . $targSec->rank . " ORDER BY rank");
                //update moving sections rank and parent
                $moveSec->rank   = $targSec->rank + 1;
                $moveSec->parent = $targSec->parent;
                //$rerank=$moveSec->rank+1;
                foreach ($moveNextSiblings as $value) {
                    $value->rank = $value->rank + 1;
                    $db->updateObject($value, 'section');
                }
                $db->updateObject($moveSec, 'section');
                //handle re-ranking of previous parent
                $oldSiblings = $db->selectObjects("section", "parent=" . $oldParent . " AND rank>" . $oldRank . " ORDER BY rank");
                $rerank      = 1;
                foreach ($oldSiblings as $value) {
                    if ($value->id != $moveSec->id) {
                        $value->rank = $rerank;
                        $db->updateObject($value, 'section');
                        $rerank++;
                    }
                }
                if ($oldParent != $moveSec->parent) {
                    //we need to re-rank the children of the parent that the moving section has just left
                    $childOfLastMove = $db->selectObjects("section", "parent=" . $oldParent . " ORDER BY rank");
                    for ($i = 0, $iMax = count($childOfLastMove); $i < $iMax; $i++) {
                        $childOfLastMove[$i]->rank = $i;
                        $db->updateObject($childOfLastMove[$i], 'section');
                    }
                }
            }
        }
        self::checkForSectionalAdmins($move);
        expSession::clearAllUsersSessionCache('navigation');
    }

    /**
     * Ajax function to reorder page hierarchy from jstree control
     */
    public static function DragnDropReRank2() {
        global $router, $db;

        $id = $router->params['id'];
        $page = new section($id);
        $old_rank = $page->rank;
        $old_parent = $page->parent;
        $new_rank = $router->params['position'] + 1;  // rank
        $new_parent = intval($router->params['parent']);

        $db->decrement($page->tablename, 'rank', 1, 'rank>' . $old_rank . ' AND parent=' . $old_parent);  // close in hole
        $db->increment($page->tablename, 'rank', 1, 'rank>=' . $new_rank . ' AND parent=' . $new_parent);  // make room

        $params = array();
        $params['parent'] = $new_parent;
        $params['rank'] = $new_rank;
        $page->update($params);

        self::checkForSectionalAdmins($id);
        expSession::clearAllUsersSessionCache('navigation');
    }

    function edit_section() {
        global $db, $user;

        $parent = new section($this->params['parent']);
        if (empty($parent->id)) $parent->id = 0;
        assign_to_template(array(
            'haveStandalone'  => ($db->countObjects('section', 'parent=-1') && $parent->id >= 0),
            'parent'          => $parent,
            'isAdministrator' => $user->isAdmin(),
        ));
    }

    function edit_contentpage() {
        //FIXME we come here for new/edit content/standalone pages
        // FIXME: Allow non-administrative users to manage certain parts of the section hierarchy.
        //if ($user->is_acting_admin == 1 /*TODO: section admin*/) {
//        $section = null;
        $section = new stdClass();
        if (isset($this->params['id'])) {
            // Check to see if an id was passed in get.  If so, retrieve that section from
            // the database, and perform an edit on it.
            $section  = $this->section->find($this->params['id']);
        } elseif (isset($this->params['parent'])) {
            // The isset check is merely a precaution.  This action should
            // ALWAYS be invoked with a parent or id value.
            $section  = new section($this->params);
        } else {
            notfoundController::handle_not_found();
            exit;
        }
        if (!empty($section->id)) {
            $check_id = $section->id;
        } else {
            $check_id = $section->parent;
        }
        if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $check_id))) {
            if (empty($section->id)) {
                $section->active = 1;
                $section->public = 1;
                if (!isset($section->parent)) {
                    // This is another precaution.  The parent attribute
                    // should ALWAYS be set by the caller.
                    //FJD - if that's the case, then we should die.
                    notfoundController::handle_not_authorized();
                    exit;
                    //$section->parent = 0;
                }
            }
            assign_to_template(array(
                'section' => $section,
                'glyphs' => self::get_glyphs(),
            ));
        } else {  // User does not have permission to manage sections.  Throw a 403
            notfoundController::handle_not_authorized();
        }
    }

    private static function get_glyphs() {
        if (bs()) {
            require_once(BASE . 'external/font-awesome.class.php');
            $fa = new Smk_FontAwesome;
            if (bs3()) {
                $icons = $fa->getArray(BASE . 'external/font-awesome4/css/font-awesome.css');
                $icons = $fa->sortByName($icons);
                return $fa->nameGlyph($icons);
            } elseif (bs2()) {
                expCSS::auto_compile_less(
                    'external/font-awesome/less/font-awesome.less',
                    'external/font-awesome/css/font-awesome.css'
                ); // font-awesome is included within bootstrap2, but not as a separate .css file
                $icons = $fa->getArray(BASE . 'external/font-awesome/css/font-awesome.css', 'icon-');
                return $fa->nameGlyph($icons, 'icon-');
            }
        } else {
            return array();
        }
    }

    function edit_internalalias() {
        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
        if ($section->parent == -1) {
            notfoundController::handle_not_found();
            exit;
        } // doesn't work for standalone pages
        if (empty($section->id)) {
            $section->public = 1;
            if (!isset($section->parent)) {
                // This is another precaution.  The parent attribute
                // should ALWAYS be set by the caller.
                //FJD - if that's the case, then we should die.
                notfoundController::handle_not_authorized();
                exit;
                //$section->parent = 0;
            }
        }
        assign_to_template(array(
            'section' => $section,
            'glyphs' => self::get_glyphs(),
        ));
    }

    function edit_freeform() {
        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
        if ($section->parent == -1) {
            notfoundController::handle_not_found();
            exit;
        } // doesn't work for standalone pages
        if (empty($section->id)) {
            $section->public = 1;
            if (!isset($section->parent)) {
                // This is another precaution.  The parent attribute
                // should ALWAYS be set by the caller.
                //FJD - if that's the case, then we should die.
                notfoundController::handle_not_authorized();
                exit;
                //$section->parent = 0;
            }
        }
        assign_to_template(array(
            'section' => $section,
            'glyphs' => self::get_glyphs(),
        ));
    }

    function edit_externalalias() {
        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
        if ($section->parent == -1) {
            notfoundController::handle_not_found();
            exit;
        } // doesn't work for standalone pages
        if (empty($section->id)) {
            $section->public = 1;
            if (!isset($section->parent)) {
                // This is another precaution.  The parent attribute
                // should ALWAYS be set by the caller.
                //FJD - if that's the case, then we should die.
                notfoundController::handle_not_authorized();
                exit;
                //$section->parent = 0;
            }
        }
        assign_to_template(array(
            'section' => $section,
            'glyphs' => self::get_glyphs(),
        ));
    }

    function update() {
        parent::update();
        expSession::clearAllUsersSessionCache('navigation');
    }

    function move_standalone() {
        expSession::clearAllUsersSessionCache('navigation');
        assign_to_template(array(
            'parent' => $this->params['parent'],
        ));
    }

    /**
     * Move standalone back to hierarchy
     *
     */
    function reparent_standalone() {
        $standalone = $this->section->find($this->params['page']);
        if ($standalone) {
            $standalone->parent = $this->params['parent'];
            $standalone->update();
            expSession::clearAllUsersSessionCache('navigation');
            expHistory::back();
        } else {
            notfoundController::handle_not_found();
        }
    }

    /**
     * Move content page to standalones
     *
     */
    function remove() {
        global $db;

        $section = $db->selectObject('section', 'id=' . $this->params['id']);
        if ($section) {
            section::removeLevel($section->id);
            $db->decrement('section', 'rank', 1, 'rank > ' . $section->rank . ' AND parent=' . $section->parent);
            $section->parent = -1;
            $db->updateObject($section, 'section');
            expSession::clearAllUsersSessionCache('navigation');
            expHistory::back();
        } else {
            notfoundController::handle_not_authorized();
        }
    }

    function delete_standalones() {
        if (!empty($this->params['deleteit'])) {
            foreach ($this->params['deleteit'] as $page) {
                $section = new section(intval($page));
                if ($section) {
//                    self::deleteLevel($section->id);
                    $section->delete();
                }
            }
        }
        expSession::clearAllUsersSessionCache('navigation');
        expHistory::back();
    }

    /**
     * permission functions to aggregate a module's visible permissions based on add/remove permissions
     *
     * @return array
     */
    public function permissions() {
        //set the permissions array
        return $this->add_permissions;
    }

    // create a psuedo global manage pages permission
    public static function checkPermissions($permission,$location) {
        global $exponent_permissions_r, $router;

        // only applies to the 'manage' method
        if (empty($location->src) && empty($location->int) && ((!empty($router->params['action']) && $router->params['action'] == 'manage') || strpos($router->current_url, 'action=manage') !== false)) {
            if (!empty($exponent_permissions_r['navigation'])) foreach ($exponent_permissions_r['navigation'] as $page) {
                foreach ($page as $pageperm) {
                    if (!empty($pageperm['manage'])) return true;
                }
            }
        }
        return false;
    }

    /**
     * Rebuild the sectionref table as a list of modules on a page
     * @deprecated 2.3.4 moved to sectionref model
     */
    public static function rebuild_sectionrefs() {
        global $db;

        // recursive run though all the nested containers
        function scan_container($container_id, $page_id) {
            global $db;

            $containers = $db->selectObjects('container',"external='" . $container_id . "'");
            $ret = '';
            foreach ($containers as $container) {
                $iLoc = expUnserialize($container->internal);
                $newret = recyclebin::restoreFromRecycleBin($iLoc, $page_id);
                if (!empty($newret)) $ret .= $newret . '<br>';
                if ($iLoc->mod == 'container') {
                    $ret .= scan_container($container->internal, $page_id);
                }
            }
            return $ret;
        }

        // recursive run through all the nested pages
        function scan_page($parent_id) {
            global $db;

            $sections = $db->selectObjects('section','parent=' . $parent_id);
            $ret = '';
            foreach ($sections as $page) {
                $cLoc = serialize(expCore::makeLocation('container','@section' . $page->id));
                $ret .= scan_container($cLoc, $page->id);
                $ret .= scan_page($page->id);
            }
            return $ret;
        }

        // first remove duplicate records
        $db->sql('DELETE FROM ' . $db->prefix . 'sectionref WHERE id NOT IN (SELECT * FROM (SELECT MIN(n.id) FROM ' . $db->prefix . 'sectionref n GROUP BY n.module, n.source) x)');
        $ret = scan_page(0);  // the page hierarchy
        $ret .= scan_page(-1);  // now the stand alone pages

        // we need to get the non-main containers such as sidebars, footers, etc...
        $hardcodedmods = $db->selectObjects('sectionref',"refcount=1000 AND source NOT LIKE '%@section%' AND source NOT LIKE '%@random%'");
        foreach ($hardcodedmods as $hardcodedmod) {
            if ($hardcodedmod->module == 'container') {
                $page_id = intval(preg_replace('/\D/', '', $hardcodedmod->source));
                if (empty($page_id)) {
                    $page_id = SITE_DEFAULT_SECTION;  // we'll default to the home page
                }
                $ret .= scan_container(serialize(expCore::makeLocation($hardcodedmod->module, $hardcodedmod->source)), $page_id);
            } else {
                $hardcodedmod->section = 0;  // this is a hard-coded non-container module
                $db->updateObject($hardcodedmod, 'sectionref');
            }
        }

        // mark modules in the recycle bin as section 0
        $db->columnUpdate('sectionref', 'section', 0, "refcount=0");
//        $recycledmods = $db->selectObjects('sectionref',"refcount=0");
//        foreach ($recycledmods as $recycledmod) {
//            $recycledmod->section = 0;  // this is a module in the recycle bin
//            $db->updateObject($recycledmod, 'sectionref');
//        }
        return $ret;
    }

}

?>
    protected $add_permissions = array(
        'showUnpublished'=>'View Unpublished News',
        'showExpired'=>'View Unpublished News',
    );
    protected $manage_permissions = array(
        'import'=>'Import News Items',
        'export'=>'Export News Items'
    );
        }


            $id = expString::escape($this->params['title']);





    public function saveconfig() {

        parent::saveconfig();

        foreach ($items as $key => $item) {
        if (!empty($this->config['pull_rss'])) {
    protected $manage_permissions = array(
        'multi'=>'Bulk Actions',
    );




            $id = expString::escape($this->params['title']);




    }

        'editor'=>'You must be logged in to perform this action',
        'exitEditor'=>'You must be logged in to perform this action',


        $canSaveOg = $user->id==$file->poster || $user->isSuperAdmin() ? 1 : 0 ;
	    if (file_exists(BASE . $file->directory . $file->filename)) {
			$file->copyToDirectory(BASE . $this->cacheDir);
		    flash('error', gt('The file') . ' "' . BASE . $file->directory . $file->filename . '" ' . gt('does not exist on the server.'));
		    redirect_to(array("controller"=>'file', "action"=>'picker', "ajax_action"=>1, "update"=>$this->params['update'], "filter"=>$this->params['filter']));

                $oldimage = new expFile($this->params['fid']);
                $copyname = expFile::resolveDuplicateFilename($oldimage->path);
                copy(BASE . $this->cacheDir . "/" . $this->params['cpi'], $oldimage->directory . $copyname); //copy the edited file over to the files dir
                $newFile->filesize = filesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
                $resized = getimagesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
                $resized = getimagesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
                copy(BASE . $this->cacheDir . "/" . $this->params['cpi'], $oldimage->directory . $oldimage->filename); //copy the edited file over to the files dir

        $types = array(".jpg", ".gif", ".png");

        $cachedir = BASE . $this->cacheDir;

                if (in_array(substr($tmpfile, -4, 4), $types)) {
                    $filename = $cachedir . $tmpfile;

        redirect_to(array("controller"=>'file', "action"=>'picker', "ajax_action"=>1, "update"=>$this->params['update'], "filter"=>$this->params['filter']));

?>
    protected $manage_permissions = array(
        'import'=>'Import Portfolio Items',
        'export'=>'Export Portfolio Items'
    );
    protected $manage_permissions = array(
        $this->params['mod'] = expString::escape($this->params['mod']);
        $this->params['src'] = expString::escape($this->params['src']);
    protected $manage_permissions = array(
        'abandoned_carts' => 'Abandoned Carts Report',
        'batch_export' => 'Export Products',
        'current_carts' => 'Current Carts Report',
        'download' => 'Download Report',
        'order_report' => 'Generate Order Report',
        'payment_report' => 'Generate Payment Report',
        'product_report' => 'Generate Product Report',
        'purge_abandoned_carts' => 'Purge Abandoned Carts',
        'status_export' => 'Export Status',
    );
            [date-startdate] =>
            [time-h-startdate] =>
            [time-m-startdate] =>
            [date-enddate] =>
            [time-h-enddate] =>
            [time-m-enddate] =>
            [order-range-num] =>
            [order-price-num] =>
            [pnam] =>
            [sku] =>
            [blshpname] =>
            [email] =>
            [zip] =>
        //$items = $prod->find('all', 1, 'id DESC',25);
        //$items = $order->find('all', 1, 'id DESC',25);
        $geos = $geo->find('all');
        //eDebug(strftime("%A, %d %B %Y", mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y"))));
        //build
            //get each calculator's id
            [date-startdate] =>
            [time-h-startdate] =>
            [time-m-startdate] =>
            [date-enddate] =>
            [time-h-enddate] =>
            [time-m-enddate] =>
            [order-range-num] =>
            [order-price-num] =>
            [pnam] =>
            [sku] =>
            [blshpname] =>
            [email] =>
            [zip] =>
        //$items = $prod->find('all', 1, 'id DESC',25);
        //$items = $order->find('all', 1, 'id DESC',25);
        //eDebug($sql . $sqlwhere);
        //strftime("%a %d-%m-%Y", get_first_day(3, 1, 2007)); Thursday, 1 April 2010
            //$line = expString::outputField("SMC Inventory - Laurie");
        //$items = $product->find('all', '', 'id', 25);
        //$page = new expPaginator();
        //eDebug($page,true);
                'Invoice #'=>'invoice_id',
        //
        //
        // assign_to_template(array('page'=>$page));
        //echo "1<br>"; eDebug($str);
            //if HTML, then leave the single quotes alone, otheriwse replace w/ special Char
        //$str = str_replace(",","\,",$str);
            * description
            * id - SKU
            * link
            * price
            * title
            * brand - manufacturer
            * image link - fullsized image, up to 10, comma seperated
            * product type - category - "Electronics > Audio > Audio Accessories MP3 Player Accessories","Health & Beauty > Healthcare > Biometric Monitors > Pedometers"
        $allOrderCount = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend,null,null,null,true,false,$except,true);



        $ordersInCheckout = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend . " AND user_id != 0",null,null,null,true,false,$except,true);

        //$ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend . " AND user_id != 0 AND order_type_id = 1",null,null,null,true,false,$except,true);
        //$ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend . " AND user_id != 0",null,null,null,true,false,$except,true);
        $ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);
        $orders = $this->o->find('all','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);

        eDebug("All:" . $allOrderCount);
        eDebug("Carts w/ Items:" . $allCartsWithItems);
        eDebug("Carts w/ Items in Checkout:" . $ordersInCheckout);
        eDebug("Purchased:" . $ordersPurchased);





        assign_to_template(array('prev_month'=>$this->prev_month, 'now_date'=>$this->now_date, 'now_hour'=>$this->now_hour, 'now_min'=>$this->now_min, 'now_ampm'=>$this->now_ampm, 'prev_hour'=>$this->prev_hour, 'prev_min'=>$this->prev_min, 'prev_ampm'=>$this->prev_ampm));
        /*OPTIONALLY ENCLOSED BY '" . '"' .
        /*OPTIONALLY ENCLOSED BY '" . '"' .
    protected $manage_permissions = array(
        'spider'=>'Spider Site',
        'searchQueryReport'=>'Search Query Report',
        'topSearchReport'=>'Top Search Report',


























            $answer = new simplepoll_answer(intval($this->params['choice']));
		user::login(expString::escape(expString::sanitize($_POST['username'])),expString::escape(expString::sanitize($_POST['password'])));
//    protected $remove_permissions = array(
//        'create',
//        'edit'
//    );
    protected $manage_permissions = array(
        'update'           => 'Update Users',
        // if this is a new user account we need to check the password.
        // if this is a new account then we will check to see if we need to send
        $this->params['username'] = expString::escape($this->params['username']);
        $tok = $db->selectObject('passreset_token', 'uid=' . intval($this->params['uid']) . " AND token='" . preg_replace('/[^A-Za-z0-9]/', '', expString::escape($this->params['token'])) . "'");
        $u = new user(intval($this->params['uid']));
        global $user;

        if (!$user->isAdmin() && $this->params['id'] != $user->id) {
            flash('error', gt('You do not have permissions to change this users password.'));
            expHistory::back();
        }

        if (!empty($this->params['filename']) && (strpos($this->params['filename'], 'tmp/') === false || strpos($this->params['folder'], '..') !== false)) {
            header('Location: ' . URL_FULL);
            exit();  // attempt to hack the site
        }