diff --git a/WHATSNEW.md b/WHATSNEW.md new file mode 100644 index 0000000000000000000000000000000000000000..522bc605e475837fe6c321c75a57d2fe086880dd --- /dev/null +++ b/WHATSNEW.md @@ -0,0 +1,73 @@ +New stuff in 1.7-dpr2 +====================== + +Features +-------- + * Autocomplete for ticket search box (emails and ticket numbers typeahead) + * Redesigned staff login page + * Warning when leaving unsaved changes in admin and staff settings pages + * Auto change admin settings pages when selecting a new page from the + drop-down list + * Create a ticket in one click from the staff panel + * Preview ticket from the search results + * Export tickets to CSV file + +Issues +------ + * (#1) Automatically cleanup orphaned attachments + * (#2) Reject ticket creation when a matching email filter has + 'Reject email' set + * (#3) Ticket search results are properly paginated + * (#4) Make email filters editable + * (#5) Add .htaccess for API URLs rewrites + * (#6) Add utf-8 content type declaration for installer HTML output + * (#8) Fix installer for PHP settings with 'register_globals' enabled + +Outstanding +----------- + * Implement the dashboard reports + * Advanced search form for ticket searches + * Multi-file upload for responses, notes, and new tickets + * PDF export for ticket thread + * Misc. improvements + +New Features in 1.7 +=================== +Version 1.7 includes several new features + +Email Filters +------------- +As an upgrade from email banning (which is still supported), email filters +allow for matching incoming email in the subject line and message body. For +matching emails, the administrator has the ability to automatically route +tickets: + + * To a specific department, staff member, and/or team + * Automatically assign ticket priority and/or service-level-agreement + * Disable ticket auto-responses + +Canned Attachments +------------------ +Attach files to your canned responses. These attachments are automatically +attached to the ticket thread along with the canned response. The +attachments are not duplicated in the database and therefore use virtually +no space. + +Service Level Agreements +------------------------ +Service level agreements allow for a configurable grace period based on the +department or help topic associated with the ticket. A default SLA is +provided, and a due date can be set to override the grace period of the SLA +for a ticket. + +Client-side Knowledgebase +------------------------- +Manage a searchable help document portal for your users + +API +--- +Interface with osTicket via HTTP requests. Starting with version 1.7, +tickets are createable by submitting an HTTP POST request to either + + /api/tickets.xml + /api/tickets.json diff --git a/api/.htaccess b/api/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..e230ac6e186f66ada37cca3809396e32b98473e1 --- /dev/null +++ b/api/.htaccess @@ -0,0 +1,9 @@ +Options +FollowSymLinks +RewriteEngine On + +RewriteBase /api/ + +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d + +RewriteRule ^(.*)$ http.php/$1 [L] diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css index dde40189e88227edaa3f1c18e4aec6b7e1bb67db..c6a6242df3d461805e06d366f451d3abf34a29ff 100644 --- a/assets/default/css/theme.css +++ b/assets/default/css/theme.css @@ -495,7 +495,7 @@ body { #ticketForm div.error label, #clientLogin div.error label { color: #a00; } -#ticketForm p, #clientLogin p { +#clientLogin p { clear: both; text-align: center; } @@ -646,7 +646,7 @@ a.refresh { #ticketThread table th { text-align: left; border-bottom: 1px solid #aaa; - font-size: 11pt; + font-size: 12px; padding: 5px; } #ticketThread table td { @@ -659,7 +659,7 @@ a.refresh { background: #ddd; } #ticketThread .info { - padding: 5px; + padding: 2px; background: #f9f9f9; border-top: 1px solid #ddd; height: 16px; @@ -667,16 +667,13 @@ a.refresh { } #ticketThread .info a { display: inline-block; - margin: 5px 20px 5px 0; + margin: 5px 10px 5px 0; padding-left: 24px; height: 16px; line-height: 16px; background-position: 0 50%; background-repeat: no-repeat; } -#ticketThread .info .pdf { - background-image: url('../images/filetypes/pdf.png?1319636863'); -} #reply { margin-top: 20px; diff --git a/attachment.php b/attachment.php new file mode 100644 index 0000000000000000000000000000000000000000..819ff5863b559522f70a65fd1c2fc56846e37d8a --- /dev/null +++ b/attachment.php @@ -0,0 +1,36 @@ +<?php +/********************************************************************* + attachment.php + + Attachments interface for clients. + Clients should never see the dir paths. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require('secure.inc.php'); +require_once(INCLUDE_DIR.'class.attachment.php'); +//Basic checks +if(!$thisclient + || !$_GET['id'] + || !$_GET['h'] + || !($attachment=Attachment::lookup($_GET['id'])) + || !($file=$attachment->getFile())) + die('Unknown attachment!'); + +//Validate session access hash - we want to make sure the link is FRESH! and the user has access to the parent ticket!! +$vhash=md5($attachment->getFileId().session_id().$file->getHash()); +if(strcasecmp(trim($_GET['h']),$vhash) + || !($ticket=$attachment->getTicket()) + || !$ticket->checkClientAccess($thisclient)) + die('Unknown or invalid attachment'); +//Download the file.. +$file->download(); + +?> diff --git a/captcha.php b/captcha.php new file mode 100644 index 0000000000000000000000000000000000000000..3ab68f746ddb378da077cac80b616caf6f69b129 --- /dev/null +++ b/captcha.php @@ -0,0 +1,20 @@ +<?php +/********************************************************************* + captcha.php + + Simply returns captcha image. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require_once('main.inc.php'); +require(INCLUDE_DIR.'class.captcha.php'); +$captcha = new Captcha(5,12,ROOT_DIR.'images/captcha/'); +echo $captcha->getImage(); +?> diff --git a/client.inc.php b/client.inc.php index 5461bd2f75246f57b710f74312eb45b9c4cfba9a..b714e93b44bd587f4d10a2f292b2d4890bc63a3f 100644 --- a/client.inc.php +++ b/client.inc.php @@ -51,7 +51,7 @@ require_once(INCLUDE_DIR.'class.dept.php'); //clear some vars $errors=array(); $msg=''; -$thisclient=null; +$thisclient=$nav=null; //Make sure the user is valid..before doing anything else. if($_SESSION['_client']['userID'] && $_SESSION['_client']['key']) $thisclient = new ClientSession($_SESSION['_client']['userID'],$_SESSION['_client']['key']); @@ -60,6 +60,8 @@ if($_SESSION['_client']['userID'] && $_SESSION['_client']['key']) if($thisclient && $thisclient->getId() && $thisclient->isValid()){ $thisclient->refreshSession(); } +/* Client specific defaults */ +define('PAGE_LIMIT',DEFAULT_PAGE_LIMIT); $nav = new UserNav($thisclient, 'home'); ?> diff --git a/images/bg.gif b/images/bg.gif deleted file mode 100644 index e20f31775822d9b0a7a01ddaf38cb1f48a60e6f2..0000000000000000000000000000000000000000 Binary files a/images/bg.gif and /dev/null differ diff --git a/images/fibres.png b/images/fibres.png deleted file mode 100644 index 7ad3ac27f71bdf17f637ffae3d86d36e24359764..0000000000000000000000000000000000000000 Binary files a/images/fibres.png and /dev/null differ diff --git a/images/home.gif b/images/home.gif deleted file mode 100644 index b25c0781dd0b8f66d4a9271b662061b54d7a9c4d..0000000000000000000000000000000000000000 Binary files a/images/home.gif and /dev/null differ diff --git a/images/icons/attachment.gif b/images/icons/attachment.gif deleted file mode 100644 index 4400e61e9812a3b2a070c89fc6fce7489c104e17..0000000000000000000000000000000000000000 Binary files a/images/icons/attachment.gif and /dev/null differ diff --git a/images/icons/refresh.gif b/images/icons/refresh.gif deleted file mode 100644 index 8268958a19e016741fffb8309b1174e548f5ce19..0000000000000000000000000000000000000000 Binary files a/images/icons/refresh.gif and /dev/null differ diff --git a/images/icons/thread.gif b/images/icons/thread.gif deleted file mode 100644 index bffd6b0b3cf5ce0cadfc38683ee7fb3fa0a5c82a..0000000000000000000000000000000000000000 Binary files a/images/icons/thread.gif and /dev/null differ diff --git a/images/icons/ticket.gif b/images/icons/ticket.gif deleted file mode 100644 index 4304ea7955091c46d9fe570faefc643773a5c1de..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket.gif and /dev/null differ diff --git a/images/icons/ticket_source_email.gif b/images/icons/ticket_source_email.gif deleted file mode 100644 index 6b57605d47b7fc2e4729b5a6602bdf4768ad749f..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket_source_email.gif and /dev/null differ diff --git a/images/icons/ticket_source_other.gif b/images/icons/ticket_source_other.gif deleted file mode 100644 index 4304ea7955091c46d9fe570faefc643773a5c1de..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket_source_other.gif and /dev/null differ diff --git a/images/icons/ticket_source_phone.gif b/images/icons/ticket_source_phone.gif deleted file mode 100644 index b9aa8ed58a2993eab69a1c83fba78bb627e9004f..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket_source_phone.gif and /dev/null differ diff --git a/images/icons/ticket_source_web.gif b/images/icons/ticket_source_web.gif deleted file mode 100644 index 1b7a5b909075fb879056d15468e407df21e0507d..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket_source_web.gif and /dev/null differ diff --git a/images/lipsum.png b/images/lipsum.png deleted file mode 100644 index feb6a95fba027cb3d54883fc64ade1294c74bd09..0000000000000000000000000000000000000000 Binary files a/images/lipsum.png and /dev/null differ diff --git a/images/logo.png b/images/logo.png deleted file mode 100644 index 256344139522f7f8bc65b36e1ef0890e0fa3cf52..0000000000000000000000000000000000000000 Binary files a/images/logo.png and /dev/null differ diff --git a/images/logo2.jpg b/images/logo2.jpg deleted file mode 100644 index 16bc12ed36e707ace9d2d9e5443cc6d3a895711b..0000000000000000000000000000000000000000 Binary files a/images/logo2.jpg and /dev/null differ diff --git a/images/logout.gif b/images/logout.gif deleted file mode 100644 index 6dd774f09e48292379250ac0f1be17ccdb30baec..0000000000000000000000000000000000000000 Binary files a/images/logout.gif and /dev/null differ diff --git a/images/my_tickets.gif b/images/my_tickets.gif deleted file mode 100644 index ee2d25bbedd01ba5a64e9a66f5fc72b7b876f10c..0000000000000000000000000000000000000000 Binary files a/images/my_tickets.gif and /dev/null differ diff --git a/images/new_ticket.gif b/images/new_ticket.gif deleted file mode 100644 index 32d9636e71fa848c3b7d0f0d8eb559b78465ef22..0000000000000000000000000000000000000000 Binary files a/images/new_ticket.gif and /dev/null differ diff --git a/images/new_ticket_icon.jpg b/images/new_ticket_icon.jpg deleted file mode 100644 index 855eef0644245185b7b2f700d35d6a953aa65cd1..0000000000000000000000000000000000000000 Binary files a/images/new_ticket_icon.jpg and /dev/null differ diff --git a/images/poweredby.jpg b/images/poweredby.jpg deleted file mode 100644 index c98eb7d679b09975599711643cfcd3549c0540f6..0000000000000000000000000000000000000000 Binary files a/images/poweredby.jpg and /dev/null differ diff --git a/images/rainbow.png b/images/rainbow.png deleted file mode 100644 index c08f52edb522e5ec42c237994622f3b8520b428b..0000000000000000000000000000000000000000 Binary files a/images/rainbow.png and /dev/null differ diff --git a/images/refresh_btn.gif b/images/refresh_btn.gif deleted file mode 100644 index 8a33b22d9a9b026391e38a8bbb0d6834eb789a93..0000000000000000000000000000000000000000 Binary files a/images/refresh_btn.gif and /dev/null differ diff --git a/images/ticket_status.gif b/images/ticket_status.gif deleted file mode 100644 index 0775549996b70c79816e455e6850d1abf0e376ab..0000000000000000000000000000000000000000 Binary files a/images/ticket_status.gif and /dev/null differ diff --git a/images/ticket_status_icon.jpg b/images/ticket_status_icon.jpg deleted file mode 100644 index bf27b1f904418c311f05b27f118a55622be51b47..0000000000000000000000000000000000000000 Binary files a/images/ticket_status_icon.jpg and /dev/null differ diff --git a/images/verticalbar.jpg b/images/verticalbar.jpg deleted file mode 100644 index 2678913d2cdb9b8ec861e71396fcb92a552ff13a..0000000000000000000000000000000000000000 Binary files a/images/verticalbar.jpg and /dev/null differ diff --git a/images/view_closed_btn.gif b/images/view_closed_btn.gif deleted file mode 100644 index 6cd8f080a9007a85a2c0f08a6133f54a0253d6e8..0000000000000000000000000000000000000000 Binary files a/images/view_closed_btn.gif and /dev/null differ diff --git a/images/view_open_btn.gif b/images/view_open_btn.gif deleted file mode 100644 index 8ed6be9ce8159b20abfb0c9ea69b5235a4903b33..0000000000000000000000000000000000000000 Binary files a/images/view_open_btn.gif and /dev/null differ diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index 2eff8924b84c1d909d8c35da3ea171d4ebf2619a..458e430ea83192703bea52c026413af63c4edb63 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -21,31 +21,67 @@ include_once(INCLUDE_DIR.'class.ticket.php'); class TicketsAjaxAPI extends AjaxController { function search() { + global $thisstaff; + + if(!is_numeric($_REQUEST['q'])) + return self::searchByEmail(); + + + $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25; + $tickets=array(); + + $sql='SELECT DISTINCT ticketID, email' + .' FROM '.TICKET_TABLE + .' WHERE ticketID LIKE \''.db_input($_REQUEST['q'], false).'%\''; + + $sql.=' AND ( staff_id='.db_input($thisstaff->getId()); + + if(($teams=$thisstaff->getTeams()) && count(array_filter($teams))) + $sql.=' OR team_id IN('.implode(',', array_filter($teams)).')'; + + if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts())) + $sql.=' OR dept_id IN ('.implode(',', $depts).')'; + + $sql.=' ) ' + .' ORDER BY created LIMIT '.$limit; - $limit = isset($_GET['limit']) ? (int) $_GET['limit']:25; - $items=array(); - $ticketid=false; - if(isset($_GET['id'])){ - $WHERE=' WHERE ticketID LIKE \''.db_input($_GET['id'], false).'%\''; - $ticketid=true; - }elseif(isset($_GET['email'])){ - $WHERE=' WHERE email LIKE \''.db_input(strtolower($_GET['email']), false).'%\''; - }else{ - Http::response(400, "id or email argument is required"); + if(($res=db_query($sql)) && db_num_rows($res)) { + while(list($id, $email)=db_fetch_row($res)) + $tickets[] = array('id'=>$id, 'email'=>$email, 'value'=>$id, 'info'=>"$id - $email"); } - $sql='SELECT DISTINCT ticketID,email,name FROM '.TICKET_TABLE.' '.$WHERE.' ORDER BY created LIMIT '.$limit; - $res=db_query($sql); - if($res && db_num_rows($res)){ - while(list($id,$email,$name)=db_fetch_row($res)) { - $info=($ticketid)?$email:$id; - $id=($ticketid)?$id:$email; - # TODO: Return 'name' from email address if 'email' argument - # specified? - $items[] = array('id'=>$id, 'value'=>$id, 'info'=>$info, - 'name'=>$name); - } + + return $this->json_encode($tickets); + } + + function searchByEmail() { + global $thisstaff; + + + $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25; + $tickets=array(); + + $sql='SELECT email, count(ticket_id) as tickets ' + .' FROM '.TICKET_TABLE + .' WHERE email LIKE \'%'.db_input(strtolower($_REQUEST['q']), false).'%\' '; + + $sql.=' AND ( staff_id='.db_input($thisstaff->getId()); + + if(($teams=$thisstaff->getTeams()) && count(array_filter($teams))) + $sql.=' OR team_id IN('.implode(',', array_filter($teams)).')'; + + if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts())) + $sql.=' OR dept_id IN ('.implode(',', $depts).')'; + + $sql.=' ) ' + .' GROUP BY email ' + .' ORDER BY created LIMIT '.$limit; + + if(($res=db_query($sql)) && db_num_rows($res)) { + while(list($email, $count)=db_fetch_row($res)) + $tickets[] = array('email'=>$email, 'value'=>$email, 'info'=>"$email ($count)"); } - return $this->encode(array('results'=>$items)); + + return $this->json_encode($tickets); } function acquireLock($tid) { @@ -124,14 +160,98 @@ class TicketsAjaxAPI extends AjaxController { global $thisstaff; + if(!$thisstaff || !($ticket=Ticket::lookup($tid)) || !$ticket->checkStaffAccess($thisstaff)) + Http::response(404, 'No such ticket'); + + $staff=$ticket->getStaff(); + $lock=$ticket->getLock(); + $error=$msg=$warn=null; + + if($lock && $lock->getStaffId()==$thisstaff->getId()) + $warn.=' <span class="Icon lockedTicket">Ticket is locked by '.$lock->getStaffName().'</span>'; + elseif($ticket->isOverdue()) + $warn.=' <span class="Icon overdueTicket">Marked overdue!</span>'; + + ob_start(); + echo sprintf( + '<div style="width:500px; padding: 2px 2px 0 5px;"> + <h2>%s</h2><br>',Format::htmlchars($ticket->getSubject())); - $ticket = new Ticket($tid); + if($error) + echo sprintf('<div id="msg_error">%s</div>',$error); + elseif($msg) + echo sprintf('<div id="msg_notice">%s</div>',$msg); + elseif($warn) + echo sprintf('<div id="msg_warning">%s</div>',$warn); - $resp = sprintf( - '<div style="width:500px;"> - <strong>Ticket #%d Preview</strong><br>INFO HERE!!', - $ticket->getExtId()); + echo '<table border="0" cellspacing="" cellpadding="1" width="100%" class="ticket_info">'; + $ticket_state=sprintf('<span>%s</span>',ucfirst($ticket->getStatus())); + if($ticket->isOpen()) { + if($ticket->isOverdue()) + $ticket_state.=' — <span>Overdue</span>'; + else + $ticket_state.=sprintf(' — <span>%s</span>',$ticket->getPriority()); + } + + echo sprintf(' + <tr> + <th width="100">Ticket State:</th> + <td>%s</td> + </tr> + <tr> + <th>Create Date:</th> + <td>%s</td> + </tr>',$ticket_state, + Format::db_datetime($ticket->getCreateDate())); + if($ticket->isClosed()) { + echo sprintf(' + <tr> + <th>Close Date:</th> + <td>%s <span class="faded">by %s</span></td> + </tr>', + Format::db_datetime($ticket->getCloseDate()), + ($staff?$staff->getName():'staff') + ); + } elseif($ticket->getDueDate()) { + echo sprintf(' + <tr> + <th>Due Date:</th> + <td>%s</td> + </tr>', + Format::db_datetime($ticket->getDueDate())); + } + echo '</table>'; + + + echo '<hr> + <table border="0" cellspacing="" cellpadding="1" width="100%" class="ticket_info">'; + if($ticket->isOpen()) { + echo sprintf(' + <tr> + <th width="100">Assigned To:</th> + <td>%s</td> + </tr>',$ticket->isAssigned()?implode('/', $ticket->getAssignees()):' <span class="faded">— Unassigned —</span>'); + } + echo sprintf( + ' <tr> + <th width="100">Department:</th> + <td>%s</td> + </tr> + <tr> + <th>Help Topic:</th> + <td>%s</td> + </tr> + <tr> + <th>From:</th> + <td>%s <span class="faded">%s</span></td> + </tr>', + Format::htmlchars($ticket->getDeptName()), + Format::htmlchars($ticket->getHelpTopic()), + Format::htmlchars($ticket->getName()), + $ticket->getEmail()); + echo ' + </table>'; $options[]=array('action'=>'Thread ('.$ticket->getThreadCount().')','url'=>"tickets.php?id=$tid"); if($ticket->getNumNotes()) $options[]=array('action'=>'Notes ('.$ticket->getNumNotes().')','url'=>"tickets.php?id=$tid#notes"); @@ -147,16 +267,19 @@ class TicketsAjaxAPI extends AjaxController { $options[]=array('action'=>'Post Note','url'=>"tickets.php?id=$tid#note"); + if($thisstaff->canEditTickets()) + $options[]=array('action'=>'Edit Ticket','url'=>"tickets.php?id=$tid&a=edit"); + if($options) { - $resp.='<ul class="tip_menu">'; - foreach($options as $option) { - $resp.=sprintf('<li><a href="%s">%s</a></li>', - $option['url'],$option['action']); - } - $resp.='</ul>'; + echo '<ul class="tip_menu">'; + foreach($options as $option) + echo sprintf('<li><a href="%s">%s</a></li>',$option['url'],$option['action']); + echo '</ul>'; } - $resp.='</div>'; + echo '</div>'; + $resp = ob_get_contents(); + ob_end_clean(); return $resp; } diff --git a/include/ajax.users.php b/include/ajax.users.php new file mode 100644 index 0000000000000000000000000000000000000000..01a0cdbf4ba9807f44368e8c834bd17656cd24f1 --- /dev/null +++ b/include/ajax.users.php @@ -0,0 +1,50 @@ +<?php +/********************************************************************* + ajax.users.php + + AJAX interface for users (based on submitted tickets) + XXX: osTicket doesn't support user accounts at the moment. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +if(!defined('INCLUDE_DIR')) die('403'); + +include_once(INCLUDE_DIR.'class.ticket.php'); + +class UsersAjaxAPI extends AjaxController { + + /* Assumes search by emal for now */ + function search() { + + if(!isset($_REQUEST['q'])) { + Http::response(400, 'Query argument is required'); + } + + $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25; + $users=array(); + + $sql='SELECT DISTINCT email, name ' + .' FROM '.TICKET_TABLE + .' WHERE email LIKE \'%'.db_input(strtolower($_REQUEST['q']), false).'%\' ' + .' ORDER BY created ' + .' LIMIT '.$limit; + + if(($res=db_query($sql)) && db_num_rows($res)){ + while(list($email,$name)=db_fetch_row($res)) { + $users[] = array('email'=>$email, 'name'=>$name, 'info'=>"$email - $name"); + } + } + + return $this->json_encode($users); + + } +} +?> diff --git a/include/class.canned.php b/include/class.canned.php index 00c46de3365e92fef38fe29e154c56fafacb622b..6c6c1ac1c75bcbc25b7c288c2e49909e30b4876a 100644 --- a/include/class.canned.php +++ b/include/class.canned.php @@ -143,30 +143,13 @@ class Canned { return $i; } - function deleteAttachment($fileId) { - - $sql='DELETE FROM '.CANNED_ATTACHMENT_TABLE - .' WHERE canned_id='.db_input($this->getId()) - .' AND file_id='.db_input($fileId) - .' LIMIT 1'; - - if(!db_query($sql) || !db_affected_rows()) - return false; - - - if(($file=AttachmentFile::lookup($fileId)) && !$file->isInuse()) - $file->delete(); - - return true; - } - function deleteAttachments(){ $deleted=0; - if(($attachments = $this->getAttachments())) { - foreach($attachments as $attachment) - if($attachment['id'] && $this->deleteAttachment($attachment['id'])) - $deleted++; + $sql='DELETE FROM '.CANNED_ATTACHMENT_TABLE + .' WHERE canned_id='.db_input($this->getId()); + if(db_query($sql) && db_affected_rows()) { + $deleted = AttachmentFile::deleteOrphans(); } return $deleted; diff --git a/include/class.client.php b/include/class.client.php index f7ede15c52fe33b0a1a99dfdecb8081c64407d0d..8786c0e19cdb9719a86a556b3ce26795ac5ce62f 100644 --- a/include/class.client.php +++ b/include/class.client.php @@ -4,8 +4,8 @@ Handles everything about client - The class will undergo major changes one client's accounts are used. - At the moment we will play off the email + ticket ID authentication. + NOTE: Please note that osTicket uses email address and ticket ID to authenticate the user*! + Client is modeled on the info of the ticket used to login . Peter Rotich <peter@osticket.com> Copyright (c) 2006-2012 osTicket @@ -19,75 +19,119 @@ class Client { - var $id; var $fullname; var $username; - var $passwd; var $email; - - var $udata; var $ticket_id; var $ticketID; - function Client($email,$id){ + var $ht; + + + function Client($id, $email=null) { $this->id =0; $this->load($id,$email); } - function isClient(){ - return TRUE; - } + function load($id=0, $email=null) { - function load($id,$email=''){ + if(!$id && !($id=$this->getId())) + return false; - $sql='SELECT ticket_id,ticketID,name,email FROM '.TICKET_TABLE.' WHERE ticketID='.db_input($id); - if($email){ //don't validate...using whatever is entered. + $sql='SELECT ticket_id, ticketID, name, email, phone, phone_ext ' + .' FROM '.TICKET_TABLE + .' WHERE ticketID='.db_input($id); + if($email) $sql.=' AND email='.db_input($email); - } - $res=db_query($sql); - if(!$res || !db_num_rows($res)) + + if(!($res=db_query($sql)) || !db_num_rows($res)) return NULL; - $row=db_fetch_array($res); - $this->udata=$row; - $this->id = $row['ticketID']; //placeholder - $this->ticket_id = $row['ticket_id']; - $this->ticketID = $row['ticketID']; - $this->fullname = ucfirst($row['name']); - $this->username = $row['email']; - $this->email = $row['email']; + $this->ht = db_fetch_array($res); + $this->id = $this->ht['ticketID']; //placeholder + $this->ticket_id = $this->ht['ticket_id']; + $this->ticketID = $this->ht['ticketID']; + $this->fullname = ucfirst($this->ht['name']); + $this->username = $this->ht['email']; + $this->email = $this->ht['email']; + + $this->stats = array(); return($this->id); } + function reload() { + return $this->load(); + } - function getId(){ + function isClient() { + return TRUE; + } + + function getId() { return $this->id; } - function getEmail(){ + function getEmail() { return $this->email; } - function getUserName(){ + function getUserName() { return $this->username; } - function getName(){ + function getName() { return $this->fullname; } + + function getPhone() { + return $this->ht['phone']; + } + + function getPhoneExt() { + return $this->ht['phone_ext']; + } function getTicketID() { return $this->ticketID; } + function getTicketStats() { + + if(!$this->stats['tickets']) + $this->stats['tickets'] = Ticket::getClientStats($this->getEmail()); + + return $this->stats['tickets']; + } + + function getNumTickets() { + return ($stats=$this->getTicketStats())?($stats['open']+$stats['closed']):0; + } + + function getNumOpenTickets() { + return ($stats=$this->getTicketStats())?$stats['open']:0; + } + /* ------------- Static ---------------*/ - function lookup($id, $email) { + function getLastTicketIdByEmail($email) { + $sql='SELECT ticketID FROM '.TICKET_TABLE + .' WHERE email='.db_input($email) + .' ORDER BY created ' + .' LIMIT 1'; + if(($res=db_query($sql)) && db_num_rows($res)) + list($tid) = db_fetch_row($res); + + return $tid; + } + + function lookup($id, $email=null) { return ($id && is_numeric($id) && ($c=new Client($id,$email)) && $c->getId()==$id)?$c:null; } + function lookupByEmail($email) { + return (($id=self::getLastTicketIdByEmail($email)))?self::lookup($id, $email):null; + } } - ?> diff --git a/include/class.config.php b/include/class.config.php index 1e3d7745ffaf9788715308564bcc676fc28ac845..c51814bebc73aef1ae3a9052db364d2702798c04 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -32,17 +32,20 @@ class Config { $this->load($id); } - function load($id) { + function load($id=0) { + if(!$id && !($id=$this->getId())) + return false; - $sql='SELECT * FROM '.CONFIG_TABLE.' WHERE id='.db_input($id); - if($id && ($res=db_query($sql)) && db_num_rows($res)) { - $this->config=db_fetch_array($res); - $this->id=$this->config['id']; + $sql='SELECT * FROM '.CONFIG_TABLE + .' WHERE id='.db_input($id); + if(!($res=db_query($sql)) || !db_num_rows($res)) + return false; - return true; - } + + $this->config=db_fetch_array($res); + $this->id=$this->config['id']; - return false; + return true; } //Initialize some default values. @@ -52,10 +55,13 @@ class Config { } function reload() { - if($this->load($this->id)) - $this->init(); - } + if(!$this->load($this->getId())) + return false; + + $this->init(); + return true; + } function isHelpDeskOffline() { return !$this->isSystemOnline(); @@ -72,10 +78,10 @@ class Config { } function getVersion() { - return '1.7 DPR'; + return '1.7-DPR2'; } - function getSchemaVersion() { + function getSchemaSignature() { return $this->config['schema_signature']; } @@ -111,7 +117,7 @@ class Config { } function getId() { - return $this->config['id']; + return $this->id; } function getTitle() { @@ -145,6 +151,10 @@ class Config { function getPasswdResetPeriod() { return $this->config['passwd_reset_period']; } + + function showRelatedTickets() { + return $this->config['show_related_tickets']; + } function getClientTimeout() { return $this->getClientSessionTimeout(); diff --git a/include/class.cron.php b/include/class.cron.php index 3fd2d652cad8551ffa9852cd3d1f8984f060d542..ddc4d2973e77ff93f6f83a4a3fefd6b4b9b82814 100644 --- a/include/class.cron.php +++ b/include/class.cron.php @@ -34,10 +34,16 @@ class Cron { Sys::purgeLogs(); } + function CleanOrphanedFiles() { + require_once(INCLUDE_DIR.'class.file.php'); + AttachmentFile::deleteOrphans(); + } + function run(){ //called by outside cron NOT autocron - Cron::MailFetcher(); - Cron::TicketMonitor(); - cron::PurgeLogs(); + self::MailFetcher(); + self::TicketMonitor(); + self::PurgeLogs(); + self::CleanOrphanedFiles(); } } ?> diff --git a/include/class.dispatcher.php b/include/class.dispatcher.php index 507b2f9fe3163a30a81e944ebc876639f95407f0..da9fb862889f8eb17b9ea6bd8b89daee8c8c8194 100644 --- a/include/class.dispatcher.php +++ b/include/class.dispatcher.php @@ -30,7 +30,7 @@ class Dispatcher { if ($this->file) { $this->lazy_load(); } # Support HTTP method emulation with the _method GET argument if (isset($_GET['_method'])) { - $_SERVER['REQUEST_METHOD'] = strtoupper($_GET['method']); + $_SERVER['REQUEST_METHOD'] = strtoupper($_GET['_method']); unset($_GET['_method']); } foreach ($this->urls as $matcher) { diff --git a/include/class.export.php b/include/class.export.php new file mode 100644 index 0000000000000000000000000000000000000000..7d6a7e7ec87b5939d8a7657370ea61626c06700c --- /dev/null +++ b/include/class.export.php @@ -0,0 +1,135 @@ +<?php +/************************************************************************* + class.export.php + + Exports stuff (details to follow) + + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +class Export { + + /* static */ function dumpQuery($sql, $headers, $how='csv') { + $exporters = array( + 'csv' => CsvResultsExporter, + 'json' => JsonResultsExporter + ); + $exp = new $exporters[$how]($sql, $headers); + return $exp->dump(); + } + + # XXX: Think about facilitated exporting. For instance, we might have a + # TicketExporter, which will know how to formulate or lookup a + # formatl query (SQL), and cooperate with the output process to add + # extra (recursive) information. In this funciton, the top-level + # SQL is exported, but for something like tickets, we will need to + # export attached messages, reponses, and notes, as well as + # attachments associated with each, ... + /* static */ function dumpTickets($sql, $how='csv') { + return self::dumpQuery($sql, + array( + 'ticketID' => 'Ticket Id', + 'created' => 'Date', + 'subject' => 'Subject', + 'name' => 'From', + 'priority_desc' => 'Priority', + 'dept_name' => 'Department', + 'source' => 'Source', + 'status' => 'Current Status' + ), + $how); + } + + /* static */ function saveTickets($sql, $filename, $how='csv') { + ob_start(); + self::dumpTickets($sql, $how); + $stuff = ob_get_contents(); + ob_end_clean(); + if ($stuff) + Http::download($filename, "text/$how", $stuff); + + return false; + } +} + +class ResultSetExporter { + function ResultSetExporter($sql, $headers) { + $this->headers = array_values($headers); + $this->_res = db_query($sql); + if ($row = db_fetch_array($this->_res)) { + $query_fields = array_keys($row); + $this->headers = array(); + $this->keys = array(); + $this->lookups = array(); + foreach ($headers as $field=>$name) { + if (isset($row[$field])) { + $this->headers[] = $name; + $this->keys[] = $field; + # Remember the location of this header in the query results + # (column-wise) so we don't have to do hashtable lookups for every + # column of every row. + $this->lookups[] = array_search($field, $query_fields); + } + } + db_data_reset($this->_res); + } + } + + function getHeaders() { + return $this->headers; + } + + function next() { + if (!($row = db_fetch_row($this->_res))) + return false; + + $record = array(); + foreach ($this->lookups as $idx) + $record[] = $row[$idx]; + return $record; + } + + function nextArray() { + if (!($row = $this->next())) + return false; + return array_combine($this->keys, $row); + } + + function dump() { + # Useful for debug output + while ($row=$this->nextArray()) { + var_dump($row); + } + } +} + +class CsvResultsExporter extends ResultSetExporter { + function dump() { + echo '"' . implode('","', $this->getHeaders()) . "\"\n"; + while ($row=$this->next()) { + foreach ($row as &$val) + # Escape enclosed double-quotes + $val = str_replace('"','""',$val); + echo '"' . implode('","', $row) . "\"\n"; + } + } +} + +class JsonResultsExporter extends ResultSetExporter { + function dump() { + require_once(INCLUDE_DIR.'class.json.php'); + $exp = new JsonDataEncoder(); + $rows = array(); + while ($row=$this->nextArray()) { + $rows[] = $row; + } + echo $exp->encode($rows); + } +} diff --git a/include/class.faq.php b/include/class.faq.php index 63b0848e469c7b3b1df6dbb9d61e27fca2c28118..7e23803dc458272ed7f81184c190213ddabd0e85 100644 --- a/include/class.faq.php +++ b/include/class.faq.php @@ -192,7 +192,7 @@ class FAQ { /* The h key must match validation in file.php */ $hash=$attachment['hash'].md5($attachment['id'].session_id().$attachment['hash']); if($attachment['size']) - $size=sprintf('(<i>%s</i>)',Format::file_size($attachment['size'])); + $size=sprintf(' <small>(<i>%s</i>)</small>',Format::file_size($attachment['size'])); $str.=sprintf('<a class="Icon file" href="file.php?h=%s" target="%s">%s</a>%s %s', $hash, $target, Format::htmlchars($attachment['name']), $size, $separator); @@ -217,29 +217,13 @@ class FAQ { return $i; } - function deleteAttachment($fileId) { - - $sql='DELETE FROM '.FAQ_ATTACHMENT_TABLE - .' WHERE faq_id='.db_input($this->getId()) - .' AND file_id='.db_input($fileId) - .' LIMIT 1'; - - if(!db_query($sql) || !db_affected_rows()) - return false; - - if(($file=AttachmentFile::lookup($fileId)) && !$file->isInuse()) - $file->delete(); - - return true; - } - function deleteAttachments(){ $deleted=0; - if(($attachments = $this->getAttachments())) { - foreach($attachments as $attachment) - if($attachment['id'] && $this->deleteAttachment($attachment['id'])) - $deleted++; + $sql='DELETE FROM '.FAQ_ATTACHMENT_TABLE + .' WHERE faq_id='.db_input($this->getId()); + if(db_query($sql) && db_affected_rows()) { + $deleted = AttachmentFile::deleteOrphans(); } return $deleted; diff --git a/include/class.file.php b/include/class.file.php index af38bfd59e43b45471dc35d8e1a256678c05588a..b9bfbe1b7d2975ebdcc467bfb826ed35b8f1ec75 100644 --- a/include/class.file.php +++ b/include/class.file.php @@ -138,6 +138,7 @@ class AttachmentFile { exit(); } + /* Function assumes the files types have been validated */ function upload($file) { if(!$file['name'] || !is_uploaded_file($file['tmp_name'])) @@ -193,6 +194,24 @@ class AttachmentFile { return ($id && ($file = new AttachmentFile($id)) && $file->getId()==$id)?$file:null; } + /** + * Removes files and associated meta-data for files which no ticket, + * canned-response, or faq point to any more. + */ + /* static */ function deleteOrphans() { + $res=db_query( + 'DELETE FROM '.FILE_TABLE.' WHERE id NOT IN (' + # DISTINCT implies sort and may not be necessary + .'SELECT DISTINCT(file_id) FROM (' + .'SELECT file_id FROM '.TICKET_ATTACHMENT_TABLE + .' UNION ALL ' + .'SELECT file_id FROM '.CANNED_ATTACHMENT_TABLE + .' UNION ALL ' + .'SELECT file_id FROM '.FAQ_ATTACHMENT_TABLE + .') still_loved' + .')'); + return db_affected_rows(); + } } class AttachmentList { diff --git a/include/class.filter.php b/include/class.filter.php index 9a1caf2b1b0792c9cea14d9cbf28cf4a458ea0ce..4f18e96514c307077b7300a02674f8ad1698039e 100644 --- a/include/class.filter.php +++ b/include/class.filter.php @@ -38,7 +38,7 @@ class Filter { return false; $this->ht=db_fetch_array($res); - $this->id=$info['id']; + $this->id=$this->ht['id']; return true; } @@ -260,7 +260,7 @@ class Filter { # Set owning department (?) if ($this->getDeptId()) $ticket['deptId']=$this->getDeptId(); # Set ticket priority (?) - if ($this->getPriorityId()) $ticket['pri']=$this->getPriorityId(); + if ($this->getPriorityId()) $ticket['priorityId']=$this->getPriorityId(); # Set SLA plan (?) if ($this->getSLAId()) $ticket['slaId']=$this->getSLAId(); # Auto-assign to (?) @@ -589,16 +589,46 @@ class EmailFilter { array_push($this->filters, new Filter($id)); return $this->filters; } + /** + * Fetches the short list of filters that match the email received in the + * constructor. This function is memoized so subsequent calls will + * return immediately. + */ + function getMatchingFilterList() { + if (!isset($this->short_list)) { + $this->short_list = array(); + foreach ($this->filters as $filter) + if ($filter->matches($this->email)) + $this->short_list[] = $filter; + } + return $this->short_list; + } + /** + * Determine if the filters that match the received email indicate that + * the email should be rejected + * + * Returns FALSE if the email should be acceptable. If the email should + * be rejected, the first filter that matches and has rejectEmail set is + * returned. + */ + function shouldReject() { + foreach ($this->getMatchingFilterList() as $filter) { + # Set reject if this filter indicates that the email should + # be blocked; however, don't unset $reject, because if it + # was set by another rule that did not set stopOnMatch(), we + # should still honor its configuration + if ($filter->rejectEmail()) return $filter; + } + return false; + } /** * Determine if any filters match the received email, and if so, apply * actions defined in those filters to the ticket-to-be-created. */ function apply(&$ticket) { - foreach ($this->filters as $filter) { - if ($filter->matches($this->email)) { - $filter->apply($ticket, $this->email); - if ($filter->stopOnMatch()) break; - } + foreach ($this->getMatchingFilterList() as $filter) { + $filter->apply($ticket, $this->email); + if ($filter->stopOnMatch()) break; } } diff --git a/include/class.format.php b/include/class.format.php index 0dbd9e1432215d57b92661e99acfe761fa96b522..45f4301913072fa49d93d7dc3a10019b82536563 100644 --- a/include/class.format.php +++ b/include/class.format.php @@ -117,10 +117,12 @@ class Format { function clickableurls($text) { //Not perfect but it works - please help improve it. - $text=preg_replace('/(((f|ht){1}tp(s?):\/\/)[-a-zA-Z0-9@:%_\+.~#?&;\/\/=]+)/','<a href="\\1" target="_blank">\\1</a>', $text); + $text=preg_replace('/(((f|ht){1}tp(s?):\/\/)[-a-zA-Z0-9@:%_\+.~#?&;\/\/=]+)/', + '<a href="l.php?url=\\1" target="_blank">\\1</a>', $text); $text=preg_replace("/(^|[ \\n\\r\\t])(www\.([a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+)(\/[^\/ \\n\\r]*)*)/", - '\\1<a href="http://\\2" target="_blank">\\2</a>', $text); - $text=preg_replace("/(^|[ \\n\\r\\t])([_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4})/",'\\1<a href="mailto:\\2" target="_blank">\\2</a>', $text); + '\\1<a href="l.php?url=http://\\2" target="_blank">\\2</a>', $text); + $text=preg_replace("/(^|[ \\n\\r\\t])([_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4})/", + '\\1<a href="l.php?url=mailto:\\2" target="_blank">\\2</a>', $text); return $text; } diff --git a/include/class.http.php b/include/class.http.php index d134e6b8f3aef21f50440b175d8aa7249dc08676..37ad0302719cd8c96586dd03ed864c0dd07bc3ee 100644 --- a/include/class.http.php +++ b/include/class.http.php @@ -50,5 +50,27 @@ class Http { } exit; } + + function download($filename, $type, $data=null) { + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Cache-Control: public'); + header('Content-Type: '.$type); + $user_agent = strtolower ($_SERVER['HTTP_USER_AGENT']); + if (strpos($user_agent,'msie') !== false + && strpos($user_agent,'win') !== false) { + header('Content-Disposition: filename="'.basename($filename).'";'); + } else { + header('Content-Disposition: attachment; filename="' + .basename($filename).'"'); + } + header('Content-Transfer-Encoding: binary'); + if ($data !== null) { + header('Content-Length: '.strlen($data)); + print $data; + exit; + } + } } ?> diff --git a/include/class.misc.php b/include/class.misc.php index c9a5db034865db1ac621948aacd3a03b9a919b1b..d9f59f47858b23c9c47c2de6ea6c3cedfda61df1 100644 --- a/include/class.misc.php +++ b/include/class.misc.php @@ -139,6 +139,22 @@ class Misc { return $output; } - + function siteBaseUrl() { + # Detects Alias-ing + $paths = explode('/', $_SERVER['REQUEST_URI']); + # Drop the last item -- it will be the php page we're on + array_pop($paths); + $leading = array(); + while (count($paths)) { + if (in_array($paths[0], array('scp','client'))) + break; + $leading[] = array_shift($paths); + } + if (count($leading) > 1) + return implode('/', $leading); + else + return ''; + } + } ?> diff --git a/include/class.nav.php b/include/class.nav.php index 561fc963dcd80165bc755fd96588907a3e06a1ac..a3b719f08d6bec16f6a2a7bb3fb264b1730c2f13 100644 --- a/include/class.nav.php +++ b/include/class.nav.php @@ -263,15 +263,24 @@ class UserNav { $navs = array(); $user = $this->user; - $navs['home']=array('desc'=>'Support Center Home','href'=>'index.php','title'=>''); + $navs['home']=array('desc'=>'Support Center Home','href'=>'index.php','title'=>''); if($cfg && $cfg->isKnowledgebaseEnabled()) $navs['kb']=array('desc'=>'Knowledgebase','href'=>'kb/index.php','title'=>''); - $navs['new']=array('desc'=>'Open New Ticket','href'=>'open.php','title'=>''); - if($user && $user->isValid()) - $navs['tickets']=array('desc'=>'My Tickets','href'=>'tickets.php','title'=>''); - else + $navs['new']=array('desc'=>'Open New Ticket','href'=>'open.php','title'=>''); + if($user && $user->isValid()) { + if($cfg && $cfg->showRelatedTickets()) { + $navs['tickets']=array('desc'=>sprintf('My Tickets (%d)',$user->getNumTickets()), + 'href'=>'tickets.php', + 'title'=>'Show all tickets'); + } else { + $navs['tickets']=array('desc'=>'View Ticket Thread', + 'href'=>sprintf('tickets.php?id=%d',$user->getTicketID()), + 'title'=>'View ticket status'); + } + } else { $navs['status']=array('desc'=>'Check Ticket Status','href'=>'view.php','title'=>''); + } $this->navs=$navs; } diff --git a/include/class.sla.php b/include/class.sla.php index 9ea62b0527fbc64ede3b94b51f6f9a1a9b91243a..7055977a8a752408bf2671f6e87cd404f9f32409 100644 --- a/include/class.sla.php +++ b/include/class.sla.php @@ -19,91 +19,117 @@ class SLA { var $info; - function SLA($id){ + function SLA($id) { $this->id=0; $this->load($id); } - function load($id) { + function load($id=0) { + + if(!$id && !($id=$this->getId())) + return false; $sql='SELECT * FROM '.SLA_TABLE.' WHERE id='.db_input($id); - if(($res=db_query($sql)) && db_num_rows($res)) { - $info=db_fetch_array($res); - $this->id=$info['id']; - $this->info=$info; - return true; - } - return false; + if(!($res=db_query($sql)) || !db_num_rows($res)) + return false; + + $this->ht=db_fetch_array($res); + $this->id=$this->ht['id']; + return true; } function reload() { - return $this->load($this->getId()); + return $this->load(); } - function getId(){ + function getId() { return $this->id; } - function getName(){ - return $this->info['name']; + function getName() { + return $this->ht['name']; } - function getGracePeriod(){ - return $this->info['grace_period']; + function getGracePeriod() { + return $this->ht['grace_period']; } - function getNotes(){ - return $this->info['notes']; + function getNotes() { + return $this->ht['notes']; } - function getInfo(){ - return $this->info; + function getHashtable() { + return $this->ht; } - function isActive(){ - return ($this->info['isactive']); + function getInfo() { + return $this->getHashtable(); } - function sendAlerts(){ - return (!$this->info['disable_overdue_alerts']); + function isActive() { + return ($this->ht['isactive']); } - function priorityEscalation(){ - return ($this->info['enable_priority_escalation']); + function sendAlerts() { + return (!$this->ht['disable_overdue_alerts']); } - function update($vars,&$errors){ - if(SLA::save($this->getId(),$vars,$errors)){ - $this->reload(); - return true; - } + function alertOnOverdue() { + return $this->sendAlerts(); + } + + function priorityEscalation() { + return ($this->ht['enable_priority_escalation']); + } + + function update($vars,&$errors) { - return false; + if(!SLA::save($this->getId(),$vars,$errors)) + return false; + + $this->reload(); + + return true; } - function delete(){ + function delete() { global $cfg; - if($cfg && $cfg->getDefaultSLAId()==$this->getId()) + if(!$cfg || $cfg->getDefaultSLAId()==$this->getId()) return false; $id=$this->getId(); $sql='DELETE FROM '.SLA_TABLE.' WHERE id='.db_input($id).' LIMIT 1'; - if(db_query($sql) && ($num=db_affected_rows())){ + if(db_query($sql) && ($num=db_affected_rows())) { db_query('UPDATE '.DEPT_TABLE.' SET sla_id=0 WHERE sla_id='.db_input($id)); db_query('UPDATE '.TOPIC_TABLE.' SET sla_id=0 WHERE sla_id='.db_input($id)); - db_query('UPDATE '.TICKET_TABLE.' SET sla_id=0 WHERE sla_id='.db_input($id)); + db_query('UPDATE '.TICKET_TABLE.' SET sla_id='.db_input($cfg->getDefaultSLAId()).' WHERE sla_id='.db_input($id)); } return $num; } /** static functions **/ - function create($vars,&$errors){ + function create($vars,&$errors) { return SLA::save(0,$vars,$errors); } - function getIdByName($name){ + function getSLAs() { + + $slas=array(); + + $sql='SELECT id, name FROM '.SLA_TABLE; + if(($res=db_query($sql)) && db_num_rows($res)) { + while(list($id, $name)=db_fetch_row($res)) + $slas[$id]=$name; + + } + + return $slas; + } + + + function getIdByName($name) { $sql='SELECT id FROM '.SLA_TABLE.' WHERE name='.db_input($name); if(($res=db_query($sql)) && db_num_rows($res)) @@ -112,11 +138,11 @@ class SLA { return $id; } - function lookup($id){ + function lookup($id) { return ($id && is_numeric($id) && ($sla= new SLA($id)) && $sla->getId()==$id)?$sla:null; } - function save($id,$vars,&$errors){ + function save($id,$vars,&$errors) { if(!$vars['grace_period']) diff --git a/include/class.staff.php b/include/class.staff.php index bfb0b79d2735c32b2410845fba1f0f89490bf0ba..878c0333efc1cc5ad8416dba744c02ebc0c379f5 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -27,25 +27,28 @@ class Staff { var $teams; var $stats; - function Staff($var){ + function Staff($var) { $this->id =0; return ($this->load($var)); } - function load($var=''){ + function load($var='') { if(!$var && !($var=$this->getId())) return false; - $sql='SELECT staff.*,grp.*,tz.offset as tz_offset,TIME_TO_SEC(TIMEDIFF(NOW(),IFNULL(staff.passwdreset,staff.created))) as passwd_change_sec '. - 'FROM '.STAFF_TABLE.' staff '. - 'LEFT JOIN '.GROUP_TABLE.' grp ON(grp.group_id=staff.group_id) '. - 'LEFT JOIN '.TIMEZONE_TABLE.' tz ON(tz.id=staff.timezone_id) '; + $sql='SELECT staff.*, grp.*, tz.offset as tz_offset ' + .' ,TIME_TO_SEC(TIMEDIFF(NOW(),IFNULL(staff.passwdreset,staff.created))) as passwd_change_sec ' + .' FROM '.STAFF_TABLE.' staff ' + .' LEFT JOIN '.GROUP_TABLE.' grp ON(grp.group_id=staff.group_id) ' + .' LEFT JOIN '.TIMEZONE_TABLE.' tz ON(tz.id=staff.timezone_id) '; + $sql.=sprintf('WHERE %s=%s',is_numeric($var)?'staff_id':'username',db_input($var)); if(!($res=db_query($sql)) || !db_num_rows($res)) return NULL; + $this->ht=db_fetch_array($res); $this->id = $this->ht['staff_id']; $this->teams =$this->ht['teams']=$this->getTeams(); @@ -56,7 +59,7 @@ class Staff { return ($this->id); } - function reload(){ + function reload() { return $this->load(); } @@ -64,15 +67,15 @@ class Staff { return $this->ht; } - function getInfo(){ + function getInfo() { return $this->getHastable(); } /*compares user password*/ - function check_passwd($password){ + function check_passwd($password) { /*bcrypt based password match*/ - if(Passwd::cmp($password,$this->getPasswd())) + if(Passwd::cmp($password, $this->getPasswd())) return true; /*Fall back to MD5 && force a password reset if it matches*/ @@ -90,7 +93,7 @@ class Staff { } /* check if passwd reset is due. */ - function isPasswdResetDue(){ + function isPasswdResetDue() { global $cfg; return ($cfg && $cfg->getPasswdResetPeriod() && $this->ht['passwd_change_sec']>($cfg->getPasswdResetPeriod()*30*24*60*60)); } @@ -107,7 +110,7 @@ class Staff { return $this->ht['daylight_saving']?true:false; } - function getRefreshRate(){ + function getRefreshRate() { return $this->ht['auto_refresh_rate']; } @@ -115,39 +118,39 @@ class Staff { return $this->ht['max_page_size']; } - function getId(){ + function getId() { return $this->id; } - function getEmail(){ + function getEmail() { return $this->ht['email']; } - function getUserName(){ + function getUserName() { return $this->ht['username']; } - function getPasswd(){ + function getPasswd() { return $this->ht['passwd']; } - function getName(){ + function getName() { return ucfirst($this->ht['firstname'].' '.$this->ht['lastname']); } - function getFirstName(){ + function getFirstName() { return $this->ht['firstname']; } - function getLastName(){ + function getLastName() { return $this->ht['lastname']; } - function getGroupId(){ + function getGroupId() { return $this->ht['group_id']; } - function getSignature(){ + function getSignature() { return $this->ht['signature']; } @@ -155,24 +158,24 @@ class Staff { return $this->ht['default_signature_type']; } - function forcePasswdChange(){ + function forcePasswdChange() { return ($this->ht['change_passwd']); } - function getDepts(){ + function getDepts() { //Departments the user is allowed to access...based on the group they belong to + user's dept. - return array_filter(array_unique(array_merge(explode(',',$this->ht['dept_access']),array($this->dept_id)))); //Neptune help us + return array_filter(array_unique(array_merge(explode(',', $this->ht['dept_access']), array($this->dept_id)))); //Neptune help us } function getDepartments() { return $this->getDepts(); } - function getDeptId(){ + function getDeptId() { return $this->ht['dept_id']; } - function getDept(){ + function getDept() { if(!$this->dept && $this->getDeptIf()) $this->dept= Dept::lookup($this->getDeptId()); @@ -181,27 +184,27 @@ class Staff { } - function isManager(){ + function isManager() { return (($dept=$this->getDept()) && $dept->getManagerId()==$this->getId()); } - function isStaff(){ + function isStaff() { return TRUE; } - function isGroupActive(){ + function isGroupActive() { return ($this->ht['group_enabled']); } - function isactive(){ + function isactive() { return ($this->ht['isactive']); } - function isVisible(){ + function isVisible() { return ($this->ht['isvisible']); } - function onVacation(){ + function onVacation() { return ($this->ht['onvacation']); } @@ -209,35 +212,39 @@ class Staff { return ($this->isactive() && $this->isGroupActive() && !$this->onVacation()); } - function isAccessLimited(){ + function showAssignedOnly() { return ($this->ht['assigned_only']); } + + function isAccessLimited() { + return $this->showAssignedOnly(); + } - function isadmin(){ + function isadmin() { return ($this->ht['isadmin']); } function isTeamMember($teamId) { - return ($teamId && in_array($teamId,$this->getTeams())); + return ($teamId && in_array($teamId, $this->getTeams())); } function canAccessDept($deptId) { - return ($deptId && in_array($deptId,$this->getDepts()) && !$this->isAccessLimited()); + return ($deptId && in_array($deptId, $this->getDepts()) && !$this->isAccessLimited()); } - function canCreateTickets(){ + function canCreateTickets() { return ($this->ht['can_create_tickets']); } - function canEditTickets(){ + function canEditTickets() { return ($this->ht['can_edit_tickets']); } - function canDeleteTickets(){ + function canDeleteTickets() { return ($this->ht['can_delete_tickets']); } - function canCloseTickets(){ + function canCloseTickets() { return ($this->ht['can_close_tickets']); } @@ -253,13 +260,13 @@ class Staff { return ($this->ht['can_ban_emails']); } - function canManageTickets(){ + function canManageTickets() { return ($this->isadmin() || $this->canDeleteTickets() || $this->canCloseTickets()); } - function canManagePremade(){ + function canManagePremade() { return ($this->ht['can_manage_premade']); } @@ -267,7 +274,7 @@ class Staff { return $this->canManagePremade(); } - function canManageFAQ(){ + function canManageFAQ() { return ($this->ht['can_manage_faq']); } @@ -275,15 +282,16 @@ class Staff { return $this->canManageFAQ(); } - function showAssignedTickets(){ + function showAssignedTickets() { return ($this->ht['show_assigned_tickets'] && ($this->isAdmin() || $this->isManager())); } - function getTeams(){ + function getTeams() { - if(!$this->teams){ - $sql='SELECT team_id FROM '.TEAM_MEMBER_TABLE.' WHERE staff_id='.db_input($this->getId()); + if(!$this->teams) { + $sql='SELECT team_id FROM '.TEAM_MEMBER_TABLE + .' WHERE staff_id='.db_input($this->getId()); if(($res=db_query($sql)) && db_num_rows($res)) while(list($id)=db_fetch_row($res)) $this->teams[] = $id; @@ -307,7 +315,6 @@ class Staff { } function getNumAssignedTickets() { - return ($stats=$this->getTicketsStats())?$stats['assigned']:0; } @@ -316,7 +323,7 @@ class Staff { } //Staff profile update...unfortunately we have to separate it from admin update to avoid potential issues - function updateProfile($vars,&$errors){ + function updateProfile($vars, &$errors) { $vars['firstname']=Format::striptags($vars['firstname']); $vars['lastname']=Format::striptags($vars['lastname']); @@ -344,13 +351,13 @@ class Staff { if($vars['mobile'] && !Validator::is_phone($vars['mobile'])) $errors['mobile']='Valid number required'; - if($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd']){ + if($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd']) { if(!$vars['passwd1']) $errors['passwd1']='New password required'; elseif($vars['passwd1'] && strlen($vars['passwd1'])<6) $errors['passwd1']='Must be at least 6 characters'; - elseif($vars['passwd1'] && strcmp($vars['passwd1'],$vars['passwd2'])) + elseif($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2'])) $errors['passwd2']='Password(s) do not match'; if(!$vars['cpasswd']) @@ -384,7 +391,7 @@ class Staff { if($vars['passwd1']) - $sql.=',change_passwd=0,passwdreset=NOW(),passwd='.db_input(Passwd::hash($vars['passwd1'])); + $sql.=' ,change_passwd=0, passwdreset=NOW(), passwd='.db_input(Passwd::hash($vars['passwd1'])); $sql.=' WHERE staff_id='.db_input($this->getId()); @@ -394,25 +401,26 @@ class Staff { } - function updateTeams($teams){ + function updateTeams($teams) { - if($teams){ - foreach($teams as $k=>$id){ - $sql='INSERT IGNORE INTO '.TEAM_MEMBER_TABLE.' SET updated=NOW(),staff_id='.db_input($this->getId()).',team_id='.db_input($id); + if($teams) { + foreach($teams as $k=>$id) { + $sql='INSERT IGNORE INTO '.TEAM_MEMBER_TABLE.' SET updated=NOW() ' + .' ,staff_id='.db_input($this->getId()).', team_id='.db_input($id); db_query($sql); } } $sql='DELETE FROM '.TEAM_MEMBER_TABLE.' WHERE staff_id='.db_input($this->getId()); if($teams) - $sql.=' AND team_id NOT IN('.implode(',',$teams).')'; + $sql.=' AND team_id NOT IN('.implode(',', $teams).')'; db_query($sql); return true; } - function update($vars,&$errors) { - if(!$this->save($this->getId(),$vars,$errors)) + function update($vars, &$errors) { + if(!$this->save($this->getId(), $vars, $errors)) return false; $this->updateTeams($vars['teams']); @@ -421,14 +429,14 @@ class Staff { return true; } - function delete(){ + function delete() { global $thisstaff; if(!$thisstaff || !($id=$this->getId()) || $id==$thisstaff->getId()) return 0; $sql='DELETE FROM '.STAFF_TABLE.' WHERE staff_id='.db_input($id).' LIMIT 1'; - if(db_query($sql) && ($num=db_affected_rows())){ + if(db_query($sql) && ($num=db_affected_rows())) { // DO SOME HOUSE CLEANING //Move remove any ticket assignments...TODO: send alert to Dept. manager? db_query('UPDATE '.TICKET_TABLE.' SET staff_id=0 WHERE status=\'open\' AND staff_id='.db_input($id)); @@ -465,7 +473,7 @@ class Staff { return self::getStaffMembers(true); } - function getIdByUsername($username){ + function getIdByUsername($username) { $sql='SELECT staff_id FROM '.STAFF_TABLE.' WHERE username='.db_input($username); if(($res=db_query($sql)) && db_num_rows($res)) @@ -473,7 +481,7 @@ class Staff { return $id; } - function getIdByEmail($email){ + function getIdByEmail($email) { $sql='SELECT staff_id FROM '.STAFF_TABLE.' WHERE email='.db_input($email); if(($res=db_query($sql)) && db_num_rows($res)) @@ -482,25 +490,25 @@ class Staff { return $id; } - function lookup($id){ + function lookup($id) { return ($id && is_numeric($id) && ($staff= new Staff($id)) && $staff->getId()==$id)?$staff:null; } - function login($username,$passwd,&$errors,$strike=true){ + function login($username, $passwd, &$errors, $strike=true) { global $cfg; if($_SESSION['_staff']['laststrike']) { if((time()-$_SESSION['_staff']['laststrike'])<$cfg->getStaffLoginTimeout()) { $errors['err']='You\'ve reached maximum failed login attempts allowed.'; - }else{ //Timeout is over. + } else { //Timeout is over. //Reset the counter for next round of attempts after the timeout. $_SESSION['_staff']['laststrike']=null; $_SESSION['_staff']['strikes']=0; } } - if(!$errors && ($user=new StaffSession($username)) && $user->getId() && $user->check_passwd($passwd)){ + if(!$errors && ($user=new StaffSession($username)) && $user->getId() && $user->check_passwd($passwd)) { //update last login && password reset stuff. $sql='UPDATE '.STAFF_TABLE.' SET lastlogin=NOW() '; if($user->isPasswdResetDue() && !$user->isAdmin()) @@ -513,7 +521,7 @@ class Staff { $user->refreshSession(); //set the hash. $_SESSION['TZ_OFFSET']=$user->getTZoffset(); $_SESSION['daylight']=$user->observeDaylight(); - Sys::log(LOG_DEBUG,'Staff login',sprintf("%s logged in [%s]",$user->getUserName(),$_SERVER['REMOTE_ADDR'])); //Debug. + Sys::log(LOG_DEBUG,'Staff login',sprintf("%s logged in [%s]", $user->getUserName(), $_SERVER['REMOTE_ADDR'])); //Debug. $sid=session_id(); //Current ID session_regenerate_id(TRUE); //Destroy old session ID - needed for PHP version < 5.1.0 TODO: remove when we move to php 5.3 as min. requirement. @@ -532,25 +540,25 @@ class Staff { $alert='Excessive login attempts by a staff member?'."\n". 'Username: '.$_POST['username']."\n".'IP: '.$_SERVER['REMOTE_ADDR']."\n".'TIME: '.date('M j, Y, g:i a T')."\n\n". 'Attempts #'.$_SESSION['_staff']['strikes']."\n".'Timeout: '.($cfg->getStaffLoginTimeout()/60)." minutes \n\n"; - Sys::log(LOG_ALERT,'Excessive login attempts ('.$_POST['username'].')',$alert,($cfg->alertONLoginError())); + Sys::log(LOG_ALERT,'Excessive login attempts ('.$_POST['username'].')', $alert,($cfg->alertONLoginError())); - }elseif($_SESSION['_staff']['strikes']%2==0){ //Log every other failed login attempt as a warning. + } elseif($_SESSION['_staff']['strikes']%2==0) { //Log every other failed login attempt as a warning. $alert='Username: '.$_POST['username']."\n".'IP: '.$_SERVER['REMOTE_ADDR']. "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_staff']['strikes']; - Sys::log(LOG_WARNING,'Failed staff login attempt ('.$_POST['username'].')',$alert); + Sys::log(LOG_WARNING,'Failed staff login attempt ('.$_POST['username'].')', $alert); } return false; } - function create($vars,&$errors) { - if(($id=self::save(0,$vars,$errors)) && $vars['teams'] && ($self=Staff::lookup($id))) + function create($vars, &$errors) { + if(($id=self::save(0, $vars, $errors)) && $vars['teams'] && ($self=Staff::lookup($id))) $staff->updateTeams($vars['teams']); return $id; } - function save($id,$vars,&$errors) { + function save($id, $vars, &$errors) { $vars['username']=Format::striptags($vars['username']); $vars['firstname']=Format::striptags($vars['firstname']); @@ -583,13 +591,13 @@ class Staff { if($vars['mobile'] && !Validator::is_phone($vars['mobile'])) $errors['mobile']='Valid number required'; - if($vars['passwd1'] || $vars['passwd2'] || !$id){ - if(!$vars['passwd1'] && !$id){ + if($vars['passwd1'] || $vars['passwd2'] || !$id) { + if(!$vars['passwd1'] && !$id) { $errors['passwd1']='Temp. password required'; $errors['temppasswd']='Required'; - }elseif($vars['passwd1'] && strlen($vars['passwd1'])<6){ + } elseif($vars['passwd1'] && strlen($vars['passwd1'])<6) { $errors['passwd1']='Must be at least 6 characters'; - }elseif($vars['passwd1'] && strcmp($vars['passwd1'],$vars['passwd2'])){ + } elseif($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2'])) { $errors['passwd2']='Password(s) do not match'; } } @@ -606,30 +614,30 @@ class Staff { if($errors) return false; - $sql=' SET updated=NOW() '. - ',isadmin='.db_input($vars['isadmin']). - ',isactive='.db_input($vars['isactive']). - ',isvisible='.db_input(isset($vars['isvisible'])?1:0). - ',onvacation='.db_input(isset($vars['onvacation'])?1:0). - ',assigned_only='.db_input(isset($vars['assigned_only'])?1:0). - ',dept_id='.db_input($vars['dept_id']). - ',group_id='.db_input($vars['group_id']). - ',timezone_id='.db_input($vars['timezone_id']). - ',username='.db_input($vars['username']). - ',firstname='.db_input($vars['firstname']). - ',lastname='.db_input($vars['lastname']). - ',email='.db_input($vars['email']). - ',phone="'.db_input(Format::phone($vars['phone']),false).'"'. - ',phone_ext='.db_input($vars['phone_ext']). - ',mobile="'.db_input(Format::phone($vars['mobile']),false).'"'. - ',signature='.db_input($vars['signature']). - ',notes='.db_input($vars['notes']); + $sql='SET updated=NOW() ' + .' ,isadmin='.db_input($vars['isadmin']) + .' ,isactive='.db_input($vars['isactive']) + .' ,isvisible='.db_input(isset($vars['isvisible'])?1:0) + .' ,onvacation='.db_input(isset($vars['onvacation'])?1:0) + .' ,assigned_only='.db_input(isset($vars['assigned_only'])?1:0) + .' ,dept_id='.db_input($vars['dept_id']) + .' ,group_id='.db_input($vars['group_id']) + .' ,timezone_id='.db_input($vars['timezone_id']) + .' ,username='.db_input($vars['username']) + .' ,firstname='.db_input($vars['firstname']) + .' ,lastname='.db_input($vars['lastname']) + .' ,email='.db_input($vars['email']) + .' ,phone="'.db_input(Format::phone($vars['phone']),false).'"' + .' ,phone_ext='.db_input($vars['phone_ext']) + .' ,mobile="'.db_input(Format::phone($vars['mobile']),false).'"' + .' ,signature='.db_input($vars['signature']) + .' ,notes='.db_input($vars['notes']); if($vars['passwd1']) - $sql.=',passwd='.db_input(Passwd::hash($vars['passwd1'])); + $sql.=' ,passwd='.db_input(Passwd::hash($vars['passwd1'])); if(isset($vars['change_passwd'])) - $sql.=',change_passwd=1'; + $sql.=' ,change_passwd=1'; if($id) { $sql='UPDATE '.STAFF_TABLE.' '.$sql.' WHERE staff_id='.db_input($id); @@ -637,8 +645,8 @@ class Staff { return true; $errors['err']='Unable to update the user. Internal error occurred'; - }else{ - $sql='INSERT INTO '.STAFF_TABLE.' '.$sql.',created=NOW()'; + } else { + $sql='INSERT INTO '.STAFF_TABLE.' '.$sql.', created=NOW()'; if(db_query($sql) && ($uid=db_insert_id())) return $uid; @@ -647,7 +655,5 @@ class Staff { return false; } - - } ?> diff --git a/include/class.ticket.php b/include/class.ticket.php index edb9ac4608cd6df114bebd62c798d4b205b443aa..b0f54d2c761461ba987b0e4f91f86ad276d0290e 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -14,6 +14,7 @@ vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ include_once(INCLUDE_DIR.'class.staff.php'); +include_once(INCLUDE_DIR.'class.client.php'); include_once(INCLUDE_DIR.'class.team.php'); include_once(INCLUDE_DIR.'class.email.php'); include_once(INCLUDE_DIR.'class.dept.php'); @@ -24,6 +25,7 @@ include_once(INCLUDE_DIR.'class.attachment.php'); include_once(INCLUDE_DIR.'class.banlist.php'); include_once(INCLUDE_DIR.'class.template.php'); include_once(INCLUDE_DIR.'class.priority.php'); +include_once(INCLUDE_DIR.'class.sla.php'); class Ticket{ @@ -54,6 +56,7 @@ class Ticket{ var $dept; //Dept obj var $sla; // SLA obj var $staff; //Staff obj + var $client; //Client Obj var $team; //Team obj var $topic; //Topic obj var $tlock; //TicketLock obj @@ -123,6 +126,7 @@ class Ticket{ //Reset the sub classes (initiated ondemand)...good for reloads. $this->staff = null; + $this->client = null; $this->team = null; $this->dept = null; $this->sla = null; @@ -170,11 +174,23 @@ class Ticket{ if(!is_object($staff) && !($staff=Staff::lookup($staff))) return false; - return ($staff->canAccessDept($this->getDeptId()) + return ((!$staff->showAssignedOnly() && $staff->canAccessDept($this->getDeptId())) || ($this->getTeamId() && $staff->isTeamMember($this->getTeamId())) || $staff->getId()==$this->getStaffId()); } + function checkClientAccess($client) { + global $cfg; + + if(!is_object($client) && !($client=Client::lookup($client))) + return false; + + if(!strcasecmp($client->getEmail(),$this->getEmail())) + return true; + + return ($cfg && $cfg->showRelatedTickets() && $client->getTicketId()==$ticket->getExtId()); + } + //Getters function getId(){ return $this->id; @@ -273,6 +289,28 @@ class Ticket{ return $this->ht['ip_address']; } + function getHashtable() { + return $this->ht; + } + + function getUpdateInfo() { + + $info=array('name' => $this->getName(), + 'email' => $this->getEmail(), + 'phone' => $this->getPhone(), + 'phone_ext' => $this->getPhoneExt(), + 'subject' => $this->getSubject(), + 'source' => $this->getSource(), + 'topicId' => $this->getTopicId(), + 'priorityId' => $this->getPriorityId(), + 'slaId' => $this->getSLAId(), + 'duedate' => $this->getDueDate()?(Format::userdate('m/d/Y', Misc::db2gmtime($this->getDueDate()))):'', + 'time' => $this->getDueDate()?(Format::userdate('G:i', Misc::db2gmtime($this->getDueDate()))):'', + ); + + return $info; + } + function getLockId() { return $this->lock_id; } @@ -314,6 +352,14 @@ class Ticket{ return $this->dept; } + + function getClient() { + + if(!$this->client) + $this->client = Client::lookup($this->getExtId(), $this->getEmail()); + + return $this->client; + } function getStaffId(){ return $this->staff_id; @@ -350,6 +396,17 @@ class Ticket{ return ''; } + function getAssignees() { + + $assignees=array(); + if($staff=$this->getStaff()) + $assignees[] = $staff->getName(); + + if($team=$this->getTeam()) + $assignees[] = $team->getName(); + + return $assignees; + } function getTopicId(){ return $this->topic_id; @@ -437,8 +494,10 @@ class Ticket{ function getRelatedTicketsCount(){ - $sql='SELECT count(*) FROM '.TICKET_TABLE.' WHERE email='.db_input($this->getEmail()); - return db_count($sql); + $sql='SELECT count(*) FROM '.TICKET_TABLE + .' WHERE email='.db_input($this->getEmail()); + + return db_result(db_query($sql)); } function getThreadCount() { @@ -488,7 +547,7 @@ class Ticket{ ON (msg.ticket_id=attach.ticket_id AND msg.msg_id=attach.ref_id AND ref_type="M") ' .' WHERE msg.ticket_id='.db_input($this->getId()) .' GROUP BY msg.msg_id ' - .' ORDER BY msg.created DESC '; + .' ORDER BY msg.created ASC '; $messages=array(); if(($res=db_query($sql)) && db_num_rows($res)) @@ -709,6 +768,7 @@ class Ticket{ $sql.=' WHERE ticket_id='.db_input($this->getId()); + $this->track('closed'); return (db_query($sql) && db_affected_rows()); } @@ -722,6 +782,7 @@ class Ticket{ //TODO: log reopen event here + $this->track('reopened'); return (db_query($sql) && db_affected_rows()); } @@ -804,6 +865,43 @@ class Ticket{ return true; } + function onOpenLimit($sendNotice=true) { + global $cfg; + + //Log the limit notice as a warning for admin. + $msg=sprintf('Max open tickets (%d) reached for %s ', $cfg->getMaxOpenTickets(), $this->getEmail()); + sys::log(LOG_WARNING, 'Max. Open Tickets Limit ('.$this->getEmail().')', $msg); + + if(!$sendNotice || !$cfg->sendOverlimitNotice()) return true; + + //Send notice to user. + $dept = $this->getDept(); + + if(!$dept || !($tpl=$dept->getTemplate())) + $tpl=$cfg->getDefaultTemplate(); + + if(!$dept || !($email=$dept->getAutoRespEmail())) + $email=$cfg->getDefaultEmail(); + + if($tpl && ($msg=$tpl->getOverlimitMsgTemplate()) && $email) { + $body=$this->replaceTemplateVars($msg['body']); + $subj=$this->replaceTemplateVars($msg['subj']); + $body = str_replace('%signature',($dept && $dept->isPublic())?$dept->getSignature():'',$body); + $email->send($this->getEmail(), $subj, $body); + } + + $client= $this->getClient(); + + //Alert admin...this might be spammy (no option to disable)...but it is helpful..I think. + $msg='Max. open tickets reached for '.$this->getEmail()."\n" + .'Open ticket: '.$client->getNumOpenTickets()."\n" + .'Max Allowed: '.$cfg->getMaxOpenTickets()."\n\nNotice sent to the user."; + + Sys::alertAdmin('Overlimit Notice',$msg); + + return true; + } + function onResponse(){ db_query('UPDATE '.TICKET_TABLE.' SET isanswered=1,lastresponse=NOW(), updated=NOW() WHERE ticket_id='.db_input($this->getId())); } @@ -921,13 +1019,13 @@ class Ticket{ function onOverdue($whine=true) { global $cfg; - // TODO: log overdue events here + if($whine && ($sla=$this->getSLA()) && !$sla->alertOnOverdue()) + $whine = false; //check if we need to send alerts. if(!$whine || !$cfg->alertONOverdueTicket()) return true; - //Get template. if(!($tpl = $dept->getTemplate())) $tpl= $cfg->getDefaultTemplate(); @@ -1022,13 +1120,14 @@ class Ticket{ if($this->isOverdue()) return true; - $sql='UPDATE '.TICKET_TABLE.' SET isoverdue=1,updated=NOW() ' + $sql='UPDATE '.TICKET_TABLE.' SET isoverdue=1, updated=NOW() ' .' WHERE ticket_id='.db_input($this->getId()); if(!db_query($sql) || !db_affected_rows()) return false; $this->onOverdue($whine); + $this->track('overdue'); return true; } @@ -1095,6 +1194,7 @@ class Ticket{ } } + $this->track('transferred'); return true; } @@ -1108,6 +1208,7 @@ class Ticket{ $this->onAssign($note, $alert); + $this->track('assigned'); return true; } @@ -1126,6 +1227,7 @@ class Ticket{ $this->onAssign($note, $alert); + $this->track('assigned'); return true; } @@ -1193,7 +1295,9 @@ class Ticket{ $this->onMessage($autorespond); //must be called b4 sending alerts to staff. - if(!($tpl = $dept->getTemplate())) + $dept = $this->getDept(); + + if(!$dept || !($tpl = $dept->getTemplate())) $tpl= $cfg->getDefaultTemplate(); if(!($email=$cfg->getAlertEmail())) @@ -1327,6 +1431,22 @@ class Ticket{ return $this->postNote($title,$note,false,'system'); } + // History log -- used for statistics generation (pretty reports) + function track($state, $staff=null) { + global $thisstaff; + + if ($staff === null) { + if ($thisstaff) $staff=$thisstaff->getUserName(); + else $staff='SYSTEM'; # XXX: Security Violation ? + } + + return db_query('INSERT INTO '.TICKET_HISTORY_TABLE + .' SET ticket_id='.db_input($this->getId()) + .', timestamp=NOW(), state='.db_input($state) + .', staff='.db_input($staff)) + && db_affected_rows() == 1; + } + //Insert Internal Notes function postNote($title,$note,$alert=true,$poster='') { global $thisstaff,$cfg; @@ -1421,18 +1541,12 @@ class Ticket{ function deleteAttachments(){ - global $cfg; - + $deleted=0; - if(($attachments = $this->getAttachments())) { - //Clear reference table - XXX: some attachments might be orphaned - db_query('DELETE FROM '.TICKET_ATTACHMENT_TABLE.' WHERE ticket_id='.db_input($this->getId())); - //Delete file from DB IF NOT inuse. - foreach($attachments as $attachment) { - if(($file=AttachmentFile::lookup($attachment['file_id'])) && !$file->isInuse() && $file->delete()) - $deleted++; - } - } + // Clear reference table + $res=db_query('DELETE FROM '.TICKET_ATTACHMENT_TABLE.' WHERE ticket_id='.db_input($this->getId())); + if ($res && db_affected_rows()) + $deleted = AttachmentFile::deleteOrphans(); return $deleted; } @@ -1440,17 +1554,90 @@ class Ticket{ function delete(){ + $sql='DELETE FROM '.TICKET_TABLE.' WHERE ticket_id='.$this->getId().' LIMIT 1'; + if(!db_query($sql) || !db_affected_rows()) + return false; + + db_query('DELETE FROM '.TICKET_MESSAGE_TABLE.' WHERE ticket_id='.db_input($this->getId())); + db_query('DELETE FROM '.TICKET_RESPONSE_TABLE.' WHERE ticket_id='.db_input($this->getId())); + db_query('DELETE FROM '.TICKET_NOTE_TABLE.' WHERE ticket_id='.db_input($this->getId())); + $this->deleteAttachments(); + + return true; + } + + function update($vars, &$errors) { + + global $cfg, $thisstaff; + + if(!$cfg || !$thisstaff || !$thisstaff->canEditTickets()) + return false; + + $fields=array(); + $fields['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); + $fields['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); + $fields['subject'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required'); + $fields['topicId'] = array('type'=>'int', 'required'=>1, 'error'=>'Help topic required'); + $fields['slaId'] = array('type'=>'int', 'required'=>1, 'error'=>'SLA required'); + $fields['priorityId'] = array('type'=>'int', 'required'=>1, 'error'=>'Priority required'); + $fields['phone'] = array('type'=>'phone', 'required'=>0, 'error'=>'Valid phone # required'); + $fields['duedate'] = array('type'=>'date', 'required'=>0, 'error'=>'Invalid date - must be MM/DD/YY'); + + $fields['note'] = array('type'=>'text', 'required'=>1, 'error'=>'Reason for the update required'); + + if(!Validator::process($fields, $vars, $errors) && !$errors['err']) + $errors['err'] ='Missing or invalid data - check the errors and try again'; + + if($vars['duedate']) { + if($this->isClosed()) + $errors['duedate']='Duedate can NOT be set on a closed ticket'; + elseif(!$vars['time'] || strpos($vars['time'],':')===false) + $errors['time']='Select time'; + elseif(strtotime($vars['duedate'].' '.$vars['time'])===false) + $errors['duedate']='Invalid duedate'; + elseif(strtotime($vars['duedate'].' '.$vars['time'])<=time()) + $errors['duedate']='Due date must be in the future'; + } + + //Make sure phone extension is valid + if($vars['phone_ext'] ) { + if(!is_numeric($vars['phone_ext']) && !$errors['phone']) + $errors['phone']='Invalid phone ext.'; + elseif(!$vars['phone']) //make sure they just didn't enter ext without phone # + $errors['phone']='Phone number required'; + } + + if($errors) return false; + + $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW() ' + .' ,email='.db_input($vars['email']) + .' ,name='.db_input(Format::striptags($vars['name'])) + .' ,subject='.db_input(Format::striptags($vars['subject'])) + .' ,phone="'.db_input($vars['phone'],false).'"' + .' ,phone_ext='.db_input($vars['phone_ext']?$vars['phone_ext']:NULL) + .' ,priority_id='.db_input($vars['priorityId']) + .' ,topic_id='.db_input($vars['topicId']) + .' ,sla_id='.db_input($vars['slaId']) + .' ,duedate='.($vars['duedate']?db_input(date('Y-m-d G:i',Misc::dbtime($vars['duedate'].' '.$vars['time']))):'NULL'); + + if($vars['duedate']) { //We are setting new duedate... + $sql.=' ,isoverdue=0'; + } + + $sql.=' WHERE ticket_id='.db_input($this->getId()); + + if(!db_query($sql) || !db_affected_rows()) + return false; + + if(!$vars['note']) + $vars['note']=sprintf('Ticket Updated by %s', $thisstaff->getName()); + + $this->postNote('Ticket Updated', $vars['note']); + $this->reload(); - if(db_query('DELETE FROM '.TICKET_TABLE.' WHERE ticket_id='.$this->getId().' LIMIT 1') && db_affected_rows()): - db_query('DELETE FROM '.TICKET_MESSAGE_TABLE.' WHERE ticket_id='.db_input($this->getId())); - db_query('DELETE FROM '.TICKET_RESPONSE_TABLE.' WHERE ticket_id='.db_input($this->getId())); - db_query('DELETE FROM '.TICKET_NOTE_TABLE.' WHERE ticket_id='.db_input($this->getId())); - $this->deleteAttachments(); - return TRUE; - endif; - - return FALSE; + return true; } + /*============== Static functions. Use Ticket::function(params); ==================*/ function getIdByExtId($extid) { @@ -1463,10 +1650,14 @@ class Ticket{ - function lookup($id){ //Assuming local ID is the only lookup used! + function lookup($id) { //Assuming local ID is the only lookup used! return ($id && is_numeric($id) && ($ticket= new Ticket($id)) && $ticket->getId()==$id)?$ticket:null; } + function lookupByExtId($id) { + return self::lookup(self:: getIdByExtId($id)); + } + function genExtRandID() { global $cfg; @@ -1525,13 +1716,14 @@ class Ticket{ ON (assigned.ticket_id=ticket.ticket_id AND assigned.status=\'open\' AND assigned.staff_id='.db_input($staff->getId()).')' .' LEFT JOIN '.TICKET_TABLE.' closed ON (closed.ticket_id=ticket.ticket_id AND closed.status=\'closed\' AND closed.staff_id='.db_input($staff->getId()).')' - .' WHERE (ticket.dept_id IN('.implode(',',$staff->getDepts()).') OR ticket.staff_id='.db_input($staff->getId()); - - + .' WHERE (ticket.staff_id='.db_input($staff->getId()); + if(($teams=$staff->getTeams())) $sql.=' OR ticket.team_id IN('.implode(',', array_filter($teams)).')'; - + if(!$staff->showAssignedOnly()) //Staff with limited access just see Assigned tickets. + $sql.=' OR ticket.dept_id IN('.implode(',',$staff->getDepts()).') '; + $sql.=')'; @@ -1542,97 +1734,66 @@ class Ticket{ return db_fetch_array(db_query($sql)); } - function update($var,&$errors) { - global $cfg,$thisstaff; - - $fields=array(); - $fields['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); - $fields['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Email is required'); - $fields['note'] = array('type'=>'text', 'required'=>1, 'error'=>'Reason for the update required'); - $fields['subject'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required'); - $fields['topicId'] = array('type'=>'int', 'required'=>0, 'error'=>'Invalid Selection'); - $fields['pri'] = array('type'=>'int', 'required'=>0, 'error'=>'Invalid Priority'); - $fields['phone'] = array('type'=>'phone', 'required'=>0, 'error'=>'Valid phone # required'); - $fields['duedate'] = array('type'=>'date', 'required'=>0, 'error'=>'Invalid date - must be MM/DD/YY'); - - - $params = new Validator($fields); - if(!$params->validate($var)){ - $errors=array_merge($errors,$params->errors()); - } - - if($var['duedate']){ - if($this->isClosed()) - $errors['duedate']='Duedate can NOT be set on a closed ticket'; - elseif(!$var['time'] || strpos($var['time'],':')===false) - $errors['time']='Select time'; - elseif(strtotime($var['duedate'].' '.$var['time'])===false) - $errors['duedate']='Invalid duedate'; - elseif(strtotime($var['duedate'].' '.$var['time'])<=time()) - $errors['duedate']='Due date must be in the future'; - } - //Make sure phone extension is valid - if($var['phone_ext'] ) { - if(!is_numeric($var['phone_ext']) && !$errors['phone']) - $errors['phone']='Invalid phone ext.'; - elseif(!$var['phone']) //make sure they just didn't enter ext without phone # - $errors['phone']='Phone number required'; - } + /* Quick client's tickets stats + @email - valid email. + */ + function getClientStats($email) { - $cleartopic=false; - $topicDesc=''; - if($var['topicId'] && ($topic= new Topic($var['topicId'])) && $topic->getId()) { - $topicDesc=$topic->getName(); - }elseif(!$var['topicId'] && $this->getTopicId()){ - $topicDesc=''; - $cleartopic=true; - } + if(!$email || !Validator::is_email($email)) + return null; - - if(!$errors){ - $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW() '. - ',email='.db_input($var['email']). - ',name='.db_input(Format::striptags($var['name'])). - ',subject='.db_input(Format::striptags($var['subject'])). - ',phone="'.db_input($var['phone'],false).'"'. - ',phone_ext='.db_input($var['phone_ext']?$var['phone_ext']:NULL). - ',priority_id='.db_input($var['pri']). - ',topic_id='.db_input($var['topicId']). - ',duedate='.($var['duedate']?db_input(date('Y-m-d G:i',Misc::dbtime($var['duedate'].' '.$var['time']))):'NULL'); - if($var['duedate']) { //We are setting new duedate... - $sql.=',isoverdue=0'; - } - if($topicDesc || $cleartopic) { //we're overwriting previous topic. - $sql.=',helptopic='.db_input($topicDesc); - } - $sql.=' WHERE ticket_id='.db_input($this->getId()); - //echo $sql; - if(db_query($sql)){ - $this->postNote('Ticket Updated',$var['note']); - $this->reload(); - return true; - } - } + $sql='SELECT count(open.ticket_id) as open, count(closed.ticket_id) as closed ' + .' FROM '.TICKET_TABLE.' ticket ' + .' LEFT JOIN '.TICKET_TABLE.' open + ON (open.ticket_id=ticket.ticket_id AND open.status=\'open\') ' + .' LEFT JOIN '.TICKET_TABLE.' closed + ON (closed.ticket_id=ticket.ticket_id AND closed.status=\'closed\')' + .' WHERE ticket.email='.db_input($email); - return false; + return db_fetch_array(db_query($sql)); } - /* * The mother of all functions...You break it you fix it! * - * $autorespond and $alertstaff overwrites config info... + * $autorespond and $alertstaff overwrites config settings... */ - function create($vars,&$errors, $origin, $autorespond=true, $alertstaff=true) { + function create($vars, &$errors, $origin, $autorespond=true, $alertstaff=true) { global $cfg,$thisclient,$_FILES; - //Make sure the email is not banned - if ($vars['email'] && EmailFilter::isBanned($vars['email'])) { + //Check for 403 + if ($vars['email'] && Validator::is_email($vars['email'])) { + + //Make sure the email address is not banned + if(EmailFilter::isBanned($vars['email'])) { + $errors['err']='Ticket denied. Error #403'; + Sys::log(LOG_WARNING,'Ticket denied','Banned email - '.$vars['email']); + return 0; + } + + //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL) + if($cfg->getMaxOpenTickets()>0 && strcasecmp($origin,'staff') + && ($client=Client::lookupByEmail($vars['email'])) + && ($openTickets=$client->getNumOpenTickets()) + && ($opentickets>=$cfg->getMaxOpenTickets()) ) { + + $errors['err']="You've reached the maximum open tickets allowed."; + Sys::log(LOG_WARNING, 'Ticket denied -'.$vars['email'], + sprintf('Max open tickets (%d) reached for %s ', $cfg->getMaxOpenTickets(), $vars['email'])); + + return 0; + } + } + // Make sure email contents should not be rejected + if (($email_filter=new EmailFilter($vars)) + && ($filter=$email_filter->shouldReject())) { $errors['err']='Ticket denied. Error #403'; - Sys::log(LOG_WARNING,'Ticket denied','Banned email - '.$vars['email']); + Sys::log(LOG_WARNING,'Ticket denied', + sprintf('Banned email - %s by filter "%s"', $vars['email'], + $filter->getName())); return 0; - } + } $id=0; $fields=array(); @@ -1646,7 +1807,7 @@ class Ticket{ break; case 'staff': $fields['deptId'] = array('type'=>'int', 'required'=>1, 'error'=>'Dept. required'); - $fields['topicId'] = array('type'=>'int', 'required'=>1, 'error'=>'Topic required'); + $fields['topicId'] = array('type'=>'int', 'required'=>1, 'error'=>'Topic required'); $fields['duedate'] = array('type'=>'date', 'required'=>0, 'error'=>'Invalid date - must be MM/DD/YY'); case 'api': $fields['source'] = array('type'=>'string', 'required'=>1, 'error'=>'Indicate source'); @@ -1656,10 +1817,10 @@ class Ticket{ break; default: # TODO: Return error message - $errors['origin'] = 'Invalid origin given'; + $errors['err']=$errors['origin'] = 'Invalid origin given'; } - $fields['pri'] = array('type'=>'int', 'required'=>0, 'error'=>'Invalid Priority'); - $fields['phone'] = array('type'=>'phone', 'required'=>0, 'error'=>'Valid phone # required'); + $fields['priorityId'] = array('type'=>'int', 'required'=>0, 'error'=>'Invalid Priority'); + $fields['phone'] = array('type'=>'phone', 'required'=>0, 'error'=>'Valid phone # required'); if(!Validator::process($fields, $vars, $errors) && !$errors['err']) $errors['err'] ='Missing or invalid data - check the errors and try again'; @@ -1682,62 +1843,19 @@ class Ticket{ $errors['duedate']='Due date must be in the future'; } - //check attachment..if any is set ...only set on webbased tickets.. - //XXX:?? Create ticket anyway and simply drop the attachments?? We're already doing so with emails. - if($_FILES['attachment']['name'] && $cfg->allowOnlineAttachments()) { - if(!$cfg->canUploadFileType($_FILES['attachment']['name'])) - $errors['attachment']='Invalid file type [ '.Format::htmlchars($_FILES['attachment']['name']).' ]'; - elseif($_FILES['attachment']['size']>$cfg->getMaxFileSize()) - $errors['attachment']='File is too big. Max '.$cfg->getMaxFileSize().' bytes allowed'; - } - # Perform email filter actions on the new ticket arguments XXX: Move filter to the top and check for reject... - if (!$errors && $ef = new EmailFilter($vars)) $ef->apply($vars); + if (!$errors && $email_filter) $email_filter->apply($vars); # Some things will need to be unpacked back into the scope of this # function if (isset($vars['autorespond'])) $autorespond=$vars['autorespond']; - //check ticket limits..if limit set is >0 - //TODO: Base ticket limits on SLA... XXX: move it elsewhere?? - if($vars['email'] && !$errors && $cfg->getMaxOpenTickets()>0 && strcasecmp($origin,'staff')){ - $openTickets=Ticket::getOpenTicketsByEmail($vars['email']); - if($openTickets>=$cfg->getMaxOpenTickets()) { - $errors['err']="You've reached the maximum open tickets allowed."; - //Send the notice only once (when the limit is reached) incase of autoresponders at client end. - if($cfg->getMaxOpenTickets()==$openTickets && $cfg->sendOverlimitNotice()) { - if($vars['deptId']) - $dept =Dept::lookup($vars['deptId']); - - if(!$dept || !($tpl=$dept->getTemplate())) - $tpl=$cfg->getDefaultTemplate(); - - if(!$dept || !($email=$dept->getAutoRespEmail())) - $email=$cfg->getDefaultEmail(); - - if($tpl && ($msg=$tpl->getOverlimitMsgTemplate()) && $email) { - $body = str_replace('%name', $vars['name'],$msg['body']); - $body = str_replace('%email',$vars['email'],$msg['body']); - $body = str_replace('%url', $cfg->getBaseUrl(),$body); - $body = str_replace('%signature',($dept && $dept->isPublic())?$dept->getSignature():'',$body); - $email->send($vars['email'],$msg['subj'],$body); - } - - //Log + Alert admin...this might be spammy (no option to disable)...but it is helpful..I think. - $msg='Support ticket request denied for '.$vars['email']."\n". - 'Open ticket:'.$openTickets."\n". - 'Max Allowed:'.$cfg->getMaxOpenTickets()."\n\nNotice only sent once"; - Sys::log(LOG_CRIT,'Overlimit Notice',$msg); - } - } - } - //Any error above is fatal. if($errors) return 0; // OK...just do it. $deptId=$vars['deptId']; //pre-selected Dept if any. - $priorityId=$vars['pri']; + $priorityId=$vars['priorityId']; $source=ucfirst($vars['source']); $topic=NULL; // Intenal mapping magic...see if we need to overwrite anything @@ -1800,14 +1918,6 @@ class Ticket{ //post the message. $msgid=$ticket->postMessage($vars['message'],$source,$vars['mid'],$vars['header'],true); - //TODO: recover from postMessage error?? - - //Upload attachments...web based. - XXX: Assumes user uploaded attachments!! XXX: move it to client interface. - if($_FILES['attachment']['name'] && $cfg->allowOnlineAttachments() && $msgid) { - if(!$cfg->allowAttachmentsOnlogin() || ($cfg->allowAttachmentsOnlogin() && ($thisuser && $thisuser->isValid()))) { - $ticket->uploadAttachment($_FILES['attachment'],$msgid,'M'); - } - } // Configure service-level-agreement for this ticket $ticket->selectSLAId($vars['slaId']); @@ -1844,6 +1954,15 @@ class Ticket{ $ticket->onNewTicket($vars['message'], $autorespond, $alertstaff); + /************ check if the user JUST reached the max. open tickets limit **********/ + if($cfg->getMaxOpenTickets()>0 + && ($client=$ticket->getClient()) + && ($client->getNumOpenTickets()==$cfg->getMaxOpenTickets())) { + $ticket->onOpenLimit(($autorespond && strcasecmp($origin, 'staff'))); + } + + /* Phew! ... time for tea (KETEPA) */ + return $ticket; } @@ -1925,23 +2044,24 @@ class Ticket{ } - function checkOverdue(){ + function checkOverdue() { - $sql='SELECT ticket_id FROM '.TICKET_TABLE.' T1 JOIN '. - SLA_TABLE.' T2 ON T1.sla_id=T2.id '. - 'WHERE status=\'open\' AND isoverdue=0 '. - ' AND ((reopened is NULL AND duedate is NULL AND TIME_TO_SEC(TIMEDIFF(NOW(),T1.created))>=grace_period*3600)'. - ' OR (reopened is NOT NULL AND duedate is NULL AND TIME_TO_SEC(TIMEDIFF(NOW(),reopened))>=grace_period*3600)'. - ' OR (duedate is NOT NULL AND duedate<NOW()) '. - ') ORDER BY T1.created LIMIT 50'; //Age upto 50 tickets at a time? + $sql='SELECT ticket_id FROM '.TICKET_TABLE.' T1 ' + .' JOIN '.SLA_TABLE.' T2 ON (T1.sla_id=T2.id) ' + .' WHERE status=\'open\' AND isoverdue=0 ' + .' AND ((reopened is NULL AND duedate is NULL AND TIME_TO_SEC(TIMEDIFF(NOW(),T1.created))>=T2.grace_period*3600) ' + .' OR (reopened is NOT NULL AND duedate is NULL AND TIME_TO_SEC(TIMEDIFF(NOW(),reopened))>=T2.grace_period*3600) ' + .' OR (duedate is NOT NULL AND duedate<NOW()) ' + .' ) ORDER BY T1.created LIMIT 50'; //Age upto 50 tickets at a time? //echo $sql; - if(($stale=db_query($sql)) && db_num_rows($stale)){ - while(list($id)=db_fetch_row($stale)){ + if(($res=db_query($sql)) && db_num_rows($res)) { + while(list($id)=db_fetch_row($res)) { if(($ticket=Ticket::lookup($id)) && $ticket->markOverdue()) - $ticket->logActivity('Ticket Marked Overdue','Ticket flagged as overdue by the system.'); - # TODO: Send out notifications about the now-overdue - # ticket XXX: markOverdue sends out notifications. + $ticket->logActivity('Ticket Marked Overdue', 'Ticket flagged as overdue by the system.'); } + } else { + //TODO: Trigger escalation on already overdue tickets - make sure last overdue event > grace_period. + } } diff --git a/include/class.topic.php b/include/class.topic.php index 59159c8c90a5501150f22342fdf886ed5a729330..40ab8096bc1831b821ea37754b18e3d1a1a22e3e 100644 --- a/include/class.topic.php +++ b/include/class.topic.php @@ -135,6 +135,10 @@ class Topic { return $topics; } + function getPublicHelpTopics() { + return self::getHelpTopics(true); + } + function getIdByName($topic){ $sql='SELECT topic_id FROM '.TOPIC_TABLE.' WHERE topic='.db_input($topic); diff --git a/include/class.usersession.php b/include/class.usersession.php index 9a8283e3741a9b97f59a06649293831108634f93..c12f3a0d8aaf70988cbe2c022c8346b3eccdeccd 100644 --- a/include/class.usersession.php +++ b/include/class.usersession.php @@ -107,8 +107,8 @@ class ClientSession extends Client { var $session; - function ClientSession($email,$id){ - parent::Client($email,$id); + function ClientSession($email, $id){ + parent::Client($id, $email); $this->session= new UserSession($email); } diff --git a/include/client/header.inc.php b/include/client/header.inc.php index ad88a0c80d13cb9655a5b113d28c5de94943b102..beefb3bf3c74581da257a6ef684ed5553d5d96c1 100644 --- a/include/client/header.inc.php +++ b/include/client/header.inc.php @@ -12,7 +12,7 @@ header("Content-Type: text/html; charset=UTF-8\r\n"); <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <link rel="stylesheet" href="<?php echo ASSETS_PATH; ?>css/theme.css" media="screen"> <link rel="stylesheet" href="<?php echo ASSETS_PATH; ?>css/print.css" media="print"> - <script src="./js/jquery.min.js"></script> + <script src="./js/jquery-1.7.2.min.js"></script> <script src="./js/osticket.js"></script> </head> <body> @@ -21,8 +21,14 @@ header("Content-Type: text/html; charset=UTF-8\r\n"); <a id="logo" href="<?php echo ROOT_PATH; ?>index.php" title="Support Center"><img src="<?php echo ASSETS_PATH; ?>images/logo.png" border=0 alt="Support Center"></a> <p> <?php - if($thisclient && is_object($thisclient) && $thisclient->isValid()) { ?> - <a href="<?php echo ROOT_PATH; ?>tickets.php">My Tickets</a> - + if($thisclient && is_object($thisclient) && $thisclient->isValid()) { + echo $thisclient->getName().' - '; + ?> + <?php + if($cfg->showRelatedTickets()) {?> + <a href="<?php echo ROOT_PATH; ?>tickets.php">My Tickets <b>(<?php echo $thisclient->getNumTickets(); ?>)</b></a> - + <?php + } ?> <a href="<?php echo ROOT_PATH; ?>logout.php">Log Out</a> <?php }elseif($nav){ ?> diff --git a/include/client/kb-category.inc.php b/include/client/kb-category.inc.php index f166fb5bdf8a1f528e56b965c5c32dca3e16dd8f..50a51782f214b8fc28b78f54afdd005c3f1a71df 100644 --- a/include/client/kb-category.inc.php +++ b/include/client/kb-category.inc.php @@ -1,34 +1,31 @@ <?php if(!defined('OSTCLIENTINC') || !$category || !$category->isPublic()) die('Access Denied'); - ?> -<div style="width:700;padding-top:10px; float:left;"> - <h2>Frequently Asked Questions</h2> -</div> -<div style="float:right;text-align:right;padding-top:5px;padding-right:5px;"> </div> -<div class="clear"></div> -<br> -<div><strong><?php echo $category->getName() ?></strong></div> +<h1><strong><?php echo $category->getName() ?></strong></h1> <p> <?php echo Format::safe_html($category->getDescription()); ?> </p> <hr> <?php -$sql='SELECT faq.faq_id, question ' +$sql='SELECT faq.faq_id, question, count(attach.file_id) as attachments ' .' FROM '.FAQ_TABLE.' faq ' .' LEFT JOIN '.FAQ_ATTACHMENT_TABLE.' attach ON(attach.faq_id=faq.faq_id) ' .' WHERE faq.ispublished=1 AND faq.category_id='.db_input($category->getId()) .' GROUP BY faq.faq_id'; if(($res=db_query($sql)) && db_num_rows($res)) { - echo '<div id="faq"> + echo ' + <h2>Frequently Asked Questions</h2> + <div id="faq"> <ol>'; while($row=db_fetch_array($res)) { + $attachments=$row['attachments']?'<span class="Icon file"></span>':''; echo sprintf(' - <li><a href="faq.php?id=%d" >%s</a></li>', - $row['faq_id'],Format::htmlchars($row['question'])); + <li><a href="faq.php?id=%d" >%s %s</a></li>', + $row['faq_id'],Format::htmlchars($row['question']), $attachments); } echo ' </ol> - </div>'; + </div> + <p><a class="back" href="index.php">« Go Back</a></p>'; }else { echo '<strong>Category does not have any FAQs. <a href="index.php">Back To Index</a></strong>'; } diff --git a/include/client/knowledgebase.inc.php b/include/client/knowledgebase.inc.php index 0af99ba21b1d92532a6063e175e9cf0fdc69c2c9..83484e95de818d732a67fed39b980fd5e9262e95 100644 --- a/include/client/knowledgebase.inc.php +++ b/include/client/knowledgebase.inc.php @@ -1,5 +1,6 @@ <?php if(!defined('OSTCLIENTINC')) die('Access Denied'); + ?> <h1>Frequently Asked Questions</h1> <form action="index.php" method="get" style="padding-top:15px;"> @@ -14,6 +15,7 @@ if(!defined('OSTCLIENTINC')) die('Access Denied'); $sql='SELECT category_id, name, count(faq.category_id) as faqs ' .' FROM '.FAQ_CATEGORY_TABLE.' cat ' .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' + .' WHERE cat.ispublic=1 AND faq.ispublished=1 ' .' GROUP BY cat.category_id ' .' HAVING faqs>0 ' .' ORDER BY cat.name DESC '; @@ -40,6 +42,7 @@ if(!defined('OSTCLIENTINC')) die('Access Denied'); $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' .' FROM '.TOPIC_TABLE.' ht ' .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' + .' WHERE ht.ispublic=1 ' .' GROUP BY ht.topic_id ' .' HAVING faqs>0 ' .' ORDER BY ht.topic DESC '; @@ -88,7 +91,7 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search. } else { //Category Listing. $sql='SELECT cat.category_id, cat.name, cat.description, cat.ispublic, count(faq.faq_id) as faqs ' .' FROM '.FAQ_CATEGORY_TABLE.' cat ' - .' LEFT JOIN '.FAQ_TABLE.' faq ON(faq.category_id=cat.category_id) ' + .' LEFT JOIN '.FAQ_TABLE.' faq ON(faq.category_id=cat.category_id AND faq.ispublished=1) ' .' WHERE cat.ispublic=1 ' .' GROUP BY cat.category_id ' .' HAVING faqs>0 ' diff --git a/include/client/open.inc.php b/include/client/open.inc.php index fd31bc9b81f907204134114e1aed59d3fc728cb6..9c2a82b4706e1fc83253471eea8224e47cd7b382 100644 --- a/include/client/open.inc.php +++ b/include/client/open.inc.php @@ -1,21 +1,40 @@ <?php -if(!defined('OSTCLIENTINC')) die('Access Denied'); //Say bye to our friend.. +if(!defined('OSTCLIENTINC')) die('Access Denied!'); +$info=array(); +if($thisclient && $thisclient->isValid()) { + $info=array('name'=>$thisclient->getName(), + 'email'=>$thisclient->getEmail(), + 'phone'=>$thisclient->getPhone(), + 'phone_ext'=>$thisclient->getPhoneExt()); +} -$info=($_POST && $errors)?Format::htmlchars($_POST):array(); +$info=($_POST && $errors)?Format::htmlchars($_POST):$info; ?> - <h1>Open a New Ticket</h1> <p>Please fill in the form below to open a new ticket.</p> <form id="ticketForm" method="post" action="open.php" enctype="multipart/form-data"> + <input type="hidden" name="a" value="open"> <div> <label for="name" class="required">Full Name:</label> + <?php + if($thisclient && $thisclient->isValid()) { + echo $thisclient->getName(); + } else { ?> <input id="name" type="text" name="name" size="30" value="<?php echo $info['name']; ?>"> <font class="error">* <?php echo $errors['name']; ?></font> + <?php + } ?> </div> <div> - <label for="email" class="required">E-Mail Address:</label> + <label for="email" class="required">Email Address:</label> + <?php + if($thisclient && $thisclient->isValid()) { + echo $thisclient->getEmail(); + } else { ?> <input id="email" type="text" name="email" size="30" value="<?php echo $info['email']; ?>"> <font class="error">* <?php echo $errors['email']; ?></font> + <?php + } ?> </div> <div> <label for="phone">Telephone:</label> @@ -30,16 +49,14 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array(); <select id="topicId" name="topicId"> <option value="" selected="selected">— Select a Help Topics —</option> <?php - $sql='SELECT topic_id,topic FROM '.TOPIC_TABLE.' WHERE isactive=1 ORDER BY topic'; - if(($res=db_query($sql)) && db_num_rows($res)) { - while (list($topicId,$topic) = db_fetch_row($res)){ - $selected = ($info['topicId']==$topicId)?'selected="selected"':''; ?> - <option value="<?php echo $topicId; ?>"<?php echo $selected; ?>><?php echo $topic; ?></option> - <?php - } - }else{ ?> - <option value="0" >General Inquiry</option> - <?php } ?> + if($topics=Topic::getPublicHelpTopics()) { + foreach($topics as $id =>$name) { + echo sprintf('<option value="%d" %s>%s</option>', + $id, ($info['topicId']==$id)?'selected="selected"':'', $name); + } + } else { ?> + <option value="0" >General Inquiry</option> + <?php } ?> </select> <font class="error">* <?php echo $errors['topicId']; ?></font> </div> @@ -58,35 +75,41 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array(); <textarea id="message" cols="60" rows="8" name="message"><?php echo $info['message']; ?></textarea> </div> <?php if(($cfg->allowOnlineAttachments() && !$cfg->allowAttachmentsOnlogin()) - || ($cfg->allowAttachmentsOnlogin() && ($thisuser && $thisuser->isValid()))) { ?> + || ($cfg->allowAttachmentsOnlogin() && ($thisclient && $thisclient->isValid()))) { ?> <div> - <label for="attachment">Attachments:</label> - <input id="attachment" type="file" name="attachment"><font class="error"> <?php echo $errors['attachment']; ?></font> + <label for="attachments">Attachments:</label> + <span id="uploads"></span> + <input type="file" class="multifile" name="attachments[]" id="attachments" size="30" value="" /> + <font class="error"> <?php echo $errors['attachments']; ?></font> </div> <?php } ?> <?php - if($cfg && $cfg->allowPriorityChange()) { - $sql='SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE.' WHERE ispublic=1 ORDER BY priority_urgency DESC'; - if(($res=db_query($sql)) && db_num_rows($res)) {?> - <div> + if($cfg->allowPriorityChange() && ($priorities=Priority::getPriorities())) { ?> + <div> <label for="priority">Ticket Priority:</label> <select id="priority" name="priorityId"> - <?php + <?php if(!$info['priorityId']) - $info['priorityId']=$cfg->getDefaultPriorityId(); //use system's default priority. - while($row=db_fetch_array($res)){ - $selected=$info['priorityId']==$row['priority_id']?'selected="selected"':''; - ?> - <option value="<?php echo $row['priority_id']; ?>" <?php echo $selected; ?> ><?php echo $row['priority_desc']; ?></option> - <?php } ?> + $info['priorityId'] = $cfg->getDefaultPriorityId(); //System default. + foreach($priorities as $id =>$name) { + echo sprintf('<option value="%d" %s>%s</option>', + $id, ($info['priorityId']==$id)?'selected="selected"':'', $name); + + } + ?> + + + </select> + <font class="error"> <?php echo $errors['priorityId']; ?></font> - </div> + + </div> <?php - } - } ?> + } + ?> <?php - if($cfg && $cfg->enableCaptcha() && (!$thisuser || !$thisuser->isValid())) { + if($cfg && $cfg->enableCaptcha() && (!$thisclient || !$thisclient->isValid())) { if($_POST && $errors && !$errors['captcha']) $errors['captcha']='Please re-enter the text again'; ?> @@ -101,7 +124,7 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array(); <?php } ?> <br> - <p> + <p style="padding-left:150px;"> <input type="submit" value="Create Ticket"> <input type="reset" value="Reset"> <input type="button" value="Cancel" onClick='window.location.href="index.php"'> diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..a360217167bde83dedcb4decb339677e3c5370d6 --- /dev/null +++ b/include/client/tickets.inc.php @@ -0,0 +1,172 @@ +<?php +if(!defined('OSTCLIENTINC') || !is_object($thisclient) || !$thisclient->isValid() || !$cfg->showRelatedTickets()) die('Access Denied'); + +$qstr='&'; //Query string collector +$status=null; +if(isset($_REQUEST['status'])) { //Query string status has nothing to do with the real status used below. + $qstr.='status='.urlencode($_REQUEST['status']); + //Status we are actually going to use on the query...making sure it is clean! + switch(strtolower($_REQUEST['status'])) { + case 'open': + case 'closed': + $status=strtolower($_REQUEST['status']); + break; + default: + $status=''; //ignore + } +} elseif($thisclient->getNumOpenTickets()) { + $status='open'; //Defaulting to open +} + +$sortOptions=array('id'=>'ticketID', 'name'=>'ticket.name', 'subject'=>'ticket.subject', + 'email'=>'ticket.email', 'status'=>'ticket.status', 'dept'=>'dept_name','date'=>'ticket.created'); +$orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); +//Sorting options... +$order_by=$order=null; +$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'date'; +if($sort && $sortOptions[$sort]) + $order_by =$sortOptions[$sort]; + +$order_by=$order_by?$order_by:'ticket_created'; +if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) + $order=$orderWays[strtoupper($_REQUEST['order'])]; + +$order=$order?$order:'ASC'; +if($order_by && strpos($order_by,',')) + $order_by=str_replace(','," $order,",$order_by); + +$x=$sort.'_sort'; +$$x=' class="'.strtolower($order).'" '; + +$qselect='SELECT ticket.ticket_id,ticket.ticketID,ticket.dept_id,isanswered, dept.ispublic, ticket.subject, ticket.name, ticket.email '. + ',dept_name,ticket. status, ticket.source, ticket.created '; + +$qfrom='FROM '.TICKET_TABLE.' ticket ' + .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) '; + +$qwhere =' WHERE ticket.email='.db_input($thisclient->getEmail()); + +if($status){ + $qwhere.=' AND ticket.status='.db_input($status); +} + +$search=($_REQUEST['a']=='search' && $_REQUEST['q']); +if($search) { + $qstr.='&a='.urlencode($_REQUEST['a']).'&q='.urlencode($_REQUEST['q']); + if(is_numeric($_REQUEST['q'])) { + $qwhere.=" AND ticket.ticketID LIKE '$queryterm%'"; + } else {//Deep search! + $queryterm=db_real_escape($_REQUEST['q'],false); //escape the term ONLY...no quotes. + $qwhere.=' AND ( ' + ." ticket.subject LIKE '%$queryterm%'" + ." OR message.message LIKE '%$queryterm%'" + ." OR response.response LIKE '%$queryterm%'" + .' ) '; + $deep_search=true; + //Joins needed for search + $qfrom.=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )' + .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )'; + } +} + +$total=db_count('SELECT count(DISTINCT ticket.ticket_id) '.$qfrom.' '.$qwhere); +$pageNav=new Pagenate($total,$page, PAGE_LIMIT); +$pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); + +//more stuff... +$qselect.=' ,count(attach_id) as attachments '; +$qfrom.=' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON ticket.ticket_id=attach.ticket_id '; +$qgroup=' GROUP BY ticket.ticket_id'; + +$query="$qselect $qfrom $qwhere $qgroup ORDER BY $order_by $order LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); +//echo $query; +$res = db_query($query); +$showing=($res && db_num_rows($res))?$pageNav->showing():""; +$showing.=($status)?(' '.ucfirst($status).' Tickets'):' All Tickets'; +if($search) + $showing="Search Results: $showing"; + +$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting + +?> +<h1>My Tickets</h1> +<br> +<form action="tickets.php" method="get" id="ticketSearchForm"> + <input type="hidden" name="a" value="search"> + <input type="text" name="q" size="20" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> + <select name="status"> + <option value="">— Any Status —</option> + <option value="open" <?php echo ($status=='open')?'selected="selected"':'';?>>Open</option> + <option value="closed" <?php echo ($status=='closed')?'selected="selected"':'';?>>Closed</option> + </select> + <input type="submit" value="Go"> +</form> +<a class="refresh" href="<?php echo $_SERVER['REQUEST_URI']; ?>">Refresh</a> +<table id="ticketTable" width="800" border="0" cellspacing="0" cellpadding="0"> + <caption><?php echo $showing; ?></caption> + <thead> + <tr> + <th width="70" nowrap> + <a href="tickets.php?sort=ID&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Ticket ID">Ticket #</a> + </th> + <th width="100"> + <a href="tickets.php?sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Date">Create Date</a> + </th> + <th width="80"> + <a href="tickets.php?sort=status&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Status">Status</a> + </th> + <th width="240"> + <a href="tickets.php?sort=subj&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Subject">Subject</a> + </th> + <th width="150"> + <a href="tickets.php?sort=dept&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Department">Department</a> + </th> + <th width="150">Phone Number</th> + </tr> + </thead> + <tbody> + <?php + if($res && ($num=db_num_rows($res))) { + $defaultDept=Dept::getDefaultDeptName(); //Default public dept. + while ($row = db_fetch_array($res)) { + $dept=$row['ispublic']?$row['dept_name']:$defaultDept; + $subject=Format::htmlchars(Format::truncate($row['subject'],40)); + if($row['attachments']) + $subject.=' <span class="Icon file"></span>'; + + $ticketID=$row['ticketID']; + if($row['isanswered'] && !strcasecmp($row['status'],'open')) { + $subject="<b>$subject</b>"; + $ticketID="<b>$ticketID</b>"; + } + $phone=Format::phone($row['phone']); + if($row['phone_ext']) + $phone.=' '.$row['phone_ext']; + ?> + <tr id="<?php echo $row['ticketID']; ?>"> + <td class="centered"> + <a class="Icon <?php echo strtolower($row['source']); ?>Ticket" title="<?php echo $row['email']; ?>" + href="tickets.php?id=<?php echo $row['ticketID']; ?>"><?php echo $ticketID; ?></a> + </td> + <td> <?=Format::db_date($row['created'])?></td> + <td> <?=ucfirst($row['status'])?></td> + <td> + <a href="tickets.php?id=<?php echo $row['ticketID']; ?>"><?php echo $subject; ?></a> + </td> + <td> <?=Format::truncate($dept,30)?></td> + <td><?php echo $phone; ?></td> + </tr> + <?php + } + + } else { + echo '<tr><td colspan="7">Your query did not match any records</td></tr>'; + } + ?> + </tbody> +</table> +<?php +if($res && $num>0) { + echo '<div> Page:'.$pageNav->getPageLinks().' </div>'; +} +?> diff --git a/include/client/view.inc.php b/include/client/view.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..e720ed96bffa58c5d7321e7fe2544c7829a86678 --- /dev/null +++ b/include/client/view.inc.php @@ -0,0 +1,157 @@ +<?php +if(!defined('OSTCLIENTINC') || !$thisclient || !$ticket || !$ticket->checkClientAccess($thisclient)) die('Access Denied!'); + +$info=($_POST && $errors)?Format::htmlchars($_POST):array(); + +$dept = $ticket->getDept(); +//Making sure we don't leak out internal dept names +if(!$dept || !$dept->isPublic()) + $dept = $cfg->getDefaultDept(); + +?> +<table width="800" cellpadding="1" cellspacing="0" border="0" id="ticketInfo"> + <tr> + <td colspan="2" width="100%"> + <h1> + Ticket #<?php echo $ticket->getExtId(); ?> + <a href="view.php?id=<?php echo $ticket->getExtId(); ?>" title="Reload"><span class="Icon refresh"> </span></a> + </h1> + </td> + </tr> + <tr> + <td width="50%"> + <table class="infoTable" cellspacing="1" cellpadding="3" width="100%" border="0"> + <tr> + <th width="100">Ticket Status:</th> + <td><?php echo ucfirst($ticket->getStatus()); ?></td> + </tr> + <tr> + <th>Department:</th> + <td><?php echo Format::htmlchars($dept->getName()); ?></td> + </tr> + <tr> + <th>Create Date:</th> + <td><?php echo Format::db_datetime($ticket->getCreateDate()); ?></td> + </tr> + </table> + </td> + <td width="50%"> + <table class="infoTable" cellspacing="1" cellpadding="3" width="100%" border="0"> + <tr> + <th width="100">Name:</th> + <td><?php echo ucfirst($ticket->getName()); ?></td> + </tr> + <tr> + <th width="100">Email:</th> + <td><?php echo Format::htmlchars($ticket->getEmail()); ?></td> + </tr> + <tr> + <th>Phone:</th> + <td><?php echo $ticket->getPhoneNumber(); ?></td> + </tr> + </table> + </td> + </tr> +</table> +<br> +<h2>Subject:<?php echo Format::htmlchars($ticket->getSubject()); ?></h2> +<br> +<span class="Icon thread">Ticket Thread</span> +<div id="ticketThread"> +<?php +if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { + + foreach($messages as $message) {?> + + <table class="message" cellspacing="0" cellpadding="1" width="800" border="0"> + + <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr> + + <tr><td><?php echo Format::display($message['message']); ?></td></tr> + + <?php + + if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) { ?> + + <tr><td class="info"><?php echo $links; ?></td></tr> + + <?php + + } ?> + + </table> + <?php + if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) { + foreach($responses as $resp) { + $staff=$cfg->hideStaffName()?'staff':Format::htmlchars($resp['staff_name']); + ?> + <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0"> + <tr> + <th><?php echo Format::db_datetime($resp['created']);?> - <?php echo $staff; ?></th> + </tr> + <tr><td><?php echo Format::display($resp['response']); ?></td></tr> + <?php + if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?> + <tr><td class="info"><?php echo $links; ?></td></tr> + <?php + }?> + </table> + <? + } + } + } +} +?> +</div> +<div class="clear" style="padding-bottom:10px;"></div> +<?php if($errors['err']) { ?> + <div id="msg_error"><?php echo $errors['err']; ?></div> +<?php }elseif($msg) { ?> + <div id="msg_notice"><?php echo $msg; ?></div> +<?php }elseif($warn) { ?> + <div id="msg_warning"><?php echo $warn; ?></div> +<?php } ?> +<form id="reply" action="tickets.php?id=<?php echo $ticket->getExtId(); ?>#reply" name="reply" method="post" enctype="multipart/form-data"> + <h2>Post a Reply</h2> + <input type="hidden" name="id" value="<?php echo $ticket->getExtId(); ?>"> + <input type="hidden" name="a" value="reply"> + <table border="0" cellspacing="0" cellpadding="3" width="800"> + <tr> + <td width="160"> + <label>Message:</label> + </td> + <td width="640"> + <?php + if($ticket->isClosed()) { + $msg='<b>Ticket will be reopened on message post</b>'; + } else { + $msg='To best assist you, please be specific and detailed'; + } + ?> + <span id="msg"><em><?php echo $msg; ?> </em></span><font class="error">* <?php echo $errors['message']; ?></font><br/> + <textarea name="message" id="message" cols="50" rows="9" wrap="soft"><?php echo $info['message']; ?></textarea> + </td> + </tr> + <?php + if($cfg->allowOnlineAttachments()) { ?> + <tr> + <td width="160"> + <label for="attachment">Attachments:</label> + </td> + <td width="640" id="reply_form_attachments" class="attachments"> + <div class="uploads"> + </div> + <div class="file_input"> + <input type="file" name="attachments[]" size="30" value="" /> + </div> + </td> + </tr> + <?php + } ?> + </table> + <p style="padding-left:165px;"> + <input type="submit" value="Post Reply"> + <input type="reset" value="Reset"> + <input type="button" value="Cancel" onClick="history.go(-1)"> + </p> +</form> diff --git a/include/staff/api.inc.php b/include/staff/api.inc.php index 7463ad0956cbfbb02d2e4d3faa82cfa0cd6da35e..21eac469162af3d2cc9652d8e8255f230ee18460 100644 --- a/include/staff/api.inc.php +++ b/include/staff/api.inc.php @@ -1,146 +1,147 @@ -<?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); - - -$info['phrase']=($errors && $_POST['phrase'])?Format::htmlchars($_POST['phrase']):$cfg->getAPIPassphrase(); -$select='SELECT * '; -$from='FROM '.API_KEY_TABLE; -$where=''; -$sortOptions=array('date'=>'created','ip'=>'ipaddr'); -$orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); -//Sorting options... -if($_REQUEST['sort']) { - $order_column =$sortOptions[$_REQUEST['sort']]; -} - -if($_REQUEST['order']) { - $order=$orderWays[$_REQUEST['order']]; -} -$order_column=$order_column?$order_column:'ipaddr'; -$order=$order?$order:'ASC'; -$order_by=" ORDER BY $order_column $order "; - -$total=db_count('SELECT count(*) '.$from.' '.$where); -$pagelimit=1000;//No limit. -$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); -$pageNav->setURL('admin.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); -$query="$select $from $where $order_by"; -//echo $query; -$result = db_query($query); -$showing=db_num_rows($result)?$pageNav->showing():''; -$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. -$deletable=0; -?> -<div class="msg">API Keys</div> -<hr> -<div><b><?php echo $showing; ?></b></div> - <table width="100%" border="0" cellspacing=1 cellpadding=2> - <form action="admin.php?t=api" method="POST" name="api" onSubmit="return checkbox_checker(document.forms['api'],1,0);"> - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='mass_process'> - <tr><td> - <table border="0" cellspacing=0 cellpadding=2 class="dtable" align="center" width="100%"> - <tr> - <th width="7px"> </th> - <th>API Key</th> - <th width="10" nowrap>Active</th> - <th width="100" nowrap> IP Address</th> - <th width="150" nowrap> - <a href="admin.php?t=api&sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Create Date <?php echo $negorder; ?>">Created</a></th> - </tr> +<?php +if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); + + +$info['phrase']=($errors && $_POST['phrase'])?Format::htmlchars($_POST['phrase']):$cfg->getAPIPassphrase(); +$select='SELECT * '; +$from='FROM '.API_KEY_TABLE; +$where=''; +$sortOptions=array('date'=>'created','ip'=>'ipaddr'); +$orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); +//Sorting options... +if($_REQUEST['sort']) { + $order_column =$sortOptions[$_REQUEST['sort']]; +} + +if($_REQUEST['order']) { + $order=$orderWays[$_REQUEST['order']]; +} +$order_column=$order_column?$order_column:'ipaddr'; +$order=$order?$order:'ASC'; +$order_by=" ORDER BY $order_column $order "; + +$total=db_count('SELECT count(*) '.$from.' '.$where); +$pagelimit=1000;//No limit. TODO: Add limit. +$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; +$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav->setURL('admin.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); +$query="$select $from $where $order_by"; +//echo $query; +$result = db_query($query); +$showing=db_num_rows($result)?$pageNav->showing():''; +$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. +$deletable=0; +?> +<div class="msg">API Keys</div> +<hr> +<div><b><?php echo $showing; ?></b></div> + <table width="100%" border="0" cellspacing=1 cellpadding=2> + <form action="admin.php?t=api" method="POST" name="api" onSubmit="return checkbox_checker(document.forms['api'],1,0);"> + <input type=hidden name='t' value='api'> + <input type=hidden name='do' value='mass_process'> + <tr><td> + <table border="0" cellspacing=0 cellpadding=2 class="dtable" align="center" width="100%"> + <tr> + <th width="7px"> </th> + <th>API Key</th> + <th width="10" nowrap>Active</th> + <th width="100" nowrap> IP Address</th> + <th width="150" nowrap> + <a href="admin.php?t=api&sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Create Date <?php echo $negorder; ?>">Created</a></th> + </tr> <?php - $class = 'row1'; - $total=0; - $active=$inactive=0; - $sids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; - if($result && db_num_rows($result)): - $dtpl=$cfg->getDefaultTemplateId(); - while ($row = db_fetch_array($result)) { - $sel=false; - $disabled=''; - if($row['isactive']) - $active++; - else - $inactive++; - - if($sids && in_array($row['id'],$sids)){ - $class="$class highlight"; - $sel=true; - } - ?> - <tr class="<?php echo $class; ?>" id="<?php echo $row['id']; ?>"> - <td width=7px> - <input type="checkbox" name="ids[]" value="<?php echo $row['id']; ?>" <?php echo $sel?'checked':''; ?> - onClick="highLight(this.value,this.checked);"> - <td> <?php echo $row['apikey']; ?></td> - <td><?php echo $row['isactive']?'<b>Yes</b>':'No'; ?></td> - <td> <?php echo $row['ipaddr']; ?></td> - <td> <?php echo Format::db_datetime($row['created']); ?></td> - </tr> + $class = 'row1'; + $total=0; + $active=$inactive=0; + $sids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; + if($result && db_num_rows($result)): + $dtpl=$cfg->getDefaultTemplateId(); + while ($row = db_fetch_array($result)) { + $sel=false; + $disabled=''; + if($row['isactive']) + $active++; + else + $inactive++; + + if($sids && in_array($row['id'],$sids)){ + $class="$class highlight"; + $sel=true; + } + ?> + <tr class="<?php echo $class; ?>" id="<?php echo $row['id']; ?>"> + <td width=7px> + <input type="checkbox" name="ids[]" value="<?php echo $row['id']; ?>" <?php echo $sel?'checked':''; ?> + onClick="highLight(this.value,this.checked);"> + <td> <?php echo $row['apikey']; ?></td> + <td><?php echo $row['isactive']?'<b>Yes</b>':'No'; ?></td> + <td> <?php echo $row['ipaddr']; ?></td> + <td> <?php echo Format::db_datetime($row['created']); ?></td> + </tr> <?php - $class = ($class =='row2') ?'row1':'row2'; - } //end of while. - else: //nothin' found!! ?> - <tr class="<?php echo $class; ?>"><td colspan=5><b>Query returned 0 results</b> <a href="admin.php?t=templates">Index list</a></td></tr> + $class = ($class =='row2') ?'row1':'row2'; + } //end of while. + else: //nothin' found!! ?> + <tr class="<?php echo $class; ?>"><td colspan=5><b>Query returned 0 results</b> <a href="admin.php?t=templates">Index list</a></td></tr> <?php - endif; ?> - - </table> - </td></tr> + endif; ?> + + </table> + </td></tr> <?php - if(db_num_rows($result)>0): //Show options.. - ?> - <tr> - <td align="center"> - <?php - if($inactive) { ?> - <input class="button" type="submit" name="enable" value="Enable" - onClick='return confirm("Are you sure you want to ENABLE selected keys?");'> - <?php - } - if($active){ ?> - - <input class="button" type="submit" name="disable" value="Disable" - onClick='return confirm("Are you sure you want to DISABLE selected keys?");'> - <?php } ?> - - <input class="button" type="submit" name="delete" value="Delete" - onClick='return confirm("Are you sure you want to DELETE selected keys?");'> - </td> - </tr> + if(db_num_rows($result)>0): //Show options.. + ?> + <tr> + <td align="center"> + <?php + if($inactive) { ?> + <input class="button" type="submit" name="enable" value="Enable" + onClick='return confirm("Are you sure you want to ENABLE selected keys?");'> + <?php + } + if($active){ ?> + + <input class="button" type="submit" name="disable" value="Disable" + onClick='return confirm("Are you sure you want to DISABLE selected keys?");'> + <?php } ?> + + <input class="button" type="submit" name="delete" value="Delete" + onClick='return confirm("Are you sure you want to DELETE selected keys?");'> + </td> + </tr> <?php - endif; - ?> - </form> - </table> - <br/> - <div class="msg">Add New IP</div> - <hr> - <div> - Add a new IP address. <font class="error"><?php echo $errors['ip']; ?></font> - <form action="admin.php?t=api" method="POST" > - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='add'> - New IP: - <input name="ip" size=30 value="<?php echo ($errors['ip'])?Format::htmlchars($_REQUEST['ip']):''; ?>" /> - <font class="error">* </font> - <input class="button" type="submit" name="add" value="Add"> - </form> - </div> - <br/> - <div class="msg">API Passphrase</div> - <hr> - <div> - Passphrase must be at least 3 words. Required to generate the api keys.<br/> - <form action="admin.php?t=api" method="POST" > - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='update_phrase'> - Phrase: - <input name="phrase" size=50 value="<?php echo Format::htmlchars($info['phrase']); ?>" /> - <font class="error">* <?php echo $errors['phrase']; ?></font> - <input class="button" type="submit" name="update" value="Submit"> - </form> - <br/><br/> - <div><i>Please note that changing the passprase does NOT invalidate existing keys. To regerate a key you need to delete and readd it.</i></div> - </div> + endif; + ?> + </form> + </table> + <br/> + <div class="msg">Add New IP</div> + <hr> + <div> + Add a new IP address. <font class="error"><?php echo $errors['ip']; ?></font> + <form action="admin.php?t=api" method="POST" > + <input type=hidden name='t' value='api'> + <input type=hidden name='do' value='add'> + New IP: + <input name="ip" size=30 value="<?php echo ($errors['ip'])?Format::htmlchars($_REQUEST['ip']):''; ?>" /> + <font class="error">* </font> + <input class="button" type="submit" name="add" value="Add"> + </form> + </div> + <br/> + <div class="msg">API Passphrase</div> + <hr> + <div> + Passphrase must be at least 3 words. Required to generate the api keys.<br/> + <form action="admin.php?t=api" method="POST" > + <input type=hidden name='t' value='api'> + <input type=hidden name='do' value='update_phrase'> + Phrase: + <input name="phrase" size=50 value="<?php echo Format::htmlchars($info['phrase']); ?>" /> + <font class="error">* <?php echo $errors['phrase']; ?></font> + <input class="button" type="submit" name="update" value="Submit"> + </form> + <br/><br/> + <div><i>Please note that changing the passprase does NOT invalidate existing keys. To regerate a key you need to delete and readd it.</i></div> + </div> + diff --git a/include/staff/apikeys.inc.php b/include/staff/apikeys.inc.php index 26468089d56016c34e8dfd1dfefc972f33854b29..d7063c749ce92c04cddc36f20902b88181ab51d4 100644 --- a/include/staff/apikeys.inc.php +++ b/include/staff/apikeys.inc.php @@ -25,10 +25,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.API_KEY_TABLE.' '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total,$page,PAGE_LIMIT); $pageNav->setURL('apikeys.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/banlist.inc.php b/include/staff/banlist.inc.php index 5978964273ed573ca42fa817ed7eaf348ae143cb..ecef00ba4325e18339b4f733d82a34b38466b950 100644 --- a/include/staff/banlist.inc.php +++ b/include/staff/banlist.inc.php @@ -41,10 +41,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(DISTINCT rule.id) '.$from.' '.$where); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('banlist.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); $query="$select $from $where ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); diff --git a/include/staff/cannedreplies.inc.php b/include/staff/cannedreplies.inc.php index db44a79f3cc9470cdbdbd0746bd589a5bc16b44f..601e27d37f49646b4043b57a717abb64cb626b96 100644 --- a/include/staff/cannedreplies.inc.php +++ b/include/staff/cannedreplies.inc.php @@ -33,10 +33,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.CANNED_TABLE.' canned '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('canned.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/categories.inc.php b/include/staff/categories.inc.php index bba679898b0c5b8891486faa657eb73114f50f1f..a437338c20a156550487faf891324e2a16406562 100644 --- a/include/staff/categories.inc.php +++ b/include/staff/categories.inc.php @@ -28,10 +28,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.FAQ_CATEGORY_TABLE.' cat '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('categories.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); $query="$sql GROUP BY cat.category_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); diff --git a/include/staff/directory.inc.php b/include/staff/directory.inc.php index b687d811f2a8993c7eb8753fadb4efe5fe7668ad..c9d11a3d4bf1d8921b3261fc80d3e9a6a73616ae 100644 --- a/include/staff/directory.inc.php +++ b/include/staff/directory.inc.php @@ -52,10 +52,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(DISTINCT staff.staff_id) '.$from.' '.$where); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('directory.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/emails.inc.php b/include/staff/emails.inc.php index 44e277b468ad9879edb7fe528b7ba960e0762858..65d34d7b9bfb0b10acd983bfe41e5671932d3060 100644 --- a/include/staff/emails.inc.php +++ b/include/staff/emails.inc.php @@ -29,10 +29,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.EMAIL_TABLE.' email '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('emails.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/filters.inc.php b/include/staff/filters.inc.php index 4b9d6f31eb0e04f995ef7ffafde66a6a84bdb618..fb8a48d268a7705d5eb3a49b4076a6dcdb3b0b17 100644 --- a/include/staff/filters.inc.php +++ b/include/staff/filters.inc.php @@ -29,10 +29,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.EMAIL_FILTER_TABLE.' filter '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('filters.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php index 590673c1616c4417c3793df67c9c2234add07566..58d4f28dcdf77cbe3fa184e8a4979982b01de0fe 100644 --- a/include/staff/header.inc.php +++ b/include/staff/header.inc.php @@ -1,19 +1,26 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> - <meta charset="utf-8"> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <?php + if(defined('AUTO_REFRESH') && is_numeric(AUTO_REFRESH_RATE) && AUTO_REFRESH_RATE>0){ //Refresh rate + echo '<meta http-equiv="refresh" content="'.AUTO_REFRESH_RATE.'" />'; + } + ?> <title>osTicket Staff Control Panel</title> <!--[if IE]> <style type="text/css"> .tip_shadow { display:block !important; } </style> <![endif]--> - <script type="text/javascript" src="../js/jquery.min.js"></script> + <script type="text/javascript" src="../js/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="./js/calendar.js"></script> <script type="text/javascript" src="./js/tips.js"></script> <script type="text/javascript" src="./js/nicEdit.js"></script> + <script type="text/javascript" src="./js/bootstrap-typeahead.js"></script> <script type="text/javascript" src="./js/scp.js"></script> <link rel="stylesheet" href="./css/scp.css" media="screen"> + <link rel="stylesheet" href="./css/typeahead.css" media="screen"> </head> <body> <div id="container"> diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php index 51a7666889f562676910351c69edcf8e10f96b91..27ffde9bdacac59c2687b30b5046dde4255b1537 100644 --- a/include/staff/helptopics.inc.php +++ b/include/staff/helptopics.inc.php @@ -30,10 +30,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.TOPIC_TABLE.' topic '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('helptopics.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/login.tpl.php b/include/staff/login.tpl.php index d2b94d5516e30ae4e447d328f72f468455ca3b17..4f2364e1ae9fa21a0e79135ae5580fcaffdbcb63 100644 --- a/include/staff/login.tpl.php +++ b/include/staff/login.tpl.php @@ -1,26 +1,27 @@ <?php defined('OSTSCPINC') or die('Invalid path'); ?> +<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> -<meta http-equiv="content-type" content="text/html; charset=utf-8" /> -<title>osTicket:: SCP Login</title> -<link rel="stylesheet" href="css/login.css" type="text/css" /> -<meta name="robots" content="noindex" /> -<meta http-equiv="cache-control" content="no-cache" /> -<meta http-equiv="pragma" content="no-cache" /> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <title>osTicket:: SCP Login</title> + <link rel="stylesheet" href="css/login.css" type="text/css" /> + <meta name="robots" content="noindex" /> + <meta http-equiv="cache-control" content="no-cache" /> + <meta http-equiv="pragma" content="no-cache" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> </head> <body id="loginBody"> <div id="loginBox"> - <h1 id="logo"><a href="index.php">osTicket Staff Control Panel</a></h1> - <h1><?php echo Format::htmlchars($msg); ?></h1> - <br /> - <form action="login.php" method="post"> - <input type="hidden" name=do value="scplogin" /> - <table border=0 align="center"> - <tr><td width=100px align="right"><b>Username</b>:</td><td><input type="text" name="username" id="name" value="" /></td></tr> - <tr><td align="right"><b>Password</b>:</td><td><input type="password" name="passwd" id="pass" /></td></tr> - <tr><td> </td><td> <input class="submit" type="submit" name="submit" value="Login" /></td></tr> - </table> -</form> + <h1 id="logo"><a href="index.php">osTicket Staff Control Panel</a></h1> + <h3><?php echo Format::htmlchars($msg); ?></h3> + <form action="login.php" method="post"> + <input type="hidden" name="d"o value="scplogin"> + <fieldset> + <input type="text" name="username" id="name" value="" placeholder="username" autocorrect="off" autocapitalize="off"> + <input type="password" name="passwd" id="pass" placeholder="password" autocorrect="off" autocapitalize="off"> + </fieldset> + <input class="submit" type="submit" name="submit" value="Log In"> + </form> </div> <div id="copyRights">Copyright © <a href='http://www.osticket.com' target="_blank">osTicket.com</a></div> </body> diff --git a/include/staff/settings-general.inc.php b/include/staff/settings-general.inc.php index ff5e058b1e36bdb2a7b51282201c9b5c3e633412..2e1e347bef5c45eab3826c2b263a59149cb32fc4 100644 --- a/include/staff/settings-general.inc.php +++ b/include/staff/settings-general.inc.php @@ -1,196 +1,197 @@ -<form action="settings.php?t=general" method="post" id="save"> -<input type="hidden" name="t" value="general" > -<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2"> - <thead> - <tr> - <th colspan="2"> - <h4>General Settings</h4> - <em>Offline mode will disable client interface and only allow admins to login to Staff Control Panel</em> - </th> - </tr> - </thead> - <tbody> - - <tr> - <td width="220" class="required">Helpdesk Status:</td> - <td> - <input type="radio" name="isonline" value="1" <?php echo $config['isonline']?'checked="checked"':''; ?> /><b>Online</b> (Active) - <input type="radio" name="isonline" value="0" <?php echo !$config['isonline']?'checked="checked"':''; ?> /><b>Offline</b> (Disabled) - <font class="error"> <?php echo $config['isoffline']?'osTicket offline':''; ?></font> - </td> - </tr> - <tr> - <td width="220" class="required">Helpdesk URL:</td> - <td> - <input type="text" size="40" name="helpdesk_url" value="<?php echo $config['helpdesk_url']; ?>"> - <font class="error">* <?php echo $errors['helpdesk_url']; ?></font></td> - </tr> - <tr> - <td width="220" class="required">Helpdesk Name/Title:</td> - <td><input type="text" size="40" name="helpdesk_title" value="<?php echo $config['helpdesk_title']; ?>"> - <font class="error">* <?php echo $errors['helpdesk_title']; ?></font></td> - </tr> - <tr> - <td width="220" class="required">Default Department:</td> - <td> - <select name="default_dept_id"> - <option value="">— Select Default Department —</option> +<form action="settings.php?t=general" method="post" id="save"> +<input type="hidden" name="t" value="general" > +<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2"> + <thead> + <tr> + <th colspan="2"> + <h4>General Settings</h4> + <em>Offline mode will disable client interface and only allow admins to login to Staff Control Panel</em> + </th> + </tr> + </thead> + <tbody> + + <tr> + <td width="220" class="required">Helpdesk Status:</td> + <td> + <input type="radio" name="isonline" value="1" <?php echo $config['isonline']?'checked="checked"':''; ?> /><b>Online</b> (Active) + <input type="radio" name="isonline" value="0" <?php echo !$config['isonline']?'checked="checked"':''; ?> /><b>Offline</b> (Disabled) + <font class="error"> <?php echo $config['isoffline']?'osTicket offline':''; ?></font> + </td> + </tr> + <tr> + <td width="220" class="required">Helpdesk URL:</td> + <td> + <input type="text" size="40" name="helpdesk_url" value="<?php echo $config['helpdesk_url']; ?>"> + <font class="error">* <?php echo $errors['helpdesk_url']; ?></font></td> + </tr> + <tr> + <td width="220" class="required">Helpdesk Name/Title:</td> + <td><input type="text" size="40" name="helpdesk_title" value="<?php echo $config['helpdesk_title']; ?>"> + <font class="error">* <?php echo $errors['helpdesk_title']; ?></font></td> + </tr> + <tr> + <td width="220" class="required">Default Department:</td> + <td> + <select name="default_dept_id"> + <option value="">— Select Default Department —</option> <?php - $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE.' WHERE ispublic=1'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while (list($id,$name) = db_fetch_row($res)){ - $selected = ($config['default_dept_id']==$id)?'selected="selected"':''; ?> - <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?> Dept</option> + $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE.' WHERE ispublic=1'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while (list($id,$name) = db_fetch_row($res)){ + $selected = ($config['default_dept_id']==$id)?'selected="selected"':''; ?> + <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?> Dept</option> <?php - } - } ?> - </select> <font class="error">* <?php echo $errors['default_dept_id']; ?></font> - </td> - </tr> - <tr> - <td width="220" class="required">Default Email Templates:</td> - <td> - <select name="default_template_id"> - <option value="">— Select Default Template —</option> + } + } ?> + </select> <font class="error">* <?php echo $errors['default_dept_id']; ?></font> + </td> + </tr> + <tr> + <td width="220" class="required">Default Email Templates:</td> + <td> + <select name="default_template_id"> + <option value="">— Select Default Template —</option> <?php - $sql='SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_TABLE.' WHERE isactive=1 AND cfg_id='.db_input($cfg->getId()).' ORDER BY name'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while (list($id,$name) = db_fetch_row($res)){ - $selected = ($config['default_template_id']==$id)?'selected="selected"':''; ?> - <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> + $sql='SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_TABLE.' WHERE isactive=1 AND cfg_id='.db_input($cfg->getId()).' ORDER BY name'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while (list($id,$name) = db_fetch_row($res)){ + $selected = ($config['default_template_id']==$id)?'selected="selected"':''; ?> + <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> <?php - } - } ?> - </select> <font class="error">* <?php echo $errors['default_template_id']; ?></font> - </td> - </tr> - - <tr><td>Default Page Size:</td> - <td> - <select name="max_page_size"> + } + } ?> + </select> <font class="error">* <?php echo $errors['default_template_id']; ?></font> + </td> + </tr> + + <tr><td>Default Page Size:</td> + <td> + <select name="max_page_size"> <?php - $pagelimit=$config['max_page_size']; - for ($i = 5; $i <= 50; $i += 5) { - ?> - <option <?php echo $config['max_page_size']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"><?php echo $i; ?></option> + $pagelimit=$config['max_page_size']; + for ($i = 5; $i <= 50; $i += 5) { + ?> + <option <?php echo $config['max_page_size']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"><?php echo $i; ?></option> <?php - } ?> - </select> - </td> - </tr> - <tr> - <td>Default Log Level:</td> - <td> - <select name="log_level"> - <option value=0 <?php echo $config['log_level'] == 0 ? 'selected="selected"':''; ?>>None (Disable Logger)</option> - <option value=3 <?php echo $config['log_level'] == 3 ? 'selected="selected"':''; ?>> DEBUG</option> - <option value=2 <?php echo $config['log_level'] == 2 ? 'selected="selected"':''; ?>> WARN</option> - <option value=1 <?php echo $config['log_level'] == 1 ? 'selected="selected"':''; ?>> ERROR</option> - </select> - <font class="error"> <?php echo $errors['log_level']; ?></font> - </td> - </tr> - <tr> - <td>Purge Logs:</td> - <td> - <select name="log_graceperiod"> - <option value=0 selected>Never Purge Logs</option> + } ?> + </select> + </td> + </tr> + <tr> + <td>Default Log Level:</td> + <td> + <select name="log_level"> + <option value=0 <?php echo $config['log_level'] == 0 ? 'selected="selected"':''; ?>>None (Disable Logger)</option> + <option value=3 <?php echo $config['log_level'] == 3 ? 'selected="selected"':''; ?>> DEBUG</option> + <option value=2 <?php echo $config['log_level'] == 2 ? 'selected="selected"':''; ?>> WARN</option> + <option value=1 <?php echo $config['log_level'] == 1 ? 'selected="selected"':''; ?>> ERROR</option> + </select> + <font class="error"> <?php echo $errors['log_level']; ?></font> + </td> + </tr> + <tr> + <td>Purge Logs:</td> + <td> + <select name="log_graceperiod"> + <option value=0 selected>Never Purge Logs</option> <?php - for ($i = 1; $i <=12; $i++) { - ?> - <option <?php echo $config['log_graceperiod']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"> - After <?php echo $i; ?> <?php echo ($i>1)?'Months':'Month'; ?></option> + for ($i = 1; $i <=12; $i++) { + ?> + <option <?php echo $config['log_graceperiod']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"> + After <?php echo $i; ?> <?php echo ($i>1)?'Months':'Month'; ?></option> <?php - } ?> - </select> - </td> - </tr> - <tr><td>Password Reset Policy:</th> - <td> - <select name="passwd_reset_period"> - <option value="0"> — None —</option> - <?php - for ($i = 1; $i <= 12; $i++) { - echo sprintf('<option value="%d" %s>%s%s</option>', - $i,(($config['passwd_reset_period']==$i)?'selected="selected"':''),$i>1?"Every $i ":'',$i>1?' Months':'Monthly'); - } - ?> - </select> - <font class="error"> <?php echo $errors['passwd_reset_period']; ?></font> - </td> - </tr> - <tr><td>Staff Excessive Logins:</td> - <td> - <select name="staff_max_logins"> - <?php - for ($i = 1; $i <= 10; $i++) { - echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_max_logins']==$i)?'selected="selected"':''),$i); - } - ?> - </select> failed login attempt(s) allowed before a - <select name="staff_login_timeout"> - <?php - for ($i = 1; $i <= 10; $i++) { - echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_login_timeout']==$i)?'selected="selected"':''),$i); - } - ?> - </select> minute lock-out is enforced. - </td> - </tr> - <tr><td>Staff Session Timeout:</td> - <td> - <input type="text" name="staff_session_timeout" size=6 value="<?php echo $config['staff_session_timeout']; ?>"> - Maximum idle time in minutes before a staff member must log in again (enter 0 to disable). - </td> - </tr> - <tr><td>Bind Staff Session to IP:</td> - <td> - <input type="checkbox" name="staff_ip_binding" <?php echo $config['staff_ip_binding']?'checked="checked"':''; ?>> - <em>(binds staff session to originating IP address upon login)</em> - </td> - </tr> - <tr><td>Client Excessive Logins:</td> - <td> - <select name="client_max_logins"> - <?php - for ($i = 1; $i <= 10; $i++) { - echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_max_logins']==$i)?'selected="selected"':''),$i); - } - - ?> - </select> failed login attempt(s) allowed before a - <select name="client_login_timeout"> - <?php - for ($i = 1; $i <= 10; $i++) { - echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_login_timeout']==$i)?'selected="selected"':''),$i); - } - ?> - </select> minute lock-out is enforced. - </td> - </tr> - - <tr><td>Client Session Timeout:</td> - <td> - <input type="text" name="client_session_timeout" size=6 value="<?php echo $config['client_session_timeout']; ?>"> - Maximum idle time in minutes before a client must log in again (enter 0 to disable). - </td> - </tr> - <tr><td>Clickable URLs:</td> - <td> - <input type="checkbox" name="clickable_urls" <?php echo $config['clickable_urls']?'checked="checked"':''; ?>> - <em>(converts URLs in messages to clickable links)</em> - </td> - </tr> - <tr><td>Enable Auto Cron:</td> - <td> - <input type="checkbox" name="enable_auto_cron" <?php echo $config['enable_auto_cron']?'checked="checked"':''; ?>> - <em>(executes cron jobs based on staff activity - not recommended)</em> - </td> - </tr> - </tbody> -</table> -<p style="padding-left:250px;"> - <input class="button" type="submit" name="submit" value="Save Changes"> - <input class="button" type="reset" name="reset" value="Reset Changes"> -</p> -</form> + } ?> + </select> + </td> + </tr> + <tr><td>Password Reset Policy:</th> + <td> + <select name="passwd_reset_period"> + <option value="0"> — None —</option> + <?php + for ($i = 1; $i <= 12; $i++) { + echo sprintf('<option value="%d" %s>%s%s</option>', + $i,(($config['passwd_reset_period']==$i)?'selected="selected"':''),$i>1?"Every $i ":'',$i>1?' Months':'Monthly'); + } + ?> + </select> + <font class="error"> <?php echo $errors['passwd_reset_period']; ?></font> + </td> + </tr> + <tr><td>Staff Excessive Logins:</td> + <td> + <select name="staff_max_logins"> + <?php + for ($i = 1; $i <= 10; $i++) { + echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_max_logins']==$i)?'selected="selected"':''),$i); + } + ?> + </select> failed login attempt(s) allowed before a + <select name="staff_login_timeout"> + <?php + for ($i = 1; $i <= 10; $i++) { + echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_login_timeout']==$i)?'selected="selected"':''),$i); + } + ?> + </select> minute lock-out is enforced. + </td> + </tr> + <tr><td>Staff Session Timeout:</td> + <td> + <input type="text" name="staff_session_timeout" size=6 value="<?php echo $config['staff_session_timeout']; ?>"> + Maximum idle time in minutes before a staff member must log in again (enter 0 to disable). + </td> + </tr> + <tr><td>Bind Staff Session to IP:</td> + <td> + <input type="checkbox" name="staff_ip_binding" <?php echo $config['staff_ip_binding']?'checked="checked"':''; ?>> + <em>(binds staff session to originating IP address upon login)</em> + </td> + </tr> + <tr><td>Client Excessive Logins:</td> + <td> + <select name="client_max_logins"> + <?php + for ($i = 1; $i <= 10; $i++) { + echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_max_logins']==$i)?'selected="selected"':''),$i); + } + + ?> + </select> failed login attempt(s) allowed before a + <select name="client_login_timeout"> + <?php + for ($i = 1; $i <= 10; $i++) { + echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_login_timeout']==$i)?'selected="selected"':''),$i); + } + ?> + </select> minute lock-out is enforced. + </td> + </tr> + + <tr><td>Client Session Timeout:</td> + <td> + <input type="text" name="client_session_timeout" size=6 value="<?php echo $config['client_session_timeout']; ?>"> + Maximum idle time in minutes before a client must log in again (enter 0 to disable). + </td> + </tr> + <tr><td>Clickable URLs:</td> + <td> + <input type="checkbox" name="clickable_urls" <?php echo $config['clickable_urls']?'checked="checked"':''; ?>> + <em>(converts URLs in messages to clickable links)</em> + </td> + </tr> + <tr><td>Enable Auto Cron:</td> + <td> + <input type="checkbox" name="enable_auto_cron" <?php echo $config['enable_auto_cron']?'checked="checked"':''; ?>> + <em>(executes cron jobs based on staff activity - not recommended)</em> + </td> + </tr> + </tbody> +</table> +<p style="padding-left:250px;"> + <input class="button" type="submit" name="submit" value="Save Changes"> + <input class="button" type="reset" name="reset" value="Reset Changes"> +</p> +</form> + diff --git a/include/staff/slaplans.inc.php b/include/staff/slaplans.inc.php index 4ebb46b334e4e2a15b3f63f163824c03accbca29..5dea61f69b8ccaeaec3b84411185fbe4a26da886 100644 --- a/include/staff/slaplans.inc.php +++ b/include/staff/slaplans.inc.php @@ -25,10 +25,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.SLA_TABLE.' sla '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('slas.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/staffmembers.inc.php b/include/staff/staffmembers.inc.php index be8497b97c5030009cac3ff099dd8fadffa00ace..aa41b1bbf4a00a6143bb8bd0961d8a8ab4a801b0 100644 --- a/include/staff/staffmembers.inc.php +++ b/include/staff/staffmembers.inc.php @@ -46,10 +46,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(DISTINCT staff.staff_id) '.$from.' '.$where); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total,$page,PAGE_LIMIT); $pageNav->setURL('staff.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/syslogs.inc.php b/include/staff/syslogs.inc.php index 1cec6aff3f253876a77c11d961ca87cba5b3c91f..482dd429c3738faea83e49df05a09c8dd391a7e2 100644 --- a/include/staff/syslogs.inc.php +++ b/include/staff/syslogs.inc.php @@ -71,9 +71,7 @@ $qfrom=' FROM '.SYSLOG_TABLE.' log '; $total=db_count("SELECT count(*) $qfrom $qwhere"); $page = ($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; //pagenate -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('syslogs.php',$qstr); $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); $query="$qselect $qfrom $qwhere ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); diff --git a/include/staff/templates.inc.php b/include/staff/templates.inc.php index 8ce8ca8546ed5932fa5788aec5430400b68e6210..7f82f656f12cafe984de35ff205eb62bfef2b1a7 100644 --- a/include/staff/templates.inc.php +++ b/include/staff/templates.inc.php @@ -28,10 +28,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.EMAIL_TEMPLATE_TABLE.' tpl '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('templates.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..db80cf2f73fc53853905be23eaa6430e7eefd1de --- /dev/null +++ b/include/staff/ticket-edit.inc.php @@ -0,0 +1,173 @@ +<?php +if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->canEditTickets() || !$ticket) die('Access Denied'); + +$info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo()); +?> +<form action="tickets.php?id=<?php echo $ticket->getId(); ?>&a=edit" method="post" id="save" enctype="multipart/form-data"> + <input type="hidden" name="do" value="update"> + <input type="hidden" name="a" value="edit"> + <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>"> + <h2>Update Ticket# <?php echo $ticket->getExtId(); ?></h2> + <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2"> + <thead> + <tr> + <th colspan="2"> + <h4>Ticket Update</h4> + <em><strong>User Information</strong>: Make sure the email address is valid.</em> + </th> + </tr> + </thead> + <tbody> + <tr> + <td width="160" class="required"> + Full Name: + </td> + <td> + <input type="text" size="45" name="name" value="<?php echo $info['name']; ?>"> + <span class="error">* <?php echo $errors['name']; ?></span> + </td> + </tr> + <tr> + <td width="160" class="required"> + Email Address: + </td> + <td> + <input type="text" size="45" name="email" value="<?php echo $info['email']; ?>"> + <span class="error">* <?php echo $errors['email']; ?></span> + </td> + </tr> + <tr> + <td width="160"> + Phone Number: + </td> + <td> + <input type="text" size="18" name="phone" value="<?php echo $info['phone']; ?>"> + <span class="error"> <?php echo $errors['phone']; ?></span> + Ext <input type="text" size="5" name="phone_ext" value="<?php echo $info['phone_ext']; ?>"> + <span class="error"> <?php echo $errors['phone_ext']; ?></span> + </td> + </tr> + <tr> + <th colspan="2"> + <em><strong>Ticket Information</strong>: Due date overwrites SLA's grace period.</em> + </th> + </tr> + <tr> + <td width="160" class="required"> + Ticket Source: + </td> + <td> + <select name="source"> + <option value="" selected >— Select Source —</option> + <option value="Phone" <?php echo ($info['source']=='Phone')?'selected="selected"':''; ?>>Phone</option> + <option value="Email" <?php echo ($info['source']=='Email')?'selected="selected"':''; ?>>Email</option> + <option value="Web" <?php echo ($info['source']=='Web')?'selected="selected"':''; ?>>Web</option> + <option value="API" <?php echo ($info['source']=='API')?'selected="selected"':''; ?>>API</option> + <option value="Other" <?php echo ($info['source']=='Other')?'selected="selected"':''; ?>>Other</option> + </select> + <font class="error"><b>*</b> <?=$errors['source']?></font> + </td> + </tr> + <tr> + <td width="160" class="required"> + Help Topic: + </td> + <td> + <select name="topicId"> + <option value="" selected >— Select Help Topic —</option> + <?php + if($topics=Topic::getHelpTopics()) { + foreach($topics as $id =>$name) { + echo sprintf('<option value="%d" %s>%s</option>', + $id, ($info['topicId']==$id)?'selected="selected"':'',$name); + } + } + ?> + </select> + <font class="error"><b>*</b> <?=$errors['topicId']?></font> + </td> + </tr> + <tr> + <td width="160" class="required"> + Priority Level: + </td> + <td> + <select name="priorityId"> + <option value="" selected >— Select Priority —</option> + <?php + if($priorities=Priority::getPriorities()) { + foreach($priorities as $id =>$name) { + echo sprintf('<option value="%d" %s>%s</option>', + $id, ($info['priorityId']==$id)?'selected="selected"':'',$name); + } + } + ?> + </select> + <font class="error">* <?=$errors['priorityId']?></font> + </td> + </tr> + <tr> + <td width="160" class="required"> + SLA: + </td> + <td> + <select name="slaId"> + <option value="" selected >— Select SLA —</option> + <?php + if($slas=SLA::getSLAs()) { + foreach($slas as $id =>$name) { + echo sprintf('<option value="%d" %s>%s</option>', + $id, ($info['slaId']==$id)?'selected="selected"':'',$name); + } + } + ?> + </select> + <font class="error">* <?=$errors['slaId']?></font> + </td> + </tr> + <tr> + <td width="160" class="required"> + Subject: + </td> + <td> + <input type="text" name="subject" size="60" value="<?=$info['subject']?>"> + <font class="error">* <?=$errors['subject']?></font> + </td> + </tr> + <tr> + <td width="160"> + Due Date: + </td> + <td> + <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="10" + onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> + <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> + + <?php + $min=$hr=null; + if($info['time']) + list($hr,$min)=explode(':',$info['time']); + echo Misc::timeDropdown($hr,$min,'time'); + ?> + <font class="error"> <?=$errors['duedate']?> <?php echo $errors['time']; ?></font> + <em>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</em> + </td> + </tr> + <tr> + <th colspan="2"> + <em><strong>Internal Note</strong>: Reason for editing the ticket (required) <font class="error"> <?php echo $errors['note'];?></font></em> + </th> + </tr> + <tr> + <td colspan=2> + <textarea name="note" cols="21" rows="6" style="width:80%;"><?php echo $info['note']; ?></textarea> + </td> + </tr> + </tbody> +</table> +<p style="padding-left:250px;"> + <input type="submit" name="submit" value="Save"> + <input type="reset" name="reset" value="Reset"> + <input type="button" name="cancel" value="Cancel" onclick='window.location.href="tickets.php?id=<?php echo $ticket->getId(); ?>"'> +</p> +</form> diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php index a858c5708089f877bdb11d1ce9d58b49375e0046..4ec32b3423abb2c4fa424552ec4b6730a8418e9a 100644 --- a/include/staff/ticket-open.inc.php +++ b/include/staff/ticket-open.inc.php @@ -22,7 +22,9 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); Email Address: </td> <td> - <input type="text" size="30" name="email" value="<?php echo $info['email']; ?>"> + + <input type="text" size="45" name="email" id="email" class="typeahead" value="<?php echo $info['email']; ?>" + autocomplete="off" autocorrect="off" autocapitalize="off"> <span class="error">* <?php echo $errors['email']; ?></span> <?php if($cfg->notifyONNewStaffTicket()) { ?> @@ -37,7 +39,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); Full Name: </td> <td> - <input type="text" size="30" name="name" value="<?php echo $info['name']; ?>"> + <input type="text" size="45" name="name" id="name" value="<?php echo $info['name']; ?>"> <span class="error">* <?php echo $errors['name']; ?></span> </td> </tr> @@ -46,9 +48,9 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); Phone Number: </td> <td> - <input type="text" size="18" name="phone" value="<?php echo $info['phone']; ?>"> + <input type="text" size="18" name="phone" id="phone" value="<?php echo $info['phone']; ?>"> <span class="error"> <?php echo $errors['phone']; ?></span> - Ext <input type="text" size="5" name="phone_ext" value="<?php echo $info['phone_ext']; ?>"> + Ext <input type="text" size="5" name="phone_ext" id="phone_ext" value="<?php echo $info['phone_ext']; ?>"> <span class="error"> <?php echo $errors['phone_ext']; ?></span> </td> </tr> @@ -115,7 +117,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); Subject: </td> <td> - <input type="text" name="subject" size="35" value="<?=$info['subject']?>"> + <input type="text" name="subject" size="55" value="<?=$info['subject']?>"> <font class="error">* <?=$errors['subject']?></font> </td> </tr> @@ -304,6 +306,6 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <p style="padding-left:250px;"> <input type="submit" name="submit" value="Open"> <input type="reset" name="reset" value="Reset"> - <input type="button" name="cancel" value="Cancel" onclick='window.location.href="departments.php"'> + <input type="button" name="cancel" value="Cancel" onclick='window.location.href="tickets.php"'> </p> </form> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index f158a387b518a9996af30f6669016e936f7bdecb..33f46eadd443ccf0cda94867d0e54a924b73e30e 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -21,7 +21,7 @@ $id = $ticket->getId(); //Ticket ID. //Useful warnings and errors the user might want to know! if($ticket->isAssigned() && $staff->getId()!=$thisstaff->getId()) - $warn.=' <span class="Icon assignedTicket">Ticket is assigned to '.$ticket->getAssignee().'</span>'; + $warn.=' <span class="Icon assignedTicket">Ticket is assigned to '.implode('/', $ticket->getAssignees()).'</span>'; if(!$errors['err'] && ($lock && $lock->getStaffId()!=$thisstaff->getId())) $errors['err']='This ticket is currently locked by '.$lock->getStaffName(); if(!$errors['err'] && ($emailBanned=EmailFilter::isBanned($ticket->getEmail()))) @@ -103,10 +103,34 @@ if($ticket->isOverdue()) <tr> <td width="50%"> <table cellspacing="0" cellpadding="4" width="100%" border="0"> + <?php + if($ticket->isOpen()) { ?> <tr> <th width="100">Assigned To:</th> - <td><?php echo Format::htmlchars($ticket->getAssignee()); ?></td> + <td> + <?php + if($ticket->isAssigned()) + echo Format::htmlchars(implode('/', $ticket->getAssignees())); + else + echo '<span class="faded">— Unassigned —</span>'; + ?> + </td> </tr> + <?php + } else { ?> + <tr> + <th width="100">Closed By:</th> + <td> + <?php + if(($staff = $ticket->getStaff())) + echo Format::htmlchars($staff->getName()); + else + echo '<span class="faded">— Unknown —</span>'; + ?> + </td> + </tr> + <?php + } ?> <tr> <th nowrap>Last Response:</th> <td><?php echo Format::db_datetime($ticket->getLastRespDate()); ?></td> diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php index dad492a18f83dd64ed22f94de6a662de5e46ae45..67d270c3f033e0db98e901d66b09fdcabf5247c6 100644 --- a/include/staff/tickets.inc.php +++ b/include/staff/tickets.inc.php @@ -61,9 +61,13 @@ $qwhere =''; $depts=$thisstaff->getDepts(); $qwhere =' WHERE ( ' - .' ticket.dept_id IN ('.($depts?implode(',',$depts):0).') OR ticket.staff_id='.$thisstaff->getId(); + .' ticket.staff_id='.db_input($thisstaff->getId()); +if(!$thisstaff->showAssignedOnly()) + $qwhere.=' OR ticket.dept_id IN ('.($depts?implode(',',$depts):0).')'; + if(($teams=$thisstaff->getTeams()) && count(array_filter($teams))) $qwhere.=' OR ticket.team_id IN('.implode(',',array_filter($teams)).') '; + $qwhere .= ' )'; //STATUS @@ -85,7 +89,7 @@ if($staffId && ($staffId==$thisstaff->getId())) { //Staff's assigned tickets. } //******* Showing assigned tickets? (don't confuse it with show assigned To column). F'it it's confusing - just trust me! ***/ -if(!($cfg->showAssignedTickets() || $thisstaff->showAssignedTickets()) && strcasecmp($status,'closed')) +if(!($cfg->showAssignedTickets() || $thisstaff->showAssignedTickets()) && strcasecmp($status,'closed') && !$search) $sql.=' AND (ticket.staff_id=0 OR ticket.staff_id='.db_input($thisstaff->getId()).') '; //Search?? Somebody...get me some coffee @@ -180,8 +184,8 @@ if(!$order_by && $showanswered) { }elseif(!$order_by && !strcasecmp($status,'closed')){ $order_by='ticket.closed, ticket.created'; //No priority sorting for closed tickets. } -$order_by =$order_by?$order_by:'priority_urgency,effective_date,ticket.created'; -$order=$order?$order:'DESC'; +$order_by =$order_by?$order_by:'priority_urgency, effective_date, ticket.created'; +$order=$order?$order:'ASC'; if($order_by && strpos($order_by,',')) $order_by=str_replace(','," $order,",$order_by); @@ -200,6 +204,7 @@ $qselect ='SELECT DISTINCT ticket.ticket_id,lock_id,ticketID,ticket.dept_id,tick $qfrom=' FROM '.TICKET_TABLE.' ticket '. ' LEFT JOIN '.DEPT_TABLE.' dept ON ticket.dept_id=dept.dept_id '; +$sjoin=''; if($search && $deep_search) { $sjoin=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )' .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )' @@ -210,7 +215,7 @@ $qgroup=' GROUP BY ticket.ticket_id'; //get ticket count based on the query so far.. $total=db_count("SELECT count(DISTINCT ticket.ticket_id) $qfrom $sjoin $qwhere"); //pagenate -$pagelimit=($_GET['limit'] && is_numeric($_GET['limit']))?$_GET['limit']:$thisstaff->getPageLimit(); +$pagelimit=($_GET['limit'] && is_numeric($_GET['limit']))?$_GET['limit']:PAGE_LIMIT; $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; $pageNav=new Pagenate($total,$page,$pagelimit); $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); @@ -236,6 +241,8 @@ $qfrom.=' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (ticket.priority_id=pri.pri $query="$qselect $qfrom $qwhere $qgroup ORDER BY $order_by $order LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); //echo $query; +$hash = md5($query); +$_SESSION['search_'.$hash] = $query; $res = db_query($query); $showing=db_num_rows($res)?$pageNav->showing():""; if(!$results_type) { @@ -253,104 +260,18 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; <input type="hidden" name="a" value="search"> <table> <tr> - <td><input type="text" id="query" name="query" size=30 value="<?php echo Format::htmlchars($_REQUEST['query']); ?>"></td> + <td><input type="text" id="basic-ticket-search" name="query" size=30 value="<?php echo Format::htmlchars($_REQUEST['query']); ?>" + autocomplete="off" autocorrect="off" autocapitalize="off"></td> <td><input type="submit" name="basic_search" class="button" value="Search"></td> </tr> </table> </form> </div> -<div id='advance' style="display:<?php echo $basic_display?'none':'block'; ?>"> - <form action="tickets.php" method="get"> - <input type="hidden" name="a" value="search"> - <table> - <tr> - <td>Query: </td><td><input type="text" id="query" name="query" value="<?php echo Format::htmlchars($_REQUEST['query']); ?>"></td> - <td>Dept:</td> - <td><select name="dept"><option value=0>All Departments</option> - <?php - //Showing only departments the user has access to... - $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE; - if(!$thisstaff->isadmin()) - $sql.=' WHERE dept_id IN ('.implode(',',$thisstaff->getDepts()).')'; - - $depts= db_query($sql); - while (list($deptId,$deptName) = db_fetch_row($depts)){ - $selected = ($_GET['dept']==$deptId)?'selected':''; ?> - <option value="<?php echo $deptId; ?>"<?php echo $selected; ?>><?php echo $deptName; ?></option> - <?php - } ?> - </select> - </td> - <td>Status is:</td><td> - - <select name="status"> - <option value='any' selected >Any status</option> - <option value="open" <?php echo !strcasecmp($_REQUEST['status'],'Open')?'selected':''; ?>>Open</option> - <option value="overdue" <?php echo !strcasecmp($_REQUEST['status'],'overdue')?'selected':''; ?>>Overdue</option> - <option value="closed" <?php echo !strcasecmp($_REQUEST['status'],'Closed')?'selected':''; ?>>Closed</option> - </select> - </td> - </tr> - </table> - <div> - Date Span: - From <input id="sd" name="startDate" value="<?php echo Format::htmlchars($_REQUEST['startDate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('sd')); return false;"><img src='images/cal.png'border=0 alt=""></a> - to - <input id="ed" name="endDate" value="<?php echo Format::htmlchars($_REQUEST['endDate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF > - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('ed')); return false;"><img src='images/cal.png'border=0 alt=""></a> - - </div> - <table> - <tr> - <td>Type:</td> - <td> - <select name="stype"> - <option value="LIKE" <?php echo (!$_REQUEST['stype'] || $_REQUEST['stype'] == 'LIKE') ?'selected':''; ?>>Scan (%)</option> - <option value="FT"<?php echo $_REQUEST['stype'] == 'FT'?'selected':''; ?>>Fulltext</option> - </select> - - - </td> - <td>Sort by:</td><td> - <?php - $sort=$_GET['sort']?$_GET['sort']:'date'; - ?> - <select name="sort"> - <option value="ID" <?php echo $sort== 'ID' ?'selected':''; ?>>Ticket #</option> - <option value="pri" <?php echo $sort == 'pri' ?'selected':''; ?>>Priority</option> - <option value="date" <?php echo $sort == 'date' ?'selected':''; ?>>Date</option> - <option value="dept" <?php echo $sort == 'dept' ?'selected':''; ?>>Dept.</option> - </select> - <select name="order"> - <option value="DESC"<?php echo $_REQUEST['order'] == 'DESC' ?'selected':''; ?>>Descending</option> - <option value="ASC"<?php echo $_REQUEST['order'] == 'ASC'?'selected':''; ?>>Ascending</option> - </select> - </td> - <td>Results Per Page:</td><td> - <select name="limit"> - <?php - $sel=$_REQUEST['limit']?$_REQUEST['limit']:15; - for ($x = 5; $x <= 25; $x += 5) { ?> - <option value="<?php echo $x; ?>" <?php echo ($sel==$x )?'selected':''; ?>><?php echo $x; ?></option> - <?php } ?> - </select> - </td> - <td> - <input type="submit" name="advance_search" class="button" value="Search"> - [ <a href="#" onClick="showHide('advance','basic'); return false;" >Basic</a> ] - </td> - </tr> - </table> - </form> -</div> <!-- SEARCH FORM END --> <div class="clear"></div> <div style="margin-bottom:20px"> <form action="tickets.php" method="POST" name='tickets' onSubmit="return checkbox_checker(this,1,0);"> - <a class="refresh" href="">Refresh</a> + <a class="refresh" href="<?php echo $_SERVER['REQUEST_URI']; ?>">Refresh</a> <input type="hidden" name="a" value="mass_process" > <input type="hidden" name="status" value="<?php echo $status; ?>" > <table class="list" border="0" cellspacing="1" cellpadding="2" width="940"> @@ -485,7 +406,9 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; </table> <?php if($num>0){ //if we actually had any tickets returned. - echo '<div> Page:'.$pageNav->getPageLinks().' </div>'; + echo '<div> Page:'.$pageNav->getPageLinks().' '; + echo '<a class="export-csv" href="?a=export&h=' + .$hash.'&status='.$_REQUEST['status'] .'">Export</a></div>'; ?> <?php if($thisstaff->canManageTickets()) { ?> diff --git a/index.php b/index.php index 37e5c7f1b2dd3e899d3d7a154d5e074629ed1bfe..ac4fe04a014455d083aacab299fdace3a045e529 100644 --- a/index.php +++ b/index.php @@ -13,4 +13,40 @@ vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ -require('offline.php'); +require('client.inc.php'); +$section = 'home'; +require(CLIENTINC_DIR.'header.inc.php'); +?> + +<div id="landing_page"> + <h1>Welcome to the Support Center</h1> + <p> + In order to streamline support requests and better serve you, we utilize a support ticket system. Every support request is assigned a unique ticket number which you can use to track the progress and responses online. For your reference we provide complete archives and history of all your support requests. A valid email address is required to submit a ticket. + </p> + + <div id="new_ticket"> + <h3>Open A New Ticket</h3> + <form method="get" action="open.php"> + <div>Please provide as much detail as possible so we can best assist you. To update a previously submitted ticket, please login.</div> + <input type="submit" value="Open a New Ticket"> + </form> + </div> + + <div id="check_status"> + <h3>Check Ticket Status</h3> + <form class="status_form" action="view.php" method="get"> + <div>We provide archives and history of all your current and past support requests complete with responses.</div> + <input type="submit" value="Check Ticket Status"> + </form> + </div> +</div> +<div class="clear"></div> +<?php +if($cfg && $cfg->isKnowledgebaseEnabled()){ + //FIXME: provide ability to feature or select random FAQs ?? +?> +<p>Be sure to browse our <a href="kb/index.php">Frequently Asked Questions (FAQs)</a>, before opening a ticket.</p> +</div> +<?php +} ?> +<?php require(CLIENTINC_DIR.'footer.inc.php'); ?> diff --git a/js/jquery-1.7.2.min.js b/js/jquery-1.7.2.min.js new file mode 100644 index 0000000000000000000000000000000000000000..16ad06c5acaad09ee4d6e9d7c428506db028aeeb --- /dev/null +++ b/js/jquery-1.7.2.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.2 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"<!doctype html>":"")+"<html><body>"),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bD.test(a)?d(a,e):b_(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&f.type(b)==="object")for(var e in b)b_(a+"["+e+"]",b[e],c,d);else d(a,b)}function b$(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bZ(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bS,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bZ(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bZ(a,c,d,e,"*",g));return l}function bY(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bO),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bB(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?1:0,g=4;if(d>0){if(c!=="border")for(;e<g;e+=2)c||(d-=parseFloat(f.css(a,"padding"+bx[e]))||0),c==="margin"?d+=parseFloat(f.css(a,c+bx[e]))||0:d-=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0;return d+"px"}d=by(a,b);if(d<0||d==null)d=a.style[b];if(bt.test(d))return d;d=parseFloat(d)||0;if(c)for(;e<g;e+=2)d+=parseFloat(f.css(a,"padding"+bx[e]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+bx[e]))||0);return d+"px"}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;b.nodeType===1&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?b.outerHTML=a.outerHTML:c!=="input"||a.type!=="checkbox"&&a.type!=="radio"?c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text):(a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value)),b.removeAttribute(f.expando),b.removeAttribute("_submit_attached"),b.removeAttribute("_change_attached"))}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c,i[c][d])}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h,i){var j,k=d==null,l=0,m=a.length;if(d&&typeof d=="object"){for(l in d)e.access(a,c,l,d[l],1,h,f);g=1}else if(f!==b){j=i===b&&e.isFunction(f),k&&(j?(j=c,c=function(a,b,c){return j.call(e(a),c)}):(c.call(a,f),c=null));if(c)for(;l<m;l++)c(a[l],d,j?f.call(a[l],l,c(a[l],d)):f,i);g=1}return g?a:k?c.call(a):m?c(a[0],d):h},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test("Â ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m,n=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?n(g):h==="function"&&(!a.unique||!p.has(g))&&c.push(g)},o=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,j=!0,m=k||0,k=0,l=c.length;for(;c&&m<l;m++)if(c[m].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}j=!1,c&&(a.once?e===!0?p.disable():c=[]:d&&d.length&&(e=d.shift(),p.fireWith(e[0],e[1])))},p={add:function(){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){j&&f<=l&&(l--,f<=m&&m--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&p.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(j?a.once||d.push([b,c]):(!a.once||!e)&&o(b,c));return this},fire:function(){p.fireWith(this,arguments);return this},fired:function(){return!!i}};return p};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p=c.createElement("div"),q=c.documentElement;p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="<div "+n+"display:block;'><div style='"+t+"0;display:block;overflow:hidden;'></div></div>"+"<table "+n+"' cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="<table><tr><td style='"+t+"0;display:none'></td><td>t</td></tr></table>",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="<div style='width:5px;'></div>",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h,i,j=this[0],k=0,m=null;if(a===b){if(this.length){m=f.data(j);if(j.nodeType===1&&!f._data(j,"parsedAttrs")){g=j.attributes;for(i=g.length;k<i;k++)h=g[k].name,h.indexOf("data-")===0&&(h=f.camelCase(h.substring(5)),l(j,h,m[h]));f._data(j,"parsedAttrs",!0)}}return m}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!";return f.access(this,function(c){if(c===b){m=this.triggerHandler("getData"+e,[d[0]]),m===b&&j&&(m=f.data(j,a),m=l(j,a,m));return m===b&&d[1]?this.data(d[0]):m}d[1]=c,this.each(function(){var b=f(this);b.triggerHandler("setData"+e,d),f.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length<d)return f.queue(this[0],a);return c===b?this:this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise(c)}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,f.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i<g;i++)e=d[i],e&&(c=f.propFix[e]||e,h=u.test(e),h||f.attr(a,e,""),a.removeAttribute(v?e:c),h&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0,coords:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function( +a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:g&&G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=f.event.special[c.type]||{},j=[],k,l,m,n,o,p,q,r,s,t,u;g[0]=c,c.delegateTarget=this;if(!i.preDispatch||i.preDispatch.call(this,c)!==!1){if(e&&(!c.button||c.type!=="click")){n=f(this),n.context=this.ownerDocument||this;for(m=c.target;m!=this;m=m.parentNode||this)if(m.disabled!==!0){p={},r=[],n[0]=m;for(k=0;k<e;k++)s=d[k],t=s.selector,p[t]===b&&(p[t]=s.quick?H(m,s.quick):n.is(t)),p[t]&&r.push(s);r.length&&j.push({elem:m,matches:r})}}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k<j.length&&!c.isPropagationStopped();k++){q=j[k],c.currentTarget=q.elem;for(l=0;l<q.matches.length&&!c.isImmediatePropagationStopped();l++){s=q.matches[l];if(h||!c.namespace&&!s.namespace||c.namespace_re&&c.namespace_re.test(s.namespace))c.data=s.data,c.handleObj=s,o=((f.event.special[s.origType]||{}).handle||s.handler).apply(q.elem,g),o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()))}}i.postDispatch&&i.postDispatch.call(this,c);return c.result}},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),d._submit_attached=!0)})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9||d===11){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.globalPOS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")[\\s/>]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f +.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(f.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(g){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,function(a,b){b.src?f.ajax({type:"GET",global:!1,url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1></$2>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]==="<table>"&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i<u;i++)bn(l[i]);else bn(l);l.nodeType?j.push(l):j=f.merge(j,l)}if(d){g=function(a){return!a.type||be.test(a.type)};for(k=0;j[k];k++){h=j[k];if(e&&f.nodeName(h,"script")&&(!h.type||be.test(h.type)))e.push(h.parentNode?h.parentNode.removeChild(h):h);else{if(h.nodeType===1){var v=f.grep(h.getElementsByTagName("script"),g);j.splice.apply(j,[k+1,0].concat(v))}d.appendChild(h)}}}return j},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bp=/alpha\([^)]*\)/i,bq=/opacity=([^)]*)/,br=/([A-Z]|^ms)/g,bs=/^[\-+]?(?:\d*\.)?\d+$/i,bt=/^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,bu=/^([\-+])=([\-+.\de]+)/,bv=/^margin/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Top","Right","Bottom","Left"],by,bz,bA;f.fn.css=function(a,c){return f.access(this,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)},a,c,arguments.length>1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),(e===""&&f.css(d,"display")==="none"||!f.contains(d.ownerDocument.documentElement,d))&&f._data(d,"olddisplay",cu(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ct("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(ct("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o,p,q;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]);if((k=f.cssHooks[g])&&"expand"in k){l=k.expand(a[g]),delete a[g];for(i in l)i in a||(a[i]=l[i])}}for(g in a){h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cu(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cm.test(h)?(q=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),q?(f._data(this,"toggle"+i,q==="show"?"hide":"show"),j[q]()):j[h]()):(m=cn.exec(h),n=j.cur(),m?(o=parseFloat(m[2]),p=m[3]||(f.cssNumber[i]?"":"px"),p!=="px"&&(f.style(this,i,(o||1)+p),n=(o||1)/j.cur()*n,f.style(this,i,n+p)),m[1]&&(o=(m[1]==="-="?-1:1)*o+n),j.custom(n,o,p)):j.custom(n,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:ct("show",1),slideUp:ct("hide",1),slideToggle:ct("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a){return a},swing:function(a){return-Math.cos(a*Math.PI)/2+.5}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cq||cr(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){f._data(e.elem,"fxshow"+e.prop)===b&&(e.options.hide?f._data(e.elem,"fxshow"+e.prop,e.start):e.options.show&&f._data(e.elem,"fxshow"+e.prop,e.end))},h()&&f.timers.push(h)&&!co&&(co=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cq||cr(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(cp.concat.apply([],cp),function(a,b){b.indexOf("margin")&&(f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)})}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cv,cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?cv=function(a,b,c,d){try{d=a.getBoundingClientRect()}catch(e){}if(!d||!f.contains(c,a))return d?{top:d.top,left:d.left}:{top:0,left:0};var g=b.body,h=cy(b),i=c.clientTop||g.clientTop||0,j=c.clientLeft||g.clientLeft||0,k=h.pageYOffset||f.support.boxModel&&c.scrollTop||g.scrollTop,l=h.pageXOffset||f.support.boxModel&&c.scrollLeft||g.scrollLeft,m=d.top+k-i,n=d.left+l-j;return{top:m,left:n}}:cv=function(a,b,c){var d,e=a.offsetParent,g=a,h=b.body,i=b.defaultView,j=i?i.getComputedStyle(a,null):a.currentStyle,k=a.offsetTop,l=a.offsetLeft;while((a=a.parentNode)&&a!==h&&a!==c){if(f.support.fixedPosition&&j.position==="fixed")break;d=i?i.getComputedStyle(a,null):a.currentStyle,k-=a.scrollTop,l-=a.scrollLeft,a===e&&(k+=a.offsetTop,l+=a.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(a.nodeName))&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),g=e,e=a.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),j=d}if(j.position==="relative"||j.position==="static")k+=h.offsetTop,l+=h.offsetLeft;f.support.fixedPosition&&j.position==="fixed"&&(k+=Math.max(c.scrollTop,h.scrollTop),l+=Math.max(c.scrollLeft,h.scrollLeft));return{top:k,left:l}},f.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){f.offset.setOffset(this,a,b)});var c=this[0],d=c&&c.ownerDocument;if(!d)return null;if(c===d.body)return f.offset.bodyOffset(c);return cv(c,d,d.documentElement)},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/js/jquery.min.js b/js/jquery.min.js deleted file mode 100644 index f78f96a12f13973ee16bc9d334e403b55502c66a..0000000000000000000000000000000000000000 --- a/js/jquery.min.js +++ /dev/null @@ -1,16 +0,0 @@ -/*! - * jQuery JavaScript Library v1.5.2 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu Mar 31 15:28:23 2011 -0400 - */ -(function(a,b){function ci(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cf(a){if(!b_[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";b_[a]=c}return b_[a]}function ce(a,b){var c={};d.each(cd.concat.apply([],cd.slice(0,b)),function(){c[this]=a});return c}function b$(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bZ(){try{return new a.XMLHttpRequest}catch(b){}}function bY(){d(a).unload(function(){for(var a in bW)bW[a](0,1)})}function bS(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==="string"&&(f[h.toLowerCase()]=a.converters[h]);l=k,k=e[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=f[m]||f["* "+k];if(!n){p=b;for(o in f){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=f[j[1]+" "+k];if(p){o=f[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&d.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bR(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bQ(a,b,c,e){if(d.isArray(b)&&b.length)d.each(b,function(b,f){c||bs.test(a)?e(a,f):bQ(a+"["+(typeof f==="object"||d.isArray(f)?b:"")+"]",f,c,e)});else if(c||b==null||typeof b!=="object")e(a,b);else if(d.isArray(b)||d.isEmptyObject(b))e(a,"");else for(var f in b)bQ(a+"["+f+"]",b[f],c,e)}function bP(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bJ,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bP(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bP(a,c,d,e,"*",g));return l}function bO(a){return function(b,c){typeof b!=="string"&&(c=b,b="*");if(d.isFunction(c)){var e=b.toLowerCase().split(bD),f=0,g=e.length,h,i,j;for(;f<g;f++)h=e[f],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bq(a,b,c){var e=b==="width"?bk:bl,f=b==="width"?a.offsetWidth:a.offsetHeight;if(c==="border")return f;d.each(e,function(){c||(f-=parseFloat(d.css(a,"padding"+this))||0),c==="margin"?f+=parseFloat(d.css(a,"margin"+this))||0:f-=parseFloat(d.css(a,"border"+this+"Width"))||0});return f}function bc(a,b){b.src?d.ajax({url:b.src,async:!1,dataType:"script"}):d.globalEval(b.text||b.textContent||b.innerHTML||""),b.parentNode&&b.parentNode.removeChild(b)}function bb(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function ba(a,b){if(b.nodeType===1){var c=b.nodeName.toLowerCase();b.clearAttributes(),b.mergeAttributes(a);if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(d.expando)}}function _(a,b){if(b.nodeType===1&&d.hasData(a)){var c=d.expando,e=d.data(a),f=d.data(b,e);if(e=e[c]){var g=e.events;f=f[c]=d.extend({},e);if(g){delete f.handle,f.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)d.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function $(a,b){return d.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Q(a,b,c){if(d.isFunction(b))return d.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return d.grep(a,function(a,d){return a===b===c});if(typeof b==="string"){var e=d.grep(a,function(a){return a.nodeType===1});if(L.test(b))return d.filter(b,e,!c);b=d.filter(b,e)}return d.grep(a,function(a,e){return d.inArray(a,b)>=0===c})}function P(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function H(a,b){return(a&&a!=="*"?a+".":"")+b.replace(t,"`").replace(u,"&")}function G(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,p=[],q=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;i<t.length;i++)g=t[i],g.origType.replace(r,"")===a.type?q.push(g.selector):t.splice(i--,1);f=d(a.target).closest(q,a.currentTarget);for(j=0,k=f.length;j<k;j++){m=f[j];for(i=0;i<t.length;i++){g=t[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,e=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,e=d(a.relatedTarget).closest(g.selector)[0];(!e||e!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){f=p[j];if(c&&f.level>c)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function E(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function y(){return!0}function x(){return!1}function i(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function h(a,c,e){if(e===b&&a.nodeType===1){e=a.getAttribute("data-"+c);if(typeof e==="string"){try{e=e==="true"?!0:e==="false"?!1:e==="null"?null:d.isNaN(e)?g.test(e)?d.parseJSON(e):e:parseFloat(e)}catch(f){}d.data(a,c,e)}else e=b}return e}var c=a.document,d=function(){function G(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(G,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=navigator.userAgent,w,x,y,z=Object.prototype.toString,A=Object.prototype.hasOwnProperty,B=Array.prototype.push,C=Array.prototype.slice,D=String.prototype.trim,E=Array.prototype.indexOf,F={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.2",length:0,size:function(){return this.length},toArray:function(){return C.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var e=this.constructor();d.isArray(a)?B.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),x.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(C.apply(this,arguments),"slice",C.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:B,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!=="object"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){e=i[c],f=a[c];if(i===f)continue;l&&f&&(d.isPlainObject(f)||(g=d.isArray(f)))?(g?(g=!1,h=e&&d.isArray(e)?e:[]):h=e&&d.isPlainObject(e)?e:{},i[c]=d.extend(l,h,f)):f!==b&&(i[c]=f)}return i},d.extend({noConflict:function(b){a.$=f,b&&(a.jQuery=e);return d},isReady:!1,readyWait:1,ready:function(a){a===!0&&d.readyWait--;if(!d.readyWait||a!==!0&&!d.isReady){if(!c.body)return setTimeout(d.ready,1);d.isReady=!0;if(a!==!0&&--d.readyWait>0)return;x.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=d._Deferred();if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",y,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",y),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&G()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):F[z.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!A.call(a,"constructor")&&!A.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||A.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g<h;)if(c.apply(a[g++],e)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(var j=a[0];g<h&&c.call(j,g,j)!==!1;j=a[++g]){}return a},trim:D?function(a){return a==null?"":D.call(a)}:function(a){return a==null?"":(a+"").replace(j,"").replace(k,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var e=d.type(a);a.length==null||e==="string"||e==="function"||e==="regexp"||d.isWindow(a)?B.call(c,a):d.merge(c,a)}return c},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length==="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,b,c){var d=[],e;for(var f=0,g=a.length;f<g;f++)e=b(a[f],f,c),e!=null&&(d[d.length]=e);return d.concat.apply([],d)},guid:1,proxy:function(a,c,e){arguments.length===2&&(typeof c==="string"?(e=a,a=e[c],c=b):c&&!d.isFunction(c)&&(e=c,c=b)),!c&&a&&(c=function(){return a.apply(e||this,arguments)}),a&&(c.guid=a.guid=a.guid||c.guid||d.guid++);return c},access:function(a,c,e,f,g,h){var i=a.length;if(typeof c==="object"){for(var j in c)d.access(a,j,c[j],f,g,e);return a}if(e!==b){f=!h&&f&&d.isFunction(e);for(var k=0;k<i;k++)g(a[k],c,f?e.call(a[k],k,g(a[k],c)):e,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){F["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),E&&(d.inArray=function(a,b){return E.call(b,a)}),i.test("Â ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?y=function(){c.removeEventListener("DOMContentLoaded",y,!1),d.ready()}:c.attachEvent&&(y=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",y),d.ready())});return d}(),e="then done fail isResolved isRejected promise".split(" "),f=[].slice;d.extend({_Deferred:function(){var a=[],b,c,e,f={done:function(){if(!e){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=d.type(i),j==="array"?f.done.apply(f,i):j==="function"&&a.push(i);k&&f.resolveWith(k[0],k[1])}return this},resolveWith:function(d,f){if(!e&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(d,f)}finally{b=[d,f],c=0}}return this},resolve:function(){f.resolveWith(this,arguments);return this},isResolved:function(){return c||b},cancel:function(){e=1,a=[];return this}};return f},Deferred:function(a){var b=d._Deferred(),c=d._Deferred(),f;d.extend(b,{then:function(a,c){b.done(a).fail(c);return this},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,promise:function(a){if(a==null){if(f)return f;f=a={}}var c=e.length;while(c--)a[e[c]]=b[e[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?f.call(arguments,0):c,--g||h.resolveWith(h,f.call(b,0))}}var b=arguments,c=0,e=b.length,g=e,h=e<=1&&a&&d.isFunction(a.promise)?a:d.Deferred();if(e>1){for(;c<e;c++)b[c]&&d.isFunction(b[c].promise)?b[c].promise().then(i(c),h.reject):--g;g||h.resolveWith(h,b)}else h!==a&&h.resolveWith(h,e?[a]:[]);return h.promise()}}),function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0,reliableMarginRight:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e)}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(a.style.width="1px",a.style.marginRight="0",d.support.reliableMarginRight=(parseInt(c.defaultView.getComputedStyle(a,null).marginRight,10)||0)===0),b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function");return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}}();var g=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!i(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,g=b.nodeType,h=g?d.cache:b,j=g?b[d.expando]:d.expando;if(!h[j])return;if(c){var k=e?h[j][f]:h[j];if(k){delete k[c];if(!i(k))return}}if(e){delete h[j][f];if(!i(h[j]))return}var l=h[j][f];d.support.deleteExpando||h!=a?delete h[j]:h[j]=null,l?(h[j]={},g||(h[j].toJSON=d.noop),h[j][f]=l):g&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var f=this[0].attributes,g;for(var i=0,j=f.length;i<j;i++)g=f[i].name,g.indexOf("data-")===0&&(g=g.substr(5),h(this[0],g,e[g]))}}return e}if(typeof a==="object")return this.each(function(){d.data(this,a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(c===b){e=this.triggerHandler("getData"+k[1]+"!",[k[0]]),e===b&&this.length&&(e=d.data(this[0],a),e=h(this[0],a,e));return e===b&&k[1]?this.data(k[0]):e}return this.each(function(){var b=d(this),e=[k[0],c];b.triggerHandler("setData"+k[1]+"!",e),d.data(this,a,c),b.triggerHandler("changeData"+k[1]+"!",e)})},removeData:function(a){return this.each(function(){d.removeData(this,a)})}}),d.extend({queue:function(a,b,c){if(a){b=(b||"fx")+"queue";var e=d._data(a,b);if(!c)return e||[];!e||d.isArray(c)?e=d._data(a,b,d.makeArray(c)):e.push(c);return e}},dequeue:function(a,b){b=b||"fx";var c=d.queue(a,b),e=c.shift();e==="inprogress"&&(e=c.shift()),e&&(b==="fx"&&c.unshift("inprogress"),e.call(a,function(){d.dequeue(a,b)})),c.length||d.removeData(a,b+"queue",!0)}}),d.fn.extend({queue:function(a,c){typeof a!=="string"&&(c=a,a="fx");if(c===b)return d.queue(this[0],a);return this.each(function(b){var e=d.queue(this,a,c);a==="fx"&&e[0]!=="inprogress"&&d.dequeue(this,a)})},dequeue:function(a){return this.each(function(){d.dequeue(this,a)})},delay:function(a,b){a=d.fx?d.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){d.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var j=/[\n\t\r]/g,k=/\s+/,l=/\r/g,m=/^(?:href|src|style)$/,n=/^(?:button|input)$/i,o=/^(?:button|input|object|select|textarea)$/i,p=/^a(?:rea)?$/i,q=/^(?:radio|checkbox)$/i;d.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"},d.fn.extend({attr:function(a,b){return d.access(this,a,b,!0,d.attr)},removeAttr:function(a,b){return this.each(function(){d.attr(this,a,""),this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.addClass(a.call(this,b,c.attr("class")))});if(a&&typeof a==="string"){var b=(a||"").split(k);for(var c=0,e=this.length;c<e;c++){var f=this[c];if(f.nodeType===1)if(f.className){var g=" "+f.className+" ",h=f.className;for(var i=0,j=b.length;i<j;i++)g.indexOf(" "+b[i]+" ")<0&&(h+=" "+b[i]);f.className=d.trim(h)}else f.className=a}}return this},removeClass:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.removeClass(a.call(this,b,c.attr("class")))});if(a&&typeof a==="string"||a===b){var c=(a||"").split(k);for(var e=0,f=this.length;e<f;e++){var g=this[e];if(g.nodeType===1&&g.className)if(a){var h=(" "+g.className+" ").replace(j," ");for(var i=0,l=c.length;i<l;i++)h=h.replace(" "+c[i]+" "," ");g.className=d.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,e=typeof b==="boolean";if(d.isFunction(a))return this.each(function(c){var e=d(this);e.toggleClass(a.call(this,c,e.attr("class"),b),b)});return this.each(function(){if(c==="string"){var f,g=0,h=d(this),i=b,j=a.split(k);while(f=j[g++])i=e?i:!h.hasClass(f),h[i?"addClass":"removeClass"](f)}else if(c==="undefined"||c==="boolean")this.className&&d._data(this,"__className__",this.className),this.className=this.className||a===!1?"":d._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(j," ").indexOf(b)>-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var j=i?f:0,k=i?f+1:h.length;j<k;j++){var m=h[j];if(m.selected&&(d.support.optDisabled?!m.disabled:m.getAttribute("disabled")===null)&&(!m.parentNode.disabled||!d.nodeName(m.parentNode,"optgroup"))){a=d(m).val();if(i)return a;g.push(a)}}if(i&&!g.length&&h.length)return d(h[f]).val();return g}if(q.test(c.type)&&!d.support.checkOn)return c.getAttribute("value")===null?"on":c.value;return(c.value||"").replace(l,"")}return b}var n=d.isFunction(a);return this.each(function(b){var c=d(this),e=a;if(this.nodeType===1){n&&(e=a.call(this,b,c.val())),e==null?e="":typeof e==="number"?e+="":d.isArray(e)&&(e=d.map(e,function(a){return a==null?"":a+""}));if(d.isArray(e)&&q.test(this.type))this.checked=d.inArray(c.val(),e)>=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=m.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&n.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var k=a.getAttributeNode("tabIndex");return k&&k.specified?k.value:o.test(a.nodeName)||p.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var l=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return l===null?b:l}h&&(a[c]=e);return a[c]}});var r=/\.(.*)$/,s=/^(?:textarea|input|select)$/i,t=/\./g,u=/ /g,v=/[^\w\s.|`]/g,w=function(a){return a.replace(v,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=x;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(a){return typeof d!=="undefined"&&d.event.triggered!==a.type?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=x);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),w).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))d.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=d.event.special[h]||{};for(j=f||0;j<p.length;j++){q=p[j];if(e.guid===q.guid){if(l||n.test(q.namespace))f==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(f!=null)break}}if(p.length===0||f!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&d.removeEvent(a,h,s.handle),g=null,delete t[h]}if(d.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,d.isEmptyObject(s)&&d.removeData(a,b,!0)}}},trigger:function(a,c,e){var f=a.type||a,g=arguments[3];if(!g){a=typeof a==="object"?a[d.expando]?a:d.extend(d.Event(f),a):d.Event(f),f.indexOf("!")>=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(r,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=a.type,l[m]())}catch(p){}k&&(l["on"+m]=k),d.event.triggered=b}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l<m;l++){var n=f[l];if(e||h.test(n.namespace)){c.handler=n.handler,c.data=n.data,c.handleObj=n;var o=n.handler.apply(this,k);o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[d.expando])return a;var e=a;a=d.Event(e);for(var f=this.props.length,g;f;)g=this.props[--f],a[g]=e[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=c.documentElement,i=c.body;a.pageX=a.clientX+(h&&h.scrollLeft||i&&i.scrollLeft||0)-(h&&h.clientLeft||i&&i.clientLeft||0),a.pageY=a.clientY+(h&&h.scrollTop||i&&i.scrollTop||0)-(h&&h.clientTop||i&&i.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:d.proxy,special:{ready:{setup:d.bindReady,teardown:d.noop},live:{add:function(a){d.event.add(this,H(a.origType,a.selector),d.extend({},a,{handler:G,guid:a.handler.guid}))},remove:function(a){d.event.remove(this,H(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){d.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},d.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},d.Event=function(a){if(!this.preventDefault)return new d.Event(a);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?y:x):this.type=a,this.timeStamp=d.now(),this[d.expando]=!0},d.Event.prototype={preventDefault:function(){this.isDefaultPrevented=y;var a=this.originalEvent;a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=y;var a=this.originalEvent;a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=y,this.stopPropagation()},isDefaultPrevented:x,isPropagationStopped:x,isImmediatePropagationStopped:x};var z=function(a){var b=a.relatedTarget;try{if(b&&b!==c&&!b.parentNode)return;while(b&&b!==this)b=b.parentNode;b!==this&&(a.type=a.data,d.event.handle.apply(this,arguments))}catch(e){}},A=function(a){a.type=a.data,d.event.handle.apply(this,arguments)};d.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){d.event.special[a]={setup:function(c){d.event.add(this,b,c&&c.selector?A:z,a)},teardown:function(a){d.event.remove(this,b,a&&a.selector?A:z)}}}),d.support.submitBubbles||(d.event.special.submit={setup:function(a,b){if(this.nodeName&&this.nodeName.toLowerCase()!=="form")d.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&d(b).closest("form").length&&E("submit",this,arguments)}),d.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&d(b).closest("form").length&&a.keyCode===13&&E("submit",this,arguments)});else return!1},teardown:function(a){d.event.remove(this,".specialSubmit")}});if(!d.support.changeBubbles){var B,C=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},D=function D(a){var c=a.target,e,f;if(s.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=C(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:D,beforedeactivate:D,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&D.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&D.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",C(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in B)d.event.add(this,c+".specialChange",B[c]);return s.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return s.test(this.nodeName)}},B=d.event.special.change.filters,B.focus=B.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function f(a){var c=d.event.fix(a);c.type=b,c.originalEvent={},d.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var e=0;d.event.special[b]={setup:function(){e++===0&&c.addEventListener(a,f,!0)},teardown:function(){--e===0&&c.removeEventListener(a,f,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i<j;i++)d.event.add(this[i],a,h,e);return this}}),d.fn.extend({unbind:function(a,b){if(typeof a!=="object"||a.preventDefault)for(var e=0,f=this.length;e<f;e++)d.event.remove(this[e],a,b);else for(var c in a)this.unbind(c,a[c]);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){d.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var c=d.Event(a);c.preventDefault(),c.stopPropagation(),d.event.trigger(c,b,this[0]);return c.result}},toggle:function(a){var b=arguments,c=1;while(c<b.length)d.proxy(a,b[c++]);return this.click(d.proxy(a,function(e){var f=(d._data(this,"lastToggle"+a.guid)||0)%c;d._data(this,"lastToggle"+a.guid,f+1),e.preventDefault();return b[f].apply(this,arguments)||!1}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var F={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};d.each(["live","die"],function(a,c){d.fn[c]=function(a,e,f,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:d(this.context);if(typeof a==="object"&&!a.preventDefault){for(var o in a)n[c](o,e,a[o],m);return this}d.isFunction(e)&&(f=e,e=b),a=(a||"").split(" ");while((h=a[i++])!=null){j=r.exec(h),k="",j&&(k=j[0],h=h.replace(r,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,h==="focus"||h==="blur"?(a.push(F[h]+k),h=h+k):h=(F[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)d.event.add(n[p],"live."+H(h,m),{data:e,selector:m,handler:f,origType:h,origHandler:f,preType:l});else n.unbind("live."+H(h,m),f)}return this}}),d.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){d.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!=="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!=="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(f){if(f===!0)continue}else g=o=!0}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b==="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1){}a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=u;typeof b==="string"&&!j.test(b)&&(b=b.toLowerCase(),d=b,g=t),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=u;typeof b==="string"&&!j.test(b)&&(b=b.toLowerCase(),d=b,g=t),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!=="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!=="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!=="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return"text"===c&&(b===c||b===null)},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(a===b){g=!0;return 0}if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};d.find=k,d.expr=k.selectors,d.expr[":"]=d.expr.filters,d.unique=k.uniqueSort,d.text=k.getText,d.isXMLDoc=k.isXML,d.contains=k.contains}();var I=/Until$/,J=/^(?:parents|prevUntil|prevAll)/,K=/,/,L=/^.[^:#\[\.,]*$/,M=Array.prototype.slice,N=d.expr.match.POS,O={children:!0,contents:!0,next:!0,prev:!0};d.fn.extend({find:function(a){var b=this.pushStack("","find",a),c=0;for(var e=0,f=this.length;e<f;e++){c=b.length,d.find(a,this[e],b);if(e>0)for(var g=c;g<b.length;g++)for(var h=0;h<c;h++)if(b[h]===b[g]){b.splice(g--,1);break}}return b},has:function(a){var b=d(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(d.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(Q(this,a,!1),"not",a)},filter:function(a){return this.pushStack(Q(this,a,!0),"filter",a)},is:function(a){return!!a&&d.filter(a,this).length>0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e<f;e++)i=a[e],j[i]||(j[i]=d.expr.match.POS.test(i)?d(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=N.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e<f;e++){g=this[e];while(g){if(l?l.index(g)>-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(P(c[0])||P(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=M.call(arguments);I.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!O[a]?d.unique(f):f,(this.length>1||K.test(e))&&J.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var R=/ jQuery\d+="(?:\d+|null)"/g,S=/^\s+/,T=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,U=/<([\w:]+)/,V=/<tbody/i,W=/<|&#?\w+;/,X=/<(?:script|object|embed|option|style)/i,Y=/checked\s*(?:[^=]|=\s*.checked.)/i,Z={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};Z.optgroup=Z.option,Z.tbody=Z.tfoot=Z.colgroup=Z.caption=Z.thead,Z.th=Z.td,d.support.htmlSerialize||(Z._default=[1,"div<div>","</div>"]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))});if(typeof a!=="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(R,""):null;if(typeof a!=="string"||X.test(a)||!d.support.leadingWhitespace&&S.test(a)||Z[(U.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(T,"<$1></$2>");try{for(var c=0,e=this.length;c<e;c++)this[c].nodeType===1&&(d.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(f){this.empty().append(a)}}return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(d.isFunction(a))return this.each(function(b){var c=d(this),e=c.html();c.replaceWith(a.call(this,b,e))});typeof a!=="string"&&(a=d(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;d(this).remove(),b?d(b).before(a):d(c).append(a)})}return this.length?this.pushStack(d(d.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,e){var f,g,h,i,j=a[0],k=[];if(!d.support.checkClone&&arguments.length===3&&typeof j==="string"&&Y.test(j))return this.each(function(){d(this).domManip(a,c,e,!0)});if(d.isFunction(j))return this.each(function(f){var g=d(this);a[0]=j.call(this,f,c?g.html():b),g.domManip(a,c,e)});if(this[0]){i=j&&j.parentNode,d.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?f={fragment:i}:f=d.buildFragment(a,this,k),h=f.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&d.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)e.call(c?$(this[l],g):this[l],f.cacheable||m>1&&l<n?d.clone(h,!0,!0):h)}k.length&&d.each(k,bc)}return this}}),d.buildFragment=function(a,b,e){var f,g,h,i=b&&b[0]?b[0].ownerDocument||b[0]:c;a.length===1&&typeof a[0]==="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!X.test(a[0])&&(d.support.checkClone||!Y.test(a[0]))&&(g=!0,h=d.fragments[a[0]],h&&(h!==1&&(f=h))),f||(f=i.createDocumentFragment(),d.clean(a,i,f,e)),g&&(d.fragments[a[0]]=h?f:1);return{fragment:f,cacheable:g}},d.fragments={},d.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){d.fn[a]=function(c){var e=[],f=d(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&f.length===1){f[b](this[0]);return this}for(var h=0,i=f.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){ba(a,e),f=bb(a),g=bb(e);for(h=0;f[h];++h)ba(f[h],g[h])}if(b){_(a,e);if(c){f=bb(a),g=bb(e);for(h=0;f[h];++h)_(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||W.test(i)){if(typeof i==="string"){i=i.replace(T,"<$1></$2>");var j=(U.exec(i)||["",""])[1].toLowerCase(),k=Z[j]||Z._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=V.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]==="<table>"&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&S.test(i)&&m.insertBefore(b.createTextNode(S.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bd=/alpha\([^)]*\)/i,be=/opacity=([^)]*)/,bf=/-([a-z])/ig,bg=/([A-Z]|^ms)/g,bh=/^-?\d+(?:px)?$/i,bi=/^-?\d/,bj={position:"absolute",visibility:"hidden",display:"block"},bk=["Left","Right"],bl=["Top","Bottom"],bm,bn,bo,bp=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bm(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bm)return bm(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bf,bp)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bq(a,b,e):d.swap(a,bj,function(){f=bq(a,b,e)});if(f<=0){f=bm(a,b,b),f==="0px"&&bo&&(f=bo(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bh.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return be.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bd.test(f)?f.replace(bd,e):c.filter+" "+e}}),d(function(){d.support.reliableMarginRight||(d.cssHooks.marginRight={get:function(a,b){var c;d.swap(a,{display:"inline-block"},function(){b?c=bm(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bn=function(a,c,e){var f,g,h;e=e.replace(bg,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bo=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bh.test(d)&&bi.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bm=bn||bo,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var br=/%20/g,bs=/\[\]$/,bt=/\r?\n/g,bu=/#.*$/,bv=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bw=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bx=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,by=/^(?:GET|HEAD)$/,bz=/^\/\//,bA=/\?/,bB=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bC=/^(?:select|textarea)/i,bD=/\s+/,bE=/([?&])_=[^&]*/,bF=/(^|\-)([a-z])/g,bG=function(a,b,c){return b+c.toUpperCase()},bH=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bI=d.fn.load,bJ={},bK={},bL,bM;try{bL=c.location.href}catch(bN){bL=c.createElement("a"),bL.href="",bL=bL.href}bM=bH.exec(bL.toLowerCase())||[],d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bI)return bI.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?d("<div>").append(c.replace(bB,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bC.test(this.nodeName)||bw.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(bt,"\r\n")}}):{name:b.name,value:c.replace(bt,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bL,isLocal:bx.test(bM[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bO(bJ),ajaxTransport:bO(bK),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bR(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bS(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bF,bG)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bv.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bu,"").replace(bz,bM[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bD),e.crossDomain==null&&(q=bH.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bM[1]||q[2]!=bM[2]||(q[3]||(q[1]==="http:"?80:443))!=(bM[3]||(bM[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bP(bJ,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!by.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(bA.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bE,"$1_="+w);e.url=x+(x===e.url?(bA.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bP(bK,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bQ(g,a[g],c,f);return e.join("&").replace(br,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bT=d.now(),bU=/(\=)\?(&|$)|\?\?/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bT++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bU.test(b.url)||f&&bU.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bU,l),b.url===j&&(f&&(k=k.replace(bU,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var bV=d.now(),bW,bX;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bZ()||b$()}:bZ,bX=d.ajaxSettings.xhr(),d.support.ajax=!!bX,d.support.cors=bX&&"withCredentials"in bX,bX=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),!a.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bW[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bW||(bW={},bY()),h=bV++,g.onreadystatechange=bW[h]=c):c()},abort:function(){c&&c(0,1)}}}});var b_={},ca=/^(?:toggle|show|hide)$/,cb=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cc,cd=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(ce("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)e=this[g],f=e.style.display,!d._data(e,"olddisplay")&&f==="none"&&(f=e.style.display=""),f===""&&d.css(e,"display")==="none"&&d._data(e,"olddisplay",cf(e.nodeName));for(g=0;g<h;g++){e=this[g],f=e.style.display;if(f===""||f==="none")e.style.display=d._data(e,"olddisplay")||""}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ce("hide",3),a,b,c);for(var e=0,f=this.length;e<f;e++){var g=d.css(this[e],"display");g!=="none"&&!d._data(this[e],"olddisplay")&&d._data(this[e],"olddisplay",g)}for(e=0;e<f;e++)this[e].style.display="none";return this},_toggle:d.fn.toggle,toggle:function(a,b,c){var e=typeof a==="boolean";d.isFunction(a)&&d.isFunction(b)?this._toggle.apply(this,arguments):a==null||e?this.each(function(){var b=e?a:d(this).is(":hidden");d(this)[b?"show":"hide"]()}):this.animate(ce("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,e){var f=d.speed(b,c,e);if(d.isEmptyObject(a))return this.each(f.complete);return this[f.queue===!1?"each":"queue"](function(){var b=d.extend({},f),c,e=this.nodeType===1,g=e&&d(this).is(":hidden"),h=this;for(c in a){var i=d.camelCase(c);c!==i&&(a[i]=a[c],delete a[c],c=i);if(a[c]==="hide"&&g||a[c]==="show"&&!g)return b.complete.call(this);if(e&&(c==="height"||c==="width")){b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(d.css(this,"display")==="inline"&&d.css(this,"float")==="none")if(d.support.inlineBlockNeedsLayout){var j=cf(this.nodeName);j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)}else this.style.display="inline-block"}d.isArray(a[c])&&((b.specialEasing=b.specialEasing||{})[c]=a[c][1],a[c]=a[c][0])}b.overflow!=null&&(this.style.overflow="hidden"),b.curAnim=d.extend({},a),d.each(a,function(c,e){var f=new d.fx(h,b,c);if(ca.test(e))f[e==="toggle"?g?"show":"hide":e](a);else{var i=cb.exec(e),j=f.cur();if(i){var k=parseFloat(i[2]),l=i[3]||(d.cssNumber[c]?"":"px");l!=="px"&&(d.style(h,c,(k||1)+l),j=(k||1)/f.cur()*j,d.style(h,c,j+l)),i[1]&&(k=(i[1]==="-="?-1:1)*k+j),f.custom(j,k,l)}else f.custom(j,e,"")}});return!0})},stop:function(a,b){var c=d.timers;a&&this.queue([]),this.each(function(){for(var a=c.length-1;a>=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:ce("show",1),slideUp:ce("hide",1),slideToggle:ce("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!cc&&(cc=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||d.fx.stop()},interval:13,stop:function(){clearInterval(cc),cc=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){d.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),d.expr&&d.expr.filters&&(d.expr.filters.animated=function(a){return d.grep(d.timers,function(b){return a===b.elem}).length});var cg=/^t(?:able|d|h)$/i,ch=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?d.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){d.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return d.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,g=f.documentElement;if(!c||!d.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=f.body,i=ci(f),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||d.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||d.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:d.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){d.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return d.offset.bodyOffset(b);d.offset.initialize();var c,e=b.offsetParent,f=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(d.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===e&&(l+=b.offsetTop,m+=b.offsetLeft,d.offset.doesNotAddBorder&&(!d.offset.doesAddBorderForTableAndCells||!cg.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),f=e,e=b.offsetParent),d.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;d.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},d.offset={initialize:function(){var a=c.body,b=c.createElement("div"),e,f,g,h,i=parseFloat(d.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=(e==="absolute"||e==="fixed")&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=ch.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!ch.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=ci(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=ci(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window); \ No newline at end of file diff --git a/js/osticket.js b/js/osticket.js index fd04ff48c809525267ebaacca85ac30cb37dd00a..a809e6f2f794a0534096c69b2a210428424d703d 100644 --- a/js/osticket.js +++ b/js/osticket.js @@ -1,79 +1 @@ -jQuery(function($) { - var max_uploads = 5; - var current_reply_uploads = 0; - var current_note_uploads = 0; - - function parse_upload(elem) { - var new_input = elem.clone(); - var filename = elem.val(); - if(filename != '') { - var container = elem.parent().parent(); - var form_type = container.attr('id'); - elem.blur().hide(); - $('.uploads', container).append('<div><label><input type="checkbox" name="uploads[]" value="' + filename + '" checked="checked"> ' + filename.replace('C:\\', '').replace('fakepath\\', '') + '</label></div>'); - if(form_type=='reply_form_attachments') { - current_reply_uploads++; - if(current_reply_uploads < max_uploads) { - elem.after(new_input.val('').blur()); - } - } else { - current_note_uploads++; - if(current_note_uploads < max_uploads) { - elem.after(new_input.val('').blur()); - } - } - } - } - - if($.browser.msie) { - $('.attachments').delegate('input[type=file]', 'click', function() { - var elem = $(this); - setTimeout(function() { - parse_upload(elem); - elem.blur(); - }, 0); - }); - } else { - $('.attachments').delegate('input[type=file]', 'change', function() { - var elem = $(this); - parse_upload(elem); - }); - } - - $('.uploads').delegate('.uploads input', 'click', function(e) { - e.preventDefault(); - var elem = $(this); - elem.attr('checked', 'checked'); - if(confirm("Are you sure you want to delete this attachment?")==true) { - var container = elem.parent().parent(); - var cparent = container.parent().parent(); - var form_type = cparent.attr('id'); - var filename = elem.val(); - $('input[type=file]', cparent).each(function() { - if($(this).val() == filename) { - $(this).remove(); - } - }); - container.remove(); - var new_input = $('input[type=file]:last', cparent).clone(); - var last_elem = $('input[type=file]:last', cparent); - if(form_type=='reply_form_attachments') { - current_reply_uploads--; - if(current_reply_uploads < max_uploads) { - if(last_elem.css('display')=='none') { - last_elem.after(new_input.val('').show()); - } - } - } else { - current_note_uploads--; - if(current_note_uploads < max_uploads) { - if(last_elem.css('display')=='none') { - last_elem.after(new_input.val('').show()); - } - } - } - } else { - e.preventDefault(); - } - }); -}); \ No newline at end of file +//Nothing for now... diff --git a/l.php b/l.php new file mode 100644 index 0000000000000000000000000000000000000000..657952e266f1498846db84c663e135997ecb242f --- /dev/null +++ b/l.php @@ -0,0 +1,29 @@ +<?php +/********************************************************************* + l.php + + Link redirection + + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require 'secure.inc.php'; + +global $_GET; +$url = $_GET['url']; +if (!$url) exit(); +?> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"/> + <meta http-equiv="refresh" content="0;<?php echo $url; ?>"/> +</head> +<body/> +</html> diff --git a/login.php b/login.php new file mode 100644 index 0000000000000000000000000000000000000000..044d74644785f32a0f79bae76e6c4309fd473b2a --- /dev/null +++ b/login.php @@ -0,0 +1,91 @@ +<?php +/********************************************************************* + login.php + + Client Login + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require_once('client.inc.php'); +if(!defined('INCLUDE_DIR')) die('Fatal Error'); +define('CLIENTINC_DIR',INCLUDE_DIR.'client/'); +define('OSTCLIENTINC',TRUE); //make includes happy + +require_once(INCLUDE_DIR.'class.client.php'); +require_once(INCLUDE_DIR.'class.ticket.php'); +//We are ready baby +$loginmsg='Authentication Required'; +if($_POST && (!empty($_POST['lemail']) && !empty($_POST['lticket']))): + $loginmsg='Authentication Required'; + $email=trim($_POST['lemail']); + $ticketID=trim($_POST['lticket']); + //$_SESSION['_client']=array(); #Uncomment to disable login strikes. + + //Check time for last max failed login attempt strike. + $loginmsg='Invalid login'; + if($_SESSION['_client']['laststrike']) { + if((time()-$_SESSION['_client']['laststrike'])<$cfg->getClientLoginTimeout()) { + $loginmsg='Excessive failed login attempts'; + $errors['err']='You\'ve reached maximum failed login attempts allowed. Try again later or <a href="open.php">open a new ticket</a>'; + }else{ //Timeout is over. + //Reset the counter for next round of attempts after the timeout. + $_SESSION['_client']['laststrike']=null; + $_SESSION['_client']['strikes']=0; + } + } + //See if we can fetch local ticket id associated with the ID given + if(!$errors && is_numeric($ticketID) && Validator::is_email($email) && ($ticket=Ticket::lookupByExtId($ticketID))) { + //At this point we know the ticket is valid. + //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? + //Check the email given. + if($ticket->getId() && strcasecmp($ticket->getEMail(),$email)==0){ + //valid match...create session goodies for the client. + $user = new ClientSession($email,$ticket->getId()); + $_SESSION['_client']=array(); //clear. + $_SESSION['_client']['userID'] =$ticket->getEmail(); //Email + $_SESSION['_client']['key'] =$ticket->getExtId(); //Ticket ID --acts as password when used with email. See above. + $_SESSION['_client']['token'] =$user->getSessionToken(); + $_SESSION['TZ_OFFSET']=$cfg->getTZoffset(); + $_SESSION['daylight']=$cfg->observeDaylightSaving(); + //Log login info... + $msg=sprintf("%s/%s logged in [%s]",$ticket->getEmail(),$ticket->getExtId(),$_SERVER['REMOTE_ADDR']); + Sys::log(LOG_DEBUG,'User login',$msg); + //Redirect tickets.php + session_write_close(); + session_regenerate_id(); + @header("Location: tickets.php?id=".$ticket->getExtId()); + require_once('tickets.php'); //Just incase. of header already sent error. + exit; + } + } + //If we get to this point we know the login failed. + $_SESSION['_client']['strikes']+=1; + if(!$errors && $_SESSION['_client']['strikes']>$cfg->getClientMaxLogins()) { + $loginmsg='Access Denied'; + $errors['err']='Forgot your login info? Please <a href="open.php">open a new ticket</a>.'; + $_SESSION['_client']['laststrike']=time(); + $alert='Excessive login attempts by a client?'."\n". + 'Email: '.$_POST['lemail']."\n".'Ticket#: '.$_POST['lticket']."\n". + 'IP: '.$_SERVER['REMOTE_ADDR']."\n".'Time:'.date('M j, Y, g:i a T')."\n\n". + 'Attempts #'.$_SESSION['_client']['strikes']; + Sys::log(LOG_ALERT,'Excessive login attempts (client)',$alert,($cfg->alertONLoginError())); + }elseif($_SESSION['_client']['strikes']%2==0){ //Log every other failed login attempt as a warning. + $alert='Email: '.$_POST['lemail']."\n".'Ticket #: '.$_POST['lticket']."\n".'IP: '.$_SERVER['REMOTE_ADDR']. + "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_client']['strikes']; + Sys::log(LOG_WARNING,'Failed login attempt (client)',$alert); + } +endif; + +$nav = new UserNav(); +$nav->setActiveNav('status'); +require(CLIENTINC_DIR.'header.inc.php'); +require(CLIENTINC_DIR.'login.inc.php'); +require(CLIENTINC_DIR.'footer.inc.php'); +?> diff --git a/logout.php b/logout.php new file mode 100644 index 0000000000000000000000000000000000000000..72c3560ecc7f540febb1ea0032c9b6cd39e2d3d6 --- /dev/null +++ b/logout.php @@ -0,0 +1,24 @@ +<?php +/********************************************************************* + logout.php + + Destroy clients session. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +require('client.inc.php'); +//We are checking to make sure the user is logged in before a logout to avoid session reset tricks on excess logins +$_SESSION['_client']=array(); +session_unset(); +session_destroy(); +header('Location: index.php'); +require('index.php'); +?> diff --git a/main.inc.php b/main.inc.php index 6fd211ed3b4505f825dc8869e92e8186d92c1e68..bb997ebd6cb5d1d98d30136a66c55bd8a79008a7 100644 --- a/main.inc.php +++ b/main.inc.php @@ -54,7 +54,7 @@ /*############## Do NOT monkey with anything else beyond this point UNLESS you really know what you are doing ##############*/ #Current version && schema signature (Changes from version to version) - define('THIS_VERSION','1.7 DPR'); //Shown on admin panel + define('THIS_VERSION','1.7-DPR2'); //Shown on admin panel define('SCHEMA_SIGNATURE','ssddsdsd'); //MD5 signature of the db schema. (used to trigger upgrades) #load config info @@ -102,9 +102,6 @@ #CURRENT EXECUTING SCRIPT. define('THISPAGE',Misc::currentURL()); - #pagenation default - define('PAGE_LIMIT',20); - # This is to support old installations. with no secret salt. if(!defined('SECRET_SALT')) define('SECRET_SALT',md5(TABLE_PREFIX.ADMIN_EMAIL)); @@ -164,10 +161,7 @@ $ferror='Unable to connect to the database'; }elseif(!($cfg=Sys::getConfig())){ $ferror='Unable to load config info from DB. Get tech support.'; - }elseif(!ini_get('short_open_tag')) { - $ferror='Short open tag disabled! - osTicket requires it turned ON.'; } - if($ferror){ //Fatal error Sys::alertAdmin('osTicket Fatal Error',$ferror); //try alerting admin. die("<b>Fatal Error:</b> Contact system administrator."); //Generic error. @@ -175,6 +169,11 @@ } //Init $cfg->init(); + + //System defaults we might want to make global// + #pagenation default - user can overwrite it! + define('DEFAULT_PAGE_LIMIT',$cfg->getPageSize()?$cfg->getPageSize():25); + //Start session handler! $session=osTicketSession::start(SESSION_TTL); // start_session //Set default timezone...staff will overwrite it. diff --git a/offline.php b/offline.php index 3c3b24a425c78badc335c45cc62a9022fa61d1f6..24f8401a14c9710de2f9bf7af3a13985a47a099d 100644 --- a/offline.php +++ b/offline.php @@ -14,6 +14,11 @@ vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ require_once('client.inc.php'); +if($cfg && !$cfg->isHelpDeskOffline()) { + @header('Location: index.php'); //Redirect if the system is online. + include('index.php'); + exit; +} $nav=null; require(CLIENTINC_DIR.'header.inc.php'); ?> diff --git a/open.php b/open.php new file mode 100644 index 0000000000000000000000000000000000000000..11d3a0a9d3397d64941886169a5fa2892ea663a1 --- /dev/null +++ b/open.php @@ -0,0 +1,55 @@ +<?php +/********************************************************************* + open.php + + New tickets handle. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require('client.inc.php'); +define('SOURCE','Web'); //Ticket source. +$inc='open.inc.php'; //default include. +$errors=array(); +if($_POST): + $_POST['deptId']=$_POST['emailId']=0; //Just Making sure we don't accept crap...only topicId is expected. + if($thisclient) { + $_POST['name']=$thisclient->getName(); + $_POST['email']=$thisclient->getEmail(); + } elseif($cfg->enableCaptcha()) { + if(!$_POST['captcha']) + $errors['captcha']='Enter text shown on the image'; + elseif(strcmp($_SESSION['captcha'],md5($_POST['captcha']))) + $errors['captcha']='Invalid - try again!'; + } + + //Ticket::create...checks for errors.. + if(($ticket=Ticket::create($_POST,$errors,SOURCE))){ + $msg='Support ticket request created'; + //Logged in...simply view the newly created ticket. + if($thisclient && $thisclient->isValid()) { + if(!$cfg->showRelatedTickets()) + $_SESSION['_client']['key']= $ticket->getExtId(); //Resetting login Key to the current ticket! + session_write_close(); + session_regenerate_id(); + @header('Location: tickets.php?id='.$ticket->getExtId()); + } + //Thank the user and promise speedy resolution! + $inc='thankyou.inc.php'; + }else{ + $errors['err']=$errors['err']?$errors['err']:'Unable to create a ticket. Please correct errors below and try again!'; + } +endif; + +//page +$nav->setActiveNav('new'); +require(CLIENTINC_DIR.'header.inc.php'); +require(CLIENTINC_DIR.$inc); +require(CLIENTINC_DIR.'footer.inc.php'); +?> diff --git a/scp/ajax.php b/scp/ajax.php index a65de32d2d166af48661eec772cedc414d3b87a1..471e9c710d577d662abae098ef2053dbfd702694 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -30,27 +30,28 @@ ini_set('display_startup_errors','0'); //TODO: disable direct access via the browser? i,e All request must have REFER? if(!defined('INCLUDE_DIR')) Http::response(500,'config error'); -require_once INCLUDE_DIR."/class.dispatcher.php"; -require_once INCLUDE_DIR."/class.ajax.php"; -$dispatcher = patterns("", - url("^/kb/", patterns("ajax.kbase.php:KbaseAjaxAPI", +require_once INCLUDE_DIR.'/class.dispatcher.php'; +require_once INCLUDE_DIR.'/class.ajax.php'; +$dispatcher = patterns('', + url('^/kb/', patterns('ajax.kbase.php:KbaseAjaxAPI', # Send ticket-id as a query arg => canned-response/33?ticket=83 - url_get("^canned-response/(?P<id>\d+).(?P<format>json|txt)", "cannedResp"), - url_get("^faq/(?P<id>\d+)","faq") + url_get('^canned-response/(?P<id>\d+).(?P<format>json|txt)', 'cannedResp'), + url_get('^faq/(?P<id>\d+)', 'faq') )), - url("^/content/", patterns("ajax.content.php:ContentAjaxAPI", - url_get("^log/(?P<id>\d+)", 'log'), - url_get("^ticket_variables",'ticket_variables') + url('^/content/', patterns('ajax.content.php:ContentAjaxAPI', + url_get('^log/(?P<id>\d+)', 'log'), + url_get('^ticket_variables', 'ticket_variables') )), - url("^/config/", patterns("ajax.config.php:ConfigAjaxAPI", - url_get("^ui",'ui') + url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI', + url_get('^ui', 'ui') )), - url_get("^/ticket$", array("ajax.tickets.php:TicketsAjaxAPI", "search")), - url("^/ticket/", patterns("ajax.tickets.php:TicketsAjaxAPI", - url_get("^(?P<tid>\d+)/preview", "previewTicket"), - url_get("^(?P<tid>\d+)/lock", "acquireLock"), - url_post("^(?P<tid>\d+)/lock/(?P<id>\d+)/renew", "renewLock"), - url_post("^(?P<tid>\d+)/lock/(?P<id>\d+)/release", "releaseLock") + url_get('^/users$', array('ajax.users.php:UsersAjaxAPI', 'search')), + url_get('^/tickets$', array('ajax.tickets.php:TicketsAjaxAPI', 'search')), + url('^/ticket/', patterns('ajax.tickets.php:TicketsAjaxAPI', + url_get('^(?P<tid>\d+)/preview', 'previewTicket'), + url_get('^(?P<tid>\d+)/lock', 'acquireLock'), + url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/renew', 'renewLock'), + url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/release', 'releaseLock') )) ); diff --git a/scp/css/login.css b/scp/css/login.css index 8516ea0e06cdf7f6a755a1cf31504da350f1df36..a15d4d12e5b0aec8970d802e0095ad53be00620f 100644 --- a/scp/css/login.css +++ b/scp/css/login.css @@ -1,88 +1,138 @@ +* { + box-sizing: border-box; + position: relative; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +*:focus { + outline-color: rgb(207,16,118); + outline-style: auto; + outline-width: 5px; + z-index:1000; +} + +:-webkit-input-placeholder { + color:#888; + font-style:italic; +} + +:-moz-placeholder { + color:#888; + font-style:italic; +} + +html { + height:100%; + font-size: 100%; + overflow-y: scroll; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + body { - background:url(/images/bg.gif) #fff; - font-family:arial, helvetica, sans-serif; - font-size:10pt; - color:#000; -} -body#loginBody { - text-align: center; - margin: 100px; -} -h1#logo { - float: none; - width: 190px; - height: 60px; - padding:10px 0 20px 0; - background: url(../images/logo-support.gif) center center no-repeat #fff; - margin: 0 auto 0 auto; -} -h1#logo a, h1#logo a:link, h1#logo a:visited, h1#logo a:hover { - display: block; - width: 190px; - height: 60px; - text-indent: -999em; - text-decoration: none; - background: none; - margin:0 auto 0 auto; -} - -input:focus, textarea:focus { - color: #F70; - background: #FEA; - -moz-outline-style: none; -} - -input[type="hidden"] { border: 0; } - -.submit { - font-family: Arial, Helvetica, sans-serif; - margin:10px auto 10px auto; - text-shadow: #333 -1px -1px 0px; - background-color: #DB8606; - color: #FFF; - border:1px solid #666; - font-weight:bold; - width:auto; + -webkit-font-smoothing:antialiased; + background:url(../images/login-background.jpg) top left repeat-x #fff; + font-size: 16px; + font-smoothing:antialiased; + height:100%; + line-height: 1.5em; + margin: 0; + text-align: center; } -input[type="submit"]:focus { - border: 1px solid #E50; - border-right-color: #FBA; - border-bottom-color: #FBA; - background: #F70; - color: #FEA; +body, input { + font-family: helvetica, arial, sans-serif; + font-size: 100%/1.5; + color: #000; } -h1 { font-size: 0.9em; color: #F70; margin: 0; text-align: center;} +input[type=reset], input[type=submit], input[type=button] { + display: inline-block; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -moz-tap-highlight-color: rgba(0, 0, 0, 0); + -o-tap-highlight-color: rgba(0, 0, 0, 0); + tap-highlight-color: rgba(0, 0, 0, 0); +} +#loginBox { + border:1px solid #2a67ac; + border-right:2px solid #2a67ac; + border-bottom:3px solid #2a67ac; + background:#fff; + width:400px; + margin:10% auto 0 auto; + padding:1em; + text-align:center; +} -div#loginBox { - width: 300px; - padding: 10px 20px 5px 20px; - margin: 0 auto 0 auto; - background: #fff; - text-align: center; - border:5px solid #ddd; +h1 { + margin:0; } -div#copyRights { - font-size: 0.8em; - text-align: center; - color:#666; + +#logo a { + display:block; + width:180px; + height:72px; + text-decoration:none; + text-indent:-9999px; + background:url(../images/login-logo.png); + margin:0 auto 1em auto; } -#copyRights a, #copyRights a:link, #copyRights a:visited, #copyRights a:hover { +h3 { + margin:1em 0; + text-align:center; + font-size:0.8em; + font-weight:normal; + color:#d00; +} - text-decoration: none; - background: none; - color:#666; +form { + width:220px; + margin:0 auto; + overflow:hidden; } +fieldset { + border:none; + margin:0; + padding:0; +} -input { - width: 175px; - margin-left: 5px +fieldset input { + display:block; + width:100%; + margin-bottom:1em; + border:1px solid #ccc; + background:#fff; + padding:2px; } -input[type="submit"] { width: auto; margin:10px auto 10px auto; } +input.submit { + display:inline-block; + float:right; + margin:0; + height:24px; + line-height:24px; + font-weight:bold; + border:1px solid #666666; + padding:0 10px; + background: url('../images/grey_btn_bg.png?1312910883') top left repeat-x; + color: #333; +} -table,form { margin-top:2px; padding: 0; } +input.submit:hover, input.submit:active { + background-position:bottom left; +} + +#copyRights { + font-size:0.7em; + color:#888; + padding:1em; + text-align:center; +} + +#copyRights a { + color:#888; +} diff --git a/scp/css/scp.css b/scp/css/scp.css index 85a4712cdca6d4b928694df2555d125831d9a385..5ccdbe543b0030b0fe910fc2382102bd997a4acc 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -926,6 +926,17 @@ h2 .reload { width:300px; } +.tip_content hr { + + color: #ddd; + background-color: #ddd; + height: 1px; + border: 0; + padding: 0; + margin: 0.2em 0; + width: 100%; +} + .tip_close { position:absolute; left:100%; @@ -950,7 +961,7 @@ h2 .reload { .tip_menu { margin:10px 0 0 0; padding:5px 0; - border-top:1px solid #ddd; + border-top:1px solid #aaa; height:16px; font-size:9pt; } diff --git a/scp/css/typeahead.css b/scp/css/typeahead.css new file mode 100644 index 0000000000000000000000000000000000000000..981923ab1f4c200b7121f5563171101dfea0a4d2 --- /dev/null +++ b/scp/css/typeahead.css @@ -0,0 +1,58 @@ +/* FROM bootstrap.css - just what is needed for typeahead */ +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 8px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #333333; + white-space: nowrap; +} +.dropdown-menu li > a:hover, +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} diff --git a/scp/images/grey_btn_bg.png b/scp/images/grey_btn_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..3b7fca9d3c41fcefd6ca49d6aa98ea3fc3fe1a41 Binary files /dev/null and b/scp/images/grey_btn_bg.png differ diff --git a/scp/images/login-background.jpg b/scp/images/login-background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eebfa40b8f24cf1a088e6d4eb1a6b279e958ad7c Binary files /dev/null and b/scp/images/login-background.jpg differ diff --git a/scp/images/login-logo.png b/scp/images/login-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6526ebe0a15f393382e0339b38cef8422d7ff471 Binary files /dev/null and b/scp/images/login-logo.png differ diff --git a/scp/js/bootstrap-typeahead.js b/scp/js/bootstrap-typeahead.js new file mode 100644 index 0000000000000000000000000000000000000000..1e039f02ade3395bac99ae5ef35ae113ce837879 --- /dev/null +++ b/scp/js/bootstrap-typeahead.js @@ -0,0 +1,318 @@ +/* ============================================================= + * bootstrap-typeahead.js v2.0.0 + * http://twitter.github.com/bootstrap/javascript.html#typeahead + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Typeahead = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.typeahead.defaults, options) + this.matcher = this.options.matcher || this.matcher + this.sorter = this.options.sorter || this.sorter + this.highlighter = this.options.highlighter || this.highlighter + this.$menu = $(this.options.menu).appendTo('body') + this.source = this.options.source + this.onselect = this.options.onselect + this.strings = true + this.shown = false + this.listen() + } + + Typeahead.prototype = { + + constructor: Typeahead + + , select: function () { + var val = JSON.parse(this.$menu.find('.active').attr('data-value')) + , text + + if (!this.strings) text = val[this.options.property] + else text = val + + this.$element.val(text) + + if (typeof this.onselect == "function") + this.onselect(val) + + return this.hide() + } + + , show: function () { + var pos = $.extend({}, this.$element.offset(), { + height: this.$element[0].offsetHeight + }) + + this.$menu.css({ + top: pos.top + pos.height + , left: pos.left + }) + + this.$menu.show() + this.shown = true + return this + } + + , hide: function () { + this.$menu.hide() + this.shown = false + return this + } + + , lookup: function (event) { + var that = this + , items + , q + , value + + this.query = this.$element.val(); + /*Check if we have a match on the current source?? */ + if (typeof this.source == "function") { + value = this.source(this, this.query) + if (value) this.process(value) + } else { + this.process(this.source) + } + } + + , process: function (results) { + var that = this + , items + , q + + if (results.length && typeof results[0] != "string") + this.strings = false + + this.query = this.$element.val() + + if (!this.query) { + return this.shown ? this.hide() : this + } + + items = $.grep(results, function (item) { + if (!that.strings) + item = item[that.options.property] + + if (that.matcher(item)) + return item + }) + + items = this.sorter(items) + + if (!items.length) { + return this.shown ? this.hide() : this + } + + return this.render(items.slice(0, this.options.items)).show() + } + + , matcher: function (item) { + return ~item.toLowerCase().indexOf(this.query.toLowerCase()) + } + + , sorter: function (items) { + var beginswith = [] + , caseSensitive = [] + , caseInsensitive = [] + , item + , sortby + + while (item = items.shift()) { + if (this.strings) sortby = item + else sortby = item[this.options.property] + + if (!sortby.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) + else if (~sortby.indexOf(this.query)) caseSensitive.push(item) + else caseInsensitive.push(item) + } + + return beginswith.concat(caseSensitive, caseInsensitive) + } + + , highlighter: function (item) { + return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) { + return '<strong>' + match + '</strong>' + }) + } + + , render: function (items) { + var that = this + + items = $(items).map(function (i, item) { + i = $(that.options.item).attr('data-value', JSON.stringify(item)) + if (!that.strings) { + if(item[that.options.render]) + item = item[that.options.render]; + else + item = item[that.options.property]; + } + i.find('a').html(that.highlighter(item)) + return i[0] + }) + + items.first().addClass('active') + this.$menu.html(items) + return this + } + + , next: function (event) { + var active = this.$menu.find('.active').removeClass('active') + , next = active.next() + + if (!next.length) { + next = $(this.$menu.find('li')[0]) + } + + next.addClass('active') + } + + , prev: function (event) { + var active = this.$menu.find('.active').removeClass('active') + , prev = active.prev() + + if (!prev.length) { + prev = this.$menu.find('li').last() + } + + prev.addClass('active') + } + + , listen: function () { + this.$element + .on('blur', $.proxy(this.blur, this)) + .on('keypress', $.proxy(this.keypress, this)) + .on('keyup', $.proxy(this.keyup, this)) + + if ($.browser.webkit || $.browser.msie) { + this.$element.on('keydown', $.proxy(this.keypress, this)) + } + + this.$menu + .on('click', $.proxy(this.click, this)) + .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) + } + + , keyup: function (e) { + e.stopPropagation() + e.preventDefault() + + switch(e.keyCode) { + case 40: // down arrow + case 38: // up arrow + break + + case 9: // tab + case 13: // enter + if (!this.shown) return + this.select() + break + + case 27: // escape + this.hide() + break + + default: + this.lookup() + } + + } + + , keypress: function (e) { + e.stopPropagation() + if (!this.shown) return + + switch(e.keyCode) { + case 9: // tab + case 13: // enter + case 27: // escape + e.preventDefault() + break + + case 38: // up arrow + e.preventDefault() + this.prev() + break + + case 40: // down arrow + e.preventDefault() + this.next() + break + } + } + + , blur: function (e) { + var that = this + e.stopPropagation() + e.preventDefault() + setTimeout(function () { that.hide() }, 150) + } + + , click: function (e) { + e.stopPropagation() + e.preventDefault() + this.select() + } + + , mouseenter: function (e) { + this.$menu.find('.active').removeClass('active') + $(e.currentTarget).addClass('active') + } + + } + + + /* TYPEAHEAD PLUGIN DEFINITION + * =========================== */ + + $.fn.typeahead = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('typeahead') + , options = typeof option == 'object' && option + if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.typeahead.defaults = { + source: [] + , items: 8 + , menu: '<ul class="typeahead dropdown-menu"></ul>' + , item: '<li><a href="#"></a></li>' + , onselect: null + , property: 'value' + , render: 'info' + } + + $.fn.typeahead.Constructor = Typeahead + + + /* TYPEAHEAD DATA-API + * ================== */ + + $(function () { + $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { + var $this = $(this) + if ($this.data('typeahead')) return + e.preventDefault() + $this.typeahead($this.data()) + }) + }) + +}( window.jQuery ); diff --git a/scp/js/scp.js b/scp/js/scp.js index 4f61090529b84749a91139ef237308ed3a5e31ee..7a9e0e218d1da97b3ec4b2860f307dd1c1769d1f 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -87,6 +87,9 @@ $(document).ready(function(){ if(!fObj.data('changed')){ fObj.data('changed', true); $('input[type=submit]', fObj).css('color', 'red'); + $(window).bind('beforeunload', function(e) { + return 'Are you sure you want to leave? Any changes or info you\'ve entered will be discarded!'; + }); } }); @@ -97,9 +100,19 @@ $(document).ready(function(){ $('label', fObj).removeAttr('style'); $('label', fObj).removeClass('strike'); fObj.data('changed', false); + $(window).unbind('beforeunload'); } }); + $('form#save').submit(function() { + $(window).unbind('beforeunload'); + + return true; + }); + + $('select#setting_options').change(function() { + $(this).closest('form').submit(); + }); $(".clearrule").live('click',function() { $(this).closest("tr").find(":input").val(''); @@ -185,4 +198,42 @@ $(document).ready(function(){ } } + /* Typeahead init */ + $('#basic-ticket-search').typeahead({ + source: function (typeahead, query) { + $.ajax({ + url: "ajax.php/tickets?q="+query, + dataType: 'json', + success: function (data) { + typeahead.process(data); + } + }); + }, + onselect: function (obj) { + $('#basic-ticket-search').closest('form').submit(); + }, + property: "value" + }); + + $('#email.typeahead').typeahead({ + source: function (typeahead, query) { + if(query.length > 2) { + $.ajax({ + url: "ajax.php/users?q="+query, + dataType: 'json', + success: function (data) { + typeahead.process(data); + } + }); + } + }, + onselect: function (obj) { + var fObj=$('#email.typeahead').closest('form'); + if(obj.name) + $('#name', fObj).val(obj.name); + }, + property: "email" + }); + + }); diff --git a/scp/l.php b/scp/l.php new file mode 100644 index 0000000000000000000000000000000000000000..2c66c2835eefcafb6711416228fa985878c43428 --- /dev/null +++ b/scp/l.php @@ -0,0 +1,29 @@ +<?php +/********************************************************************* + l.php + + Link redirection + + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require_once 'staff.inc.php'; + +global $_GET; +$url = $_GET['url']; +if (!$url) exit(); +?> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"/> + <meta http-equiv="refresh" content="0;<?php echo $url; ?>"/> +</head> +<body/> +</html> diff --git a/scp/settings.php b/scp/settings.php index 162ea816c844ec9702a2723a2ba672f391def96b..d7809d63751039c61639efd448c5718a888cb7ac 100644 --- a/scp/settings.php +++ b/scp/settings.php @@ -44,7 +44,7 @@ require(STAFFINC_DIR.'header.inc.php'); <div style="padding-top:10px;padding-bottom:5px;"> <form method="get" action="settings.php"> Setting Option: - <select name="t" style="width:300px;"> + <select id="setting_options" name="t" style="width:300px;"> <option value="">— Select Setting Group —</option> <?php foreach($SettingOptions as $k=>$v) { diff --git a/scp/staff.inc.php b/scp/staff.inc.php index 3c0d328809cbc94b37e9a2fee074ce6dabb08a97..b3ee30a4ec3a555c2fd8c3c86ed6e72b2c6517ca 100644 --- a/scp/staff.inc.php +++ b/scp/staff.inc.php @@ -79,11 +79,14 @@ if(!$thisstaff->isadmin()){ //Keep the session activity alive $thisstaff->refreshSession(); + +/******* SET STAFF DEFAULTS **********/ //Set staff's timezone offset. $_SESSION['TZ_OFFSET']=$thisstaff->getTZoffset(); $_SESSION['daylight']=$thisstaff->observeDaylight(); define('AUTO_REFRESH_RATE',$thisstaff->getRefreshRate()*60); +define('PAGE_LIMIT',$thisstaff->getPageLimit()?$thisstaff->getPageLimit():DEFAULT_PAGE_LIMIT); //Clear some vars. we use in all pages. $errors=array(); diff --git a/scp/tickets.php b/scp/tickets.php index da9dfa97e1ea8f37df2fcc718a950da6027d12c7..c881381e0d9ff9613b1e26e1df6c410157df664b 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -157,15 +157,15 @@ if($_POST && !$errors): $errors['note']='Error(s) occurred. Unable to post the note.'; } break; + case 'edit': case 'update': - $page='editticket.inc.php'; if(!$ticket || !$thisstaff->canEditTickets()) $errors['err']='Perm. Denied. You are not allowed to edit tickets'; - elseif($ticket->update($_POST,$errors)){ + elseif($ticket->update($_POST,$errors)) { $msg='Ticket updated successfully'; - $page='ticket.inc.php'; - }elseif(!$errors['err']) { - $errors['err']='Error(s) occured! Try again.'; + $_REQUEST['a'] = null; + } elseif(!$errors['err']) { + $errors['err']='Unable to update the ticket. Correct the errors below and try again!'; } break; case 'process': @@ -435,12 +435,20 @@ if($stats['overdue']) { $sysnotice=$stats['overdue'] .' overdue tickets!'; } -$nav->addSubMenu(array('desc'=>'Closed Tickets', - 'title'=>'Closed Tickets', - 'href'=>'tickets.php?status=closed', - 'iconclass'=>'closedTickets'), - ($_REQUEST['status']=='closed')); +if($thisstaff->showAssignedOnly() && $stats['closed']) { + $nav->addSubMenu(array('desc'=>'My Closed Tickets ('.$stats['closed'].')', + 'title'=>'My Closed Tickets', + 'href'=>'tickets.php?status=closed', + 'iconclass'=>'closedTickets'), + ($_REQUEST['status']=='closed')); +} else { + $nav->addSubMenu(array('desc'=>'Closed Tickets', + 'title'=>'Closed Tickets', + 'href'=>'tickets.php?status=closed', + 'iconclass'=>'closedTickets'), + ($_REQUEST['status']=='closed')); +} if($thisstaff->canCreateTickets()) { $nav->addSubMenu(array('desc'=>'New Ticket', @@ -454,14 +462,30 @@ $inc = 'tickets.inc.php'; if($ticket) { $nav->setActiveSubMenu(-1); $inc = 'ticket-view.inc.php'; - if($_REQUEST['a']=='edit' && $thisstaff->canEditTickets()) - $errors['err'] ='Work in progress... '; -}else { + if($_REQUEST['a']=='edit' && $thisstaff->canEditTickets()) + $inc = 'ticket-edit.inc.php'; +} else { $inc = 'tickets.inc.php'; if($_REQUEST['a']=='open' && $thisstaff->canCreateTickets()) $inc = 'ticket-open.inc.php'; - elseif(!$_POST && $_REQUEST['a']!='search' && ($min=$thisstaff->getRefreshRate())) - define('AUTO_REFRESH',1); //set refresh rate if the user has it configured + elseif($_REQUEST['a'] == 'export') { + require_once(INCLUDE_DIR.'class.export.php'); + $ts = strftime('%Y%m%d'); + if (!($token=$_REQUEST['h'])) + $errors['err'] = 'Query token required'; + elseif (!($query=$_SESSION['search_'.$token])) + $errors['err'] = 'Query token not found'; + elseif (!Export::saveTickets($query, "tickets-$ts.csv", 'csv')) + $errors['err'] = 'Internal error: Unable to dump query results'; + } + + //Clear active submenu on search with no status + if($_REQUEST['a']=='search' && !$_REQUEST['status']) + $nav->setActiveSubMenu(-1); + + //set refresh rate if the user has it configured + if(!$_POST && $_REQUEST['a']!='search' && ($min=$thisstaff->getRefreshRate())) + define('AUTO_REFRESH', $min*60); } require_once(STAFFINC_DIR.'header.inc.php'); diff --git a/secure.inc.php b/secure.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..3096b3503036e8746a58cea56aa2e85f977b4896 --- /dev/null +++ b/secure.inc.php @@ -0,0 +1,25 @@ +<?php +/********************************************************************* + secure.inc.php + + File included on every client's "secure" pages + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']),basename(__FILE__))) die('Kwaheri!'); +if(!file_exists('client.inc.php')) die('Fatal Error.'); +require_once('client.inc.php'); +//User must be logged in! +if(!$thisclient || !$thisclient->getId() || !$thisclient->isValid()){ + require('./login.php'); + exit; +} +$thisclient->refreshSession(); +?> diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php index c4d986c655ad6041591f879f7e4c077ef24ec6b7..c6bf7b6751c9e80236d3cbfe143a37c6d52cf6c5 100644 --- a/setup/inc/class.setup.php +++ b/setup/inc/class.setup.php @@ -303,7 +303,7 @@ class Installer extends SetupWizard { if(!$this->errors) { //Create admin user. $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() ' - .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8 ' + .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 ' .', email='.db_input($_POST['admin_email']) .', firstname='.db_input($vars['fname']) .', lastname='.db_input($vars['lname']) diff --git a/setup/inc/header.inc.php b/setup/inc/header.inc.php index 977050bc58441041b3036386aa634b804e568d6c..4c7d16e0f217da5cce7e5db5ee779964c2b9dc2e 100644 --- a/setup/inc/header.inc.php +++ b/setup/inc/header.inc.php @@ -1,6 +1,9 @@ -<!DOCTYPE html> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> <head> <title><?php echo $wizard['title']; ?></title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" href="css/wizard.css"> <script type="text/javascript" src="js/jquery-1.6.2.min.js"></script> <script type="text/javascript" src="js/tips.js"></script> diff --git a/setup/inc/install.inc.php b/setup/inc/install.inc.php index 5daefe123386f17458fe8afacf63d570b77cdca1..7f050baef479582a393d41e452b0adb3e42b4b8b 100644 --- a/setup/inc/install.inc.php +++ b/setup/inc/install.inc.php @@ -1,12 +1,6 @@ <?php if(!defined('SETUPINC')) die('Kwaheri!'); $info=($_POST && $errors)?Format::htmlchars($_POST):array('prefix'=>'ost_','dbhost'=>'localhost'); - -//XXX: Remove b4 release. -if($_SESSION['installer']['info'] && !$_POST) - $info=$_SESSION['installer']['info']; - - ?> <div id="main" class="step2"> <h1>osTicket Basic Installation</h1> diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql b/setup/inc/sql/osticket-v1.7-mysql.sql index a9966d536dd99e68378bc163e02da729b066352c..e6401d89f668d4c933b7dc0ab6e94b3642657bcd 100644 --- a/setup/inc/sql/osticket-v1.7-mysql.sql +++ b/setup/inc/sql/osticket-v1.7-mysql.sql @@ -311,8 +311,9 @@ CREATE TABLE `%TABLE_PREFIX%email_template` ( FULLTEXT KEY `message_subj` (`ticket_reply_subj`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- TODO: Dump revised copy before release!!! INSERT INTO `%TABLE_PREFIX%email_template` (`tpl_id`, `cfg_id`, `isactive`, `name`, `notes`, `ticket_autoresp_subj`, `ticket_autoresp_body`, `ticket_notice_subj`, `ticket_notice_body`, `ticket_alert_subj`, `ticket_alert_body`, `message_autoresp_subj`, `message_autoresp_body`, `message_alert_subj`, `message_alert_body`, `note_alert_subj`, `note_alert_body`, `assigned_alert_subj`, `assigned_alert_body`, `transfer_alert_subj`, `transfer_alert_body`, `ticket_overdue_subj`, `ticket_overdue_body`, `ticket_overlimit_subj`, `ticket_overlimit_body`, `ticket_reply_subj`, `ticket_reply_body`, `created`, `updated`) VALUES -(1, 1, 1, 'osTicket Default Template', 'Default osTicket templates', 'Support Ticket Opened [#%ticket]', '%name,\r\n\r\nA request for support has been created and assigned ticket #%ticket. A representative will follow-up with you as soon as possible.\r\n\r\nYou can view this ticket''s progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\nIf you wish to send additional comments or information regarding this issue, please don''t open a new ticket. Simply login using the link above and update the ticket.\r\n\r\n%signature', '[#%ticket] %subject', '%name,\r\n\r\nOur customer care team has created a ticket, #%ticket on your behalf, with the following message.\r\n\r\n%message\r\n\r\nIf you wish to provide additional comments or information regarding this issue, please don''t open a new ticket. You can update or view this ticket''s progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\n%signature', 'New Ticket Alert', '%staff,\r\n\r\nNew ticket #%ticket created.\r\n-------------------\r\nName: %name\r\nEmail: %email\r\nDept: %dept\r\n\r\n%message\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', '[#%ticket] Message Added', '%name,\r\n\r\nYour reply to support request #%ticket has been noted.\r\n\r\nYou can view this support request progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\n%signature', 'New Message Alert', '%staff,\r\n\r\nNew message appended to ticket #%ticket\r\n\r\n----------------------\r\nName: %name\r\nEmail: %email\r\nDept: %dept\r\n\r\n%message\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'New Internal Note Alert', '%staff,\r\n\r\nInternal note appended to ticket #%ticket\r\n\r\n----------------------\r\nName: %name\r\n\r\n%note\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'Ticket #%ticket Assigned to you', '%assignee,\r\n\r\n%assigner has assigned ticket #%ticket to you or one of your teams!\r\n\r\n%note\r\n\r\nTo view complete details, simply login to the support system.\r\n\r\n%url/scp/tickets.php?id=%id\r\n\r\n- Your friendly Support Ticket System - powered by osTicket.', 'Ticket Transfer #%ticket - %dept', '%staff,\r\n\r\nTicket #%ticket has been transferred to %dept department\r\n\r\n----------------------\r\n\r\n%note\r\n\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n%url/scp/ticket.php?id=%id\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'Stale Ticket Alert', '%staff,\r\n\r\nA ticket, #%ticket assigned to you or in your department is seriously overdue.\r\n\r\n%url/scp/tickets.php?id=%id\r\n\r\nWe should all work hard to guarantee that all tickets are being addressed in a timely manner. Enough baby talk...please address the issue or you will hear from me again.\r\n\r\n\r\n- Your friendly (although with limited patience) Support Ticket System - powered by osTicket.', 'Support Ticket Denied', '%name\r\n\r\nNo support ticket has been created. You''ve exceeded maximum number of open tickets allowed.\r\n\r\nThis is a temporary block. To be able to open another ticket, one of your pending tickets must be closed. To update or add comments to an open ticket simply login using the link below.\r\n\r\n%url/view.php?e=%email\r\n\r\nThank you.\r\n\r\nSupport Ticket System', '[#%ticket] %subject', '%name,\r\n\r\nA customer support staff member has replied to your support request, #%ticket with the following response:\r\n\r\n%response\r\n\r\nWe hope this response has sufficiently answered your questions. If not, please do not send another email. Instead, reply to this email or login to your account for a complete archive of all your support requests and responses.\r\n\r\n%url/view.php?e=%email&t=%ticket\r\n\r\n%signature', '2011-08-05 17:00:03', '2012-03-19 01:44:54'); +(1, 1, 1, 'osTicket Default Template', 'Default osTicket templates', 'Support Ticket Opened [#%ticket]', '%name,\r\n\r\nA request for support has been created and assigned ticket #%ticket. A representative will follow-up with you as soon as possible.\r\n\r\nYou can view this ticket''s progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\nIf you wish to send additional comments or information regarding this issue, please don''t open a new ticket. Simply login using the link above and update the ticket.\r\n\r\n%signature', '[#%ticket] %subject', '%name,\r\n\r\nOur customer care team has created a ticket, #%ticket on your behalf, with the following message.\r\n\r\n%message\r\n\r\nIf you wish to provide additional comments or information regarding this issue, please don''t open a new ticket. You can update or view this ticket''s progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\n%signature', 'New Ticket Alert', '%staff,\r\n\r\nNew ticket #%ticket created.\r\n-------------------\r\nName: %name\r\nEmail: %email\r\nDept: %dept\r\n\r\n%message\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', '[#%ticket] Message Added', '%name,\r\n\r\nYour reply to support request #%ticket has been noted.\r\n\r\nYou can view this support request progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\n%signature', 'New Message Alert', '%staff,\r\n\r\nNew message appended to ticket #%ticket\r\n\r\n----------------------\r\nName: %name\r\nEmail: %email\r\nDept: %dept\r\n\r\n%message\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'New Internal Note Alert', '%staff,\r\n\r\nInternal note appended to ticket #%ticket\r\n\r\n----------------------\r\nName: %name\r\n\r\n%note\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'Ticket #%ticket Assigned to you', '%assignee,\r\n\r\n%assigner has assigned ticket #%ticket to you or one of your teams!\r\n\r\n%note\r\n\r\nTo view complete details, simply login to the support system.\r\n\r\n%url/scp/tickets.php?id=%id\r\n\r\n- Your friendly Support Ticket System - powered by osTicket.', 'Ticket Transfer #%ticket - %dept', '%staff,\r\n\r\nTicket #%ticket has been transferred to %dept department\r\n\r\n----------------------\r\n\r\n%note\r\n\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n%url/scp/ticket.php?id=%id\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'Stale Ticket Alert', '%staff,\r\n\r\nA ticket, #%ticket assigned to you or in your department is seriously overdue.\r\n\r\n%url/scp/tickets.php?id=%id\r\n\r\nWe should all work hard to guarantee that all tickets are being addressed in a timely manner. Enough baby talk...please address the issue or you will hear from me again.\r\n\r\n\r\n- Your friendly (although with limited patience) Support Ticket System - powered by osTicket.', 'Open Tickets Limit Reached', '%name\r\n\r\nYou've reached the maximum number of open tickets allowed.\r\n\r\nTo be able to open another ticket, one of your pending tickets must be closed. To update or add comments to an open ticket simply login using the link below.\r\n\r\n%url/view.php?e=%email\r\n\r\nThank you.\r\n\r\nSupport Ticket System', '[#%ticket] %subject', '%name,\r\n\r\nA customer support staff member has replied to your support request, #%ticket with the following response:\r\n\r\n%response\r\n\r\nWe hope this response has sufficiently answered your questions. If not, please do not send another email. Instead, reply to this email or login to your account for a complete archive of all your support requests and responses.\r\n\r\n%url/view.php?e=%email&t=%ticket\r\n\r\n%signature', '2011-08-05 17:00:03', '2012-03-19 01:44:54'); DROP TABLE IF EXISTS `%TABLE_PREFIX%file`; CREATE TABLE `%TABLE_PREFIX%file` ( @@ -446,8 +447,8 @@ CREATE TABLE `%TABLE_PREFIX%sla` ( ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `%TABLE_PREFIX%sla` (`isactive`, `enable_priority_escalation`, - `disable_overdue_alerts`, `grace_period`, `name`, `notes`) - VALUES (1, 1, 0, 48, 'Default SLA', NULL); + `disable_overdue_alerts`, `grace_period`, `name`, `notes`, `created`, `updated`) + VALUES (1, 1, 0, 48, 'Default SLA', NULL, NOW(), NOW()); DROP TABLE IF EXISTS `%TABLE_PREFIX%staff`; CREATE TABLE `%TABLE_PREFIX%staff` ( diff --git a/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql b/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql index eb7442a5f9f4a13191f7d0cd1c97f8c5c8ec3d4b..efeb8de6f26eb4e4c4a5e10140147c5b1ebdd3c6 100644 --- a/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql +++ b/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql @@ -78,8 +78,8 @@ CREATE TABLE IF NOT EXISTS `%TICKET_PREFIX%sla` ( -- Create a default SLA INSERT INTO `%TABLE_PREFIX%sla` (`isactive`, `enable_priority_escalation`, - `disable_overdue_alerts`, `grace_period`, `name`, `notes`) - VALUES (1, 1, 0, 48, 'Default SLA', NULL); + `disable_overdue_alerts`, `grace_period`, `name`, `notes`, `created`, `updated`) + VALUES (1, 1, 0, 48, 'Default SLA', NULL, NOW(), NOW()); -- Create a TEAM table CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%team` ( diff --git a/setup/inc/upgrade-attachments.inc.php b/setup/inc/upgrade-attachments.inc.php index 1a69526454fa6e695b6d50c3f9b305acafd110d8..c8155d32c672e358cb068d79720a076327a88706 100644 --- a/setup/inc/upgrade-attachments.inc.php +++ b/setup/inc/upgrade-attachments.inc.php @@ -1,6 +1,6 @@ <?php if(!defined('SETUPINC')) die('Kwaheri!'); -$msg = $_SESSION['upgrader']['msg']; +$msg = $_SESSION['ost_upgrader']['msg']; ?> <div id="main"> <h1>Attachments Migration</h1> diff --git a/setup/install.php b/setup/install.php index e7f68e9d5f203e3a6960fdb229449a48682021ea..27b1388933d03ef9c0db5690dd147213848d750f 100644 --- a/setup/install.php +++ b/setup/install.php @@ -29,11 +29,11 @@ $wizard['menu']=array('Installation Guide'=>'http://osticket.com/wiki/Installati if($_POST && $_POST['s']) { $errors = array(); - $_SESSION['installer']['s']=$_POST['s']; + $_SESSION['ost_installer']['s']=$_POST['s']; switch(strtolower($_POST['s'])) { case 'prereq': if($installer->check_prereq()) - $_SESSION['installer']['s']='config'; + $_SESSION['ost_installer']['s']='config'; else $errors['prereq']='Minimum requirements not met!'; break; @@ -43,7 +43,7 @@ if($_POST && $_POST['s']) { elseif(!$installer->config_writable()) $errors['err']='Write access required to continue'; else - $_SESSION['installer']['s']='install'; + $_SESSION['ost_installer']['s']='install'; break; case 'install': if($installer->install($_POST)) { @@ -51,7 +51,7 @@ if($_POST && $_POST['s']) { 'email' =>$_POST['admin_email'], 'URL'=>URL); //TODO: Go to subscribe step. - $_SESSION['installer']['s']='done'; + $_SESSION['ost_installer']['s']='done'; } elseif(!($errors=$installer->getErrors()) || !$errors['err']) { $errors['err']='Error installing osTicket - correct the errors below and try again.'; } @@ -69,16 +69,16 @@ if($_POST && $_POST['s']) { $errors['notify'] = 'Check one or more'; if(!$errors) - $_SESSION['installer']['s'] = 'done'; + $_SESSION['ost_installer']['s'] = 'done'; break; } -}elseif($_GET['s'] && $_GET['s']=='ns' && $_SESSION['installer']['s']=='subscribe') { - $_SESSION['installer']['s']='done'; +}elseif($_GET['s'] && $_GET['s']=='ns' && $_SESSION['ost_installer']['s']=='subscribe') { + $_SESSION['ost_installer']['s']='done'; } -switch(strtolower($_SESSION['installer']['s'])) { +switch(strtolower($_SESSION['ost_installer']['s'])) { case 'config': case 'install': if(!$installer->config_exists()) { diff --git a/setup/js/tips.js b/setup/js/tips.js index d7214dc6379caabd7b210865bb930bb7f4891a7a..76c20421a28c9301a92497a778de881e1e4f91fe 100644 --- a/setup/js/tips.js +++ b/setup/js/tips.js @@ -45,4 +45,3 @@ jQuery(function($) { $(this).parent().parent().remove(); }); }); - diff --git a/setup/setup.inc.php b/setup/setup.inc.php index 7fc66597717bbcf4ef7a092b25329d2460e1ece4..f2af40af61e1b7e94b9ae915eb1e81e103560594 100644 --- a/setup/setup.inc.php +++ b/setup/setup.inc.php @@ -15,13 +15,21 @@ **********************************************************************/ #inits -error_reporting(E_ALL ^ E_NOTICE); //turn on errors +error_reporting(E_ALL ^ E_NOTICE); //turn on errors?? ini_set('magic_quotes_gpc', 0); ini_set('session.use_trans_sid', 0); ini_set('session.cache_limiter', 'nocache'); ini_set('display_errors',1); //We want the user to see errors during install process. ini_set('display_startup_errors',1); +#Disable Globals if enabled +if(ini_get('register_globals')) { + ini_set('register_globals',0); + foreach($_REQUEST as $key=>$val) + if(isset($$key)) + unset($$key); +} + #start session session_start(); diff --git a/tickets.php b/tickets.php new file mode 100644 index 0000000000000000000000000000000000000000..d4759ba522e328911d2e9a494254ce338ea7f905 --- /dev/null +++ b/tickets.php @@ -0,0 +1,89 @@ +<?php +/********************************************************************* + tickets.php + + Main client/user interface. + Note that we are using external ID. The real (local) ids are hidden from user. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require('secure.inc.php'); +if(!is_object($thisclient) || !$thisclient->isValid()) die('Access denied'); //Double check again. +require_once(INCLUDE_DIR.'class.ticket.php'); +$ticket=null; +if($_REQUEST['id']) { + if(!($ticket=Ticket::lookupByExtId($_REQUEST['id']))) { + $errors['err']='Unknown or invalid ticket ID.'; + }elseif(!$ticket->checkClientAccess($thisclient)) { + $errors['err']='Unknown or invalid ticket ID.'; //Using generic message on purpose! + $ticket=null; + } +} + +//Process post...depends on $ticket object above. +if($_POST && is_object($ticket) && $ticket->getId()): + $errors=array(); + switch(strtolower($_POST['a'])){ + case 'reply': + if(!$ticket->checkClientAccess($thisclient)) //double check perm again! + $errors['err']='Access Denied. Possibly invalid ticket ID'; + + if(!$_POST['message']) + $errors['message']='Message required'; + + //check attachment..if any is set + $files=($cfg->allowOnlineAttachments() && $_FILES['attachments'])?Format::files($_FILES['attachments']):array(); + if($files) { + + foreach($files as $file) { + if(!$file['name']) continue; + + if(!$cfg->canUploadFileType($file['name'])) + $errors['attachment']='Invalid file type [ '.$file['name'].' ]'; + elseif($file['size']>$cfg->getMaxFileSize()) + $errors['attachment']='File '.$file['name'].'is too big. Max '.$cfg->getMaxFileSize().' bytes allowed'; + } + } + + if(!$errors){ + //Everything checked out...do the magic. + if(($msgid=$ticket->postMessage($_POST['message'],'Web'))) { + if($files && $cfg->allowOnlineAttachments()) + $ticket->uploadAttachments($files,$msgid,'M'); + + $msg='Message Posted Successfully'; + } else { + $errors['err']='Unable to post the message. Try again'; + } + + } elseif(!$errors['err']) { + print_r($errors); + $errors['err']='Error(s) occurred. Please try again'; + + } + break; + default: + $errors['err']='Uknown action'; + } + $ticket->reload(); +endif; +$nav->setActiveNav('tickets'); +if($ticket && $ticket->checkClientAccess($thisclient)) { + $inc='view.inc.php'; +} elseif($cfg->showRelatedTickets() && $thisclient->getNumTickets()) { + $inc='tickets.inc.php'; +} else { + $nav->setActiveNav('new'); + $inc='open.inc.php'; +} +include(CLIENTINC_DIR.'header.inc.php'); +include(CLIENTINC_DIR.$inc); +include(CLIENTINC_DIR.'footer.inc.php'); +?> diff --git a/view.php b/view.php new file mode 100644 index 0000000000000000000000000000000000000000..984b04c3019645c6ca1d075bbab0aac8460e4094 --- /dev/null +++ b/view.php @@ -0,0 +1,21 @@ +<?php +/********************************************************************* + view.php + + Ticket View. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2010 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: + $Id: $ +**********************************************************************/ +require('secure.inc.php'); +if(!is_object($thisclient) || !$thisclient->isValid()) die('Access denied'); //Double check again. +//We are now using tickets.php but we need to keep view.php for backward compatibility +require('tickets.php'); +?>