File: kriss.php - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

0001: <?php
0002: // kriss_feed simple and smart (or stupid) feed reader
0003: // 2012 - Copyleft - Tontof - http://tontof.net
0004: // use KrISS feed at your own risk
0005: define('DATA_DIR', 'data');
0006: define('INC_DIR', 'inc');
0007: define('CACHE_DIR', DATA_DIR.'/cache');
0008: define('FAVICON_DIR', INC_DIR.'/favicon');
0009: 
0010: define('DATA_FILE', DATA_DIR.'/data.php');
0011: define('CONFIG_FILE', DATA_DIR.'/config.php');
0012: define('STYLE_FILE', 'style.css');
0013: 
0014: define('BAN_FILE', DATA_DIR.'/ipbans.php');
0015: 
0016: define('FEED_VERSION', 6);
0017: 
0018: define('PHPPREFIX', '<?php /* '); // Prefix to encapsulate data in php code.
0019: define('PHPSUFFIX', ' */ ?>'); // Suffix to encapsulate data in php code.
0020: 
0021: define('MIN_TIME_UPDATE', 5); // Minimum accepted time for update
0022: 
0023: define('ERROR_NO_ERROR', 0);
0024: define('ERROR_NO_XML', 1);
0025: define('ERROR_ITEMS_MISSED', 2);
0026: define('ERROR_LAST_UPDATE', 3);
0027: define('ERROR_UNKNOWN', 4);
0028: 
0029: // fix some warning
0030: date_default_timezone_set('Europe/Paris');
0031: 
0032: if (!is_dir(DATA_DIR)) {
0033:     if (!@mkdir(DATA_DIR, 0755)) {
0034:         echo '
0035: <script>
0036:  alert("Error: can not create '.DATA_DIR.' directory, check permissions");
0037:  document.location=window.location.href;
0038: </script>';
0039:         exit();
0040:     }
0041:     @chmod(DATA_DIR, 0755);
0042:     if (!is_file(DATA_DIR.'/.htaccess')) {
0043:         if (!@file_put_contents(
0044:                 DATA_DIR.'/.htaccess',
0045:                 "Allow from none\nDeny from all\n"
0046:                 )) {
0047:             echo '
0048: <script>
0049:  alert("Can not protect '.DATA_DIR.'");
0050:  document.location=window.location.href;
0051: </script>';
0052:             exit();
0053:         }
0054:     }
0055: }
0056: 
0057: /* function grabFavicon */
0058: function grabFavicon($url, $feedHash){
0059:     $url = 'http://getfavicon.appspot.com/'.$url.'?defaulticon=bluepng';
0060:     $file = FAVICON_DIR.'/favicon.'.$feedHash.'.ico';
0061: 
0062:     if(!file_exists($file) && in_array('curl', get_loaded_extensions()) && Session::isLogged()){
0063:         $ch = curl_init ($url);
0064:         curl_setopt($ch, CURLOPT_HEADER, false);
0065:         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
0066:         curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
0067:         $raw = curl_exec($ch);
0068:         if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200) {
0069:             $fp = fopen($file, 'x');
0070:             fwrite($fp, $raw);
0071:             fclose($fp);
0072:         }
0073:         curl_close ($ch);
0074:     }
0075: 
0076:     if (file_exists($file)) {
0077:         return $file;
0078:     } else {
0079:         return $url;
0080:     }
0081: }
0082: 
0083: 
0084: class FeedConf
0085: {
0086:     private $_file = '';
0087: 
0088:     public $login = '';
0089: 
0090:     public $hash = '';
0091: 
0092:     public $disableSessionProtection = false;
0093: 
0094:     public $salt = '';
0095: 
0096:     public $title = "Kriss feed";
0097: 
0098:     public $redirector = '';
0099: 
0100:     public $locale = 'en_GB';
0101: 
0102:     public $shaarli = '';
0103: 
0104:     public $maxItems = 100;
0105: 
0106:     public $maxUpdate = 60;
0107: 
0108:     public $order = 'newerFirst';
0109: 
0110:     public $autoreadItem = false;
0111: 
0112:     public $autoreadPage = false;
0113: 
0114:     public $autoUpdate = false;
0115: 
0116:     public $autohide = false;
0117: 
0118:     public $autofocus = true;
0119: 
0120:     public $addFavicon = false;
0121: 
0122:     public $public = false;
0123: 
0124:     public $version;
0125: 
0126:     public $view = 'list';
0127: 
0128:     public $filter = 'unread';
0129: 
0130:     public $listFeeds = 'show';
0131: 
0132:     public $byPage = 10;
0133: 
0134:     public $currentHash = 'all';
0135: 
0136:     public $currentPage = 1;
0137: 
0138:     public $menuView = 1;
0139:     public $menuListFeeds = 2;
0140:     public $menuFilter = 3;
0141:     public $menuOrder = 4;
0142:     public $menuUpdate = 5;
0143:     public $menuRead = 6;
0144:     public $menuUnread = 7;
0145:     public $menuEdit = 8;
0146:     public $menuAdd = 9;
0147:     public $menuHelp = 10;
0148: 
0149:     public $pagingItem = 1;
0150:     public $pagingPage = 2;
0151:     public $pagingByPage = 3;
0152:     public $pagingMarkAs = 4;
0153: 
0154:     public function __construct($configFile, $version)
0155:     {
0156:         $this->_file = $configFile;
0157:         $this->version = $version;
0158: 
0159:         // Loading user config
0160:         if (file_exists($this->_file)) {
0161:             include_once $this->_file;
0162:         } else {
0163:             $this->_install();
0164:         }
0165: 
0166:         Session::$disableSessionProtection = $this->disableSessionProtection;
0167: 
0168:         if ($this->addFavicon) {
0169:             /* favicon dir */
0170:             if (!is_dir(INC_DIR)) {
0171:                 if (!@mkdir(INC_DIR, 0755)) {
0172:                     die("Can not create inc dir: ".INC_DIR);
0173:                 }
0174:             }
0175:             if (!is_dir(FAVICON_DIR)) {
0176:                 if (!@mkdir(FAVICON_DIR, 0755)) {
0177:                     die("Can not create inc dir: ".FAVICON_DIR);
0178:                 }
0179:             }
0180:         }
0181: 
0182:         if (Session::isLogged()) {
0183:             unset($_SESSION['view']);
0184:             unset($_SESSION['listFeeds']);
0185:             unset($_SESSION['filter']);
0186:             unset($_SESSION['order']);
0187:             unset($_SESSION['byPage']);
0188:         }
0189: 
0190:         $view = $this->getView();
0191:         $listFeeds = $this->getListFeeds();
0192:         $filter = $this->getFilter();
0193:         $order = $this->getOrder();
0194:         $byPage = $this->getByPage();
0195: 
0196:         if ($this->view != $view
0197:             || $this->listFeeds != $listFeeds
0198:             || $this->filter != $filter
0199:             || $this->order != $order
0200:             || $this->byPage != $byPage
0201:         ) {
0202:             $this->view = $view;
0203:             $this->listFeeds = $listFeeds;
0204:             $this->filter = $filter;
0205:             $this->order = $order;
0206:             $this->byPage = $byPage;
0207: 
0208:             if (Session::isLogged()) {
0209:                 $this->write();
0210:             }
0211:         }
0212: 
0213:         if (!Session::isLogged()) {
0214:             $_SESSION['view'] = $view;
0215:             $_SESSION['listFeeds'] = $listFeeds;
0216:             $_SESSION['filter'] = $filter;
0217:             $_SESSION['order'] = $order;
0218:             $_SESSION['byPage'] = $byPage;
0219:         }
0220:     }
0221: 
0222:     private function _install()
0223:     {
0224:         if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) {
0225:             $this->setSalt(sha1(uniqid('', true).'_'.mt_rand()));
0226:             $this->setLogin($_POST['setlogin']);
0227:             $this->setHash($_POST['setpassword']);
0228: 
0229:             if ($this->write()) {
0230:                 echo '
0231: <script>
0232:  alert("Your simple and smart (or stupid) feed reader is now configured.");
0233:  document.location="'.MyTool::getUrl().'?import'.'";
0234: </script>';
0235:                     exit();
0236:             } else {
0237:                 echo '
0238: <script>
0239:  alert("Error: can not write config and data files.");
0240:  document.location=window.location.href;
0241: </script>';
0242:                     exit();
0243:             }
0244:             Session::logout();
0245:         } else {
0246:             FeedPage::init(
0247:                 array(
0248:                     'version' => $this->version,
0249:                     'pagetitle' => 'KrISS feed installation'
0250:                 )
0251:             );
0252:             FeedPage::installTpl();
0253:         }
0254:         exit();
0255:     }
0256: 
0257:     public function hydrate(array $data)
0258:     {
0259:         foreach ($data as $key => $value) {
0260:             // get setter
0261:             $method = 'set'.ucfirst($key);
0262:             // if setter exists just call it
0263:             // (php is not case-sensitive with functions)
0264:             if (method_exists($this, $method)) {
0265:                 $this->$method($value);
0266:             }
0267:         }
0268: 
0269:         if (!$this->write()) {
0270:             die("Can't write to ".CONFIG_FILE);
0271:         }
0272:     }
0273: 
0274:     public function getView()
0275:     {
0276:         $view = $this->view;
0277:         if (isset($_GET['view'])) {
0278:             if ($_GET['view'] == 'expanded') {
0279:                 $view = 'expanded';
0280:             }
0281:             if ($_GET['view'] == 'list') {
0282:                 $view = 'list';
0283:             }
0284:         } else if (isset($_SESSION['view'])) {
0285:             $view = $_SESSION['view'];
0286:         }
0287: 
0288:         return $view;
0289:     }
0290: 
0291:     public function getFilter()
0292:     {
0293:         $filter = $this->filter;
0294:         if (isset($_GET['filter'])) {
0295:             if ($_GET['filter'] == 'unread') {
0296:                 $filter = 'unread';
0297:             }
0298:             if ($_GET['filter'] == 'all') {
0299:                 $filter = 'all';
0300:             }
0301:         } else if (isset($_SESSION['filter'])) {
0302:             $filter = $_SESSION['filter'];
0303:         }
0304: 
0305:         return $filter;
0306:     }
0307: 
0308:     public function getListFeeds()
0309:     {
0310:         $listFeeds = $this->listFeeds;
0311:         if (isset($_GET['listFeeds'])) {
0312:             if ($_GET['listFeeds'] == 'show') {
0313:                 $listFeeds = 'show';
0314:             }
0315:             if ($_GET['listFeeds'] == 'hide') {
0316:                 $listFeeds = 'hide';
0317:             }
0318:         } else if (isset($_SESSION['listFeeds'])) {
0319:             $listFeeds = $_SESSION['listFeeds'];
0320:         }
0321: 
0322:         return $listFeeds;
0323:     }
0324: 
0325:     public function getByPage()
0326:     {
0327:         $byPage = $this->byPage;
0328:         if (isset($_GET['byPage']) && is_numeric($_GET['byPage']) && $_GET['byPage'] > 0) {
0329:             $byPage = $_GET['byPage'];
0330:         } else if (isset($_SESSION['byPage'])) {
0331:             $byPage = $_SESSION['byPage'];
0332:         }
0333: 
0334:         return $byPage;
0335:     }
0336: 
0337:     public function getOrder()
0338:     {
0339:         $order = $this->order;
0340:         if (isset($_GET['order'])) {
0341:             if ($_GET['order'] === 'newerFirst') {
0342:                 $order = 'newerFirst';
0343:             }
0344:             if ($_GET['order'] === 'olderFirst') {
0345:                 $order = 'olderFirst';
0346:             }
0347:         } else if (isset($_SESSION['order'])) {
0348:             $order = $_SESSION['order'];
0349:         }
0350: 
0351:         return $order;
0352:     }
0353: 
0354:     public function getCurrentHash()
0355:     {
0356:         $currentHash = $this->currentHash;
0357:         if (isset($_GET['currentHash'])) {
0358:             $currentHash = preg_replace('/[^a-zA-Z0-9-_@]/', '', substr(trim($_GET['currentHash'], '/'), 0, 6));
0359:         }
0360: 
0361:         if (empty($currentHash)) {
0362:             $currentHash = 'all';
0363:         }
0364: 
0365:         return $currentHash;
0366:     }
0367: 
0368:     public function getCurrentPage()
0369:     {
0370:         $currentPage = $this->currentPage;
0371:         if (isset($_GET['page']) && !empty($_GET['page'])) {
0372:             $currentPage = (int)$_GET['page'];
0373:         } else if (isset($_GET['previousPage']) && !empty($_GET['previousPage'])) {
0374:             $currentPage = (int)$_GET['previousPage'] - 1;
0375:             if ($currentPage < 1) {
0376:                 $currentPage = 1;
0377:             }
0378:         } else if (isset($_GET['nextPage']) && !empty($_GET['nextPage'])) {
0379:             $currentPage = (int)$_GET['nextPage'] + 1;
0380:         }
0381: 
0382:         return $currentPage;
0383:     }
0384: 
0385:     public function setDisableSessionProtection($disableSessionProtection)
0386:     {
0387:         $this->disableSessionProtection = $disableSessionProtection;
0388:     }
0389: 
0390:     public function setLogin($login)
0391:     {
0392:         $this->login = $login;
0393:     }
0394: 
0395:     public function setPublic($public)
0396:     {
0397:         $this->public = $public;
0398:     }
0399: 
0400:     public function setHash($pass)
0401:     {
0402:         $this->hash = sha1($pass.$this->login.$this->salt);
0403:     }
0404: 
0405:     public function setSalt($salt)
0406:     {
0407:         $this->salt = $salt;
0408:     }
0409: 
0410:     public function setTitle($title)
0411:     {
0412:         $this->title = $title;
0413:     }
0414: 
0415:     public function setLocale($locale)
0416:     {
0417:         $this->locale = $locale;
0418:     }
0419: 
0420:     public function setRedirector($redirector)
0421:     {
0422:         $this->redirector = $redirector;
0423:     }
0424: 
0425:     public function setAutoreadPage($autoreadPage)
0426:     {
0427:         $this->autoreadPage = $autoreadPage;
0428:     }
0429: 
0430:     public function setAutoUpdate($autoUpdate)
0431:     {
0432:         $this->autoUpdate = $autoUpdate;
0433:     }
0434: 
0435:     public function setAutoreadItem($autoreadItem)
0436:     {
0437:         $this->autoreadItem = $autoreadItem;
0438:     }
0439: 
0440:     public function setAutohide($autohide)
0441:     {
0442:         $this->autohide = $autohide;
0443:     }
0444: 
0445:     public function setAutofocus($autofocus)
0446:     {
0447:         $this->autofocus = $autofocus;
0448:     }
0449: 
0450:     public function setAddFavicon($addFavicon)
0451:     {
0452:         $this->addFavicon = $addFavicon;
0453:     }
0454: 
0455:     public function setShaarli($url)
0456:     {
0457:         $this->shaarli = $url;
0458:     }
0459: 
0460:     public function setMaxUpdate($max)
0461:     {
0462:         $this->maxUpdate = $max;
0463:     }
0464: 
0465:     public function setMaxItems($max)
0466:     {
0467:         $this->maxItems = $max;
0468:     }
0469: 
0470:     public function setOrder($order)
0471:     {
0472:         $this->order = $order;
0473:     }
0474: 
0475:     public function getMenu()
0476:     {
0477:         $menu = array();
0478: 
0479:         if ($this->menuView != 0) {
0480:             $menu['menuView'] = $this->menuView;
0481:         }
0482:         if ($this->menuListFeeds != 0) {
0483:             $menu['menuListFeeds'] = $this->menuListFeeds;
0484:         }
0485:         if ($this->menuFilter != 0) {
0486:             $menu['menuFilter'] = $this->menuFilter;
0487:         }
0488:         if ($this->menuOrder != 0) {
0489:             $menu['menuOrder'] = $this->menuOrder;
0490:         }
0491:         if ($this->menuUpdate != 0) {
0492:             $menu['menuUpdate'] = $this->menuUpdate;
0493:         }
0494:         if ($this->menuRead != 0) {
0495:             $menu['menuRead'] = $this->menuRead;
0496:         }
0497:         if ($this->menuUnread != 0) {
0498:             $menu['menuUnread'] = $this->menuUnread;
0499:         }
0500:         if ($this->menuEdit != 0) {
0501:             $menu['menuEdit'] = $this->menuEdit;
0502:         }
0503:         if ($this->menuAdd != 0) {
0504:             $menu['menuAdd'] = $this->menuAdd;
0505:         }
0506:         if ($this->menuHelp != 0) {
0507:             $menu['menuHelp'] = $this->menuHelp;
0508:         }
0509: 
0510:         asort($menu);
0511: 
0512:         return $menu;
0513:     }
0514: 
0515:     public function getPaging()
0516:     {
0517:         $paging = array();
0518: 
0519:         if ($this->pagingItem != 0) {
0520:             $paging['pagingItem'] = $this->pagingItem;
0521:         }
0522:         if ($this->pagingPage != 0) {
0523:             $paging['pagingPage'] = $this->pagingPage;
0524:         }
0525:         if ($this->pagingByPage != 0) {
0526:             $paging['pagingByPage'] = $this->pagingByPage;
0527:         }
0528:         if ($this->pagingMarkAs != 0) {
0529:             $paging['pagingMarkAs'] = $this->pagingMarkAs;
0530:         }
0531: 
0532:         asort($paging);
0533: 
0534:         return $paging;
0535:     }
0536: 
0537:     public function setMenuView($menuView)
0538:     {
0539:         $this->menuView = $menuView;
0540:     }
0541: 
0542:     public function setMenuListFeeds($menuListFeeds)
0543:     {
0544:         $this->menuListFeeds = $menuListFeeds;
0545:     }
0546: 
0547:     public function setMenuFilter($menuFilter)
0548:     {
0549:         $this->menuFilter = $menuFilter;
0550:     }
0551: 
0552:     public function setMenuOrder($menuOrder)
0553:     {
0554:         $this->menuOrder = $menuOrder;
0555:     }
0556: 
0557:     public function setMenuUpdate($menuUpdate)
0558:     {
0559:         $this->menuUpdate = $menuUpdate;
0560:     }
0561: 
0562:     public function setMenuRead($menuRead)
0563:     {
0564:         $this->menuRead = $menuRead;
0565:     }
0566: 
0567:     public function setMenuUnread($menuUnread)
0568:     {
0569:         $this->menuUnread = $menuUnread;
0570:     }
0571: 
0572:     public function setMenuEdit($menuEdit)
0573:     {
0574:         $this->menuEdit = $menuEdit;
0575:     }
0576: 
0577:     public function setMenuAdd($menuAdd)
0578:     {
0579:         $this->menuAdd = $menuAdd;
0580:     }
0581: 
0582:     public function setMenuHelp($menuHelp)
0583:     {
0584:         $this->menuHelp = $menuHelp;
0585:     }
0586: 
0587:     public function setPagingItem($pagingItem)
0588:     {
0589:         $this->pagingItem = $pagingItem;
0590:     }
0591: 
0592:     public function setPagingPage($pagingPage)
0593:     {
0594:         $this->pagingPage = $pagingPage;
0595:     }
0596: 
0597:     public function setPagingByPage($pagingByPage)
0598:     {
0599:         $this->pagingByPage = $pagingByPage;
0600:     }
0601: 
0602:     public function setPagingMarkAs($pagingMarkAs)
0603:     {
0604:         $this->pagingMarkAs = $pagingMarkAs;
0605:     }
0606: 
0607:     public function write()
0608:     {
0609:         $data = array('login', 'hash', 'salt', 'title', 'redirector', 'shaarli',
0610:                       'byPage', 'order', 'public', 'filter', 'view','locale',
0611:                       'maxItems',  'autoreadItem', 'autoreadPage', 'maxUpdate',
0612:                       'autohide', 'autofocus', 'listFeeds', 'autoUpdate', 'menuView',
0613:                       'menuListFeeds', 'menuFilter', 'menuOrder', 'menuUpdate',
0614:                       'menuRead', 'menuUnread', 'menuEdit', 'menuAdd', 'menuHelp',
0615:                       'pagingItem', 'pagingPage', 'pagingByPage', 'addFavicon',
0616:                       'pagingMarkAs', 'disableSessionProtection');
0617:         $out = '<?php';
0618:         $out .= "\n";
0619: 
0620:         foreach ($data as $key) {
0621:             $value = strtr($this->$key, array('$' => '\\$', '"' => '\\"'));
0622:             $out .= '$this->'.$key.' = "'.$value."\";\n";
0623:         }
0624: 
0625:         $out .= '?>';
0626: 
0627:         if (!@file_put_contents($this->_file, $out)) {
0628:             return false;
0629:         }
0630: 
0631:         return true;
0632:     }
0633: }
0634: 
0635: class FeedPage
0636: {
0637:     public static $var = array();
0638:     private static $_instance;
0639: 
0640:     public static function init($var)
0641:     {
0642:         FeedPage::$var = $var;
0643:     }
0644: 
0645:     public static function includesTpl()
0646:     {
0647:         extract(FeedPage::$var);
0648: ?>
0649: <title><?php echo $pagetitle;?></title>
0650: <meta charset="utf-8">
0651: 
0652: <!-- <link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon"> -->
0653: <?php if (is_file('inc/style.css')) { ?>
0654: <link type="text/css" rel="stylesheet" href="inc/style.css?version=<?php echo $version;?>" />
0655: <?php } else { ?>
0656: <style>
0657: /*!
0658:  * Bootstrap v2.3.0
0659:  *
0660:  * Copyright 2012 Twitter, Inc
0661:  * Licensed under the Apache License v2.0
0662:  * http://www.apache.org/licenses/LICENSE-2.0
0663:  *
0664:  * Designed and built with all the love in the world @twitter by @mdo and @fat.
0665:  */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.ico-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.ico-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.ico-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.ico-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.ico-glass{background-position:0 0}.ico-music{background-position:-24px 0}.ico-search{background-position:-48px 0}.ico-envelope{background-position:-72px 0}.ico-heart{background-position:-96px 0}.ico-star{background-position:-120px 0}.ico-star-empty{background-position:-144px 0}.ico-user{background-position:-168px 0}.ico-film{background-position:-192px 0}.ico-th-large{background-position:-216px 0}.ico-th{background-position:-240px 0}.ico-th-list{background-position:-264px 0}.ico-ok{background-position:-288px 0}.ico-remove{background-position:-312px 0}.ico-zoom-in{background-position:-336px 0}.ico-zoom-out{background-position:-360px 0}.ico-off{background-position:-384px 0}.ico-signal{background-position:-408px 0}.ico-cog{background-position:-432px 0}.ico-trash{background-position:-456px 0}.ico-home{background-position:0 -24px}.ico-file{background-position:-24px -24px}.ico-time{background-position:-48px -24px}.ico-road{background-position:-72px -24px}.ico-download-alt{background-position:-96px -24px}.ico-download{background-position:-120px -24px}.ico-upload{background-position:-144px -24px}.ico-inbox{background-position:-168px -24px}.ico-play-circle{background-position:-192px -24px}.ico-repeat{background-position:-216px -24px}.ico-refresh{background-position:-240px -24px}.ico-list-alt{background-position:-264px -24px}.ico-lock{background-position:-287px -24px}.ico-flag{background-position:-312px -24px}.ico-headphones{background-position:-336px -24px}.ico-volume-off{background-position:-360px -24px}.ico-volume-down{background-position:-384px -24px}.ico-volume-up{background-position:-408px -24px}.ico-qrcode{background-position:-432px -24px}.ico-barcode{background-position:-456px -24px}.ico-tag{background-position:0 -48px}.ico-tags{background-position:-25px -48px}.ico-book{background-position:-48px -48px}.ico-bookmark{background-position:-72px -48px}.ico-print{background-position:-96px -48px}.ico-camera{background-position:-120px -48px}.ico-font{background-position:-144px -48px}.ico-bold{background-position:-167px -48px}.ico-italic{background-position:-192px -48px}.ico-text-height{background-position:-216px -48px}.ico-text-width{background-position:-240px -48px}.ico-align-left{background-position:-264px -48px}.ico-align-center{background-position:-288px -48px}.ico-align-right{background-position:-312px -48px}.ico-align-justify{background-position:-336px -48px}.ico-list{background-position:-360px -48px}.ico-indent-left{background-position:-384px -48px}.ico-indent-right{background-position:-408px -48px}.ico-facetime-video{background-position:-432px -48px}.ico-picture{background-position:-456px -48px}.ico-pencil{background-position:0 -72px}.ico-map-marker{background-position:-24px -72px}.ico-adjust{background-position:-48px -72px}.ico-tint{background-position:-72px -72px}.ico-edit{background-position:-96px -72px}.ico-share{background-position:-120px -72px}.ico-check{background-position:-144px -72px}.ico-move{background-position:-168px -72px}.ico-step-backward{background-position:-192px -72px}.ico-fast-backward{background-position:-216px -72px}.ico-backward{background-position:-240px -72px}.ico-play{background-position:-264px -72px}.ico-pause{background-position:-288px -72px}.ico-stop{background-position:-312px -72px}.ico-forward{background-position:-336px -72px}.ico-fast-forward{background-position:-360px -72px}.ico-step-forward{background-position:-384px -72px}.ico-eject{background-position:-408px -72px}.ico-chevron-left{background-position:-432px -72px}.ico-chevron-right{background-position:-456px -72px}.ico-plus-sign{background-position:0 -96px}.ico-minus-sign{background-position:-24px -96px}.ico-remove-sign{background-position:-48px -96px}.ico-ok-sign{background-position:-72px -96px}.ico-question-sign{background-position:-96px -96px}.ico-info-sign{background-position:-120px -96px}.ico-screenshot{background-position:-144px -96px}.ico-remove-circle{background-position:-168px -96px}.ico-ok-circle{background-position:-192px -96px}.ico-ban-circle{background-position:-216px -96px}.ico-arrow-left{background-position:-240px -96px}.ico-arrow-right{background-position:-264px -96px}.ico-arrow-up{background-position:-289px -96px}.ico-arrow-down{background-position:-312px -96px}.ico-share-alt{background-position:-336px -96px}.ico-resize-full{background-position:-360px -96px}.ico-resize-small{background-position:-384px -96px}.ico-plus{background-position:-408px -96px}.ico-minus{background-position:-433px -96px}.ico-asterisk{background-position:-456px -96px}.ico-exclamation-sign{background-position:0 -120px}.ico-gift{background-position:-24px -120px}.ico-leaf{background-position:-48px -120px}.ico-fire{background-position:-72px -120px}.ico-eye-open{background-position:-96px -120px}.ico-eye-close{background-position:-120px -120px}.ico-warning-sign{background-position:-144px -120px}.ico-plane{background-position:-168px -120px}.ico-calendar{background-position:-192px -120px}.ico-random{width:16px;background-position:-216px -120px}.ico-comment{background-position:-240px -120px}.ico-magnet{background-position:-264px -120px}.ico-chevron-up{background-position:-288px -120px}.ico-chevron-down{background-position:-313px -119px}.ico-retweet{background-position:-336px -120px}.ico-shopping-cart{background-position:-360px -120px}.ico-folder-close{width:16px;background-position:-384px -120px}.ico-folder-open{width:16px;background-position:-408px -120px}.ico-resize-vertical{background-position:-432px -119px}.ico-resize-horizontal{background-position:-456px -118px}.ico-hdd{background-position:0 -144px}.ico-bullhorn{background-position:-24px -144px}.ico-bell{background-position:-48px -144px}.ico-certificate{background-position:-72px -144px}.ico-thumbs-up{background-position:-96px -144px}.ico-thumbs-down{background-position:-120px -144px}.ico-hand-right{background-position:-144px -144px}.ico-hand-left{background-position:-168px -144px}.ico-hand-up{background-position:-192px -144px}.ico-hand-down{background-position:-216px -144px}.ico-circle-arrow-right{background-position:-240px -144px}.ico-circle-arrow-left{background-position:-264px -144px}.ico-circle-arrow-up{background-position:-288px -144px}.ico-circle-arrow-down{background-position:-312px -144px}.ico-globe{background-position:-336px -144px}.ico-wrench{background-position:-360px -144px}.ico-tasks{background-position:-384px -144px}.ico-filter{background-position:-408px -144px}.ico-briefcase{background-position:-432px -144px}.ico-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-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}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .ico-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .ico-bar+.ico-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-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}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
0666: /*!
0667:  * Bootstrap Responsive v2.3.0
0668:  *
0669:  * Copyright 2012 Twitter, Inc
0670:  * Licensed under the Apache License v2.0
0671:  * http://www.apache.org/licenses/LICENSE-2.0
0672:  *
0673:  * Designed and built with all the love in the world @twitter by @mdo and @fat.
0674:  */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
0675: 
0676: 
0677: /* feed icon inspired from peculiar by Lucian Marin - lucianmarin.com */
0678: /* https://github.com/lucianmarin/peculiar */
0679: .ico {
0680:   position: relative;
0681:   width: 16px;
0682:   height: 16px;
0683:   display: inline-block;
0684: }
0685: .ico-feed-dot {
0686:   background-color: #000;
0687:   width: 4px;
0688:   height: 4px;
0689:   border-radius: 3px;
0690:   position: absolute;
0691:   bottom: 2px;
0692:   left: 2px;
0693: }
0694: .ico-feed-circle-1 {
0695:   border: #000 2px solid;
0696:   border-bottom-color: transparent;
0697:   border-left-color: transparent;
0698:   width: 6px;
0699:   height: 6px;
0700:   border-radius: 6px;
0701:   position: absolute;
0702:   bottom: 0;
0703:   left: 0;
0704: }
0705: .ico-feed-circle-2 {
0706:   border: #000 2px solid;
0707:   border-bottom-color: transparent;
0708:   border-left-color: transparent;
0709:   width: 9px;
0710:   height: 9px;
0711:   border-radius: 4px 7px;
0712:   position: absolute;
0713:   bottom: 0;
0714:   left: 0;
0715: }
0716: .ico-circle {
0717:   background-color: #000;
0718:   border-radius:8px;
0719:   width: 16px;
0720:   height: 16px;
0721:   position: absolute;
0722:   top:0;
0723:   left:0;
0724: }
0725: .ico-line-h {
0726:   background-color: #fff;
0727:   width: 8px;
0728:   height: 2px;
0729:   border-radius: 1px;
0730:   position: absolute;
0731:   top:7px;
0732:   left: 4px;
0733: }
0734: .ico-line-v {
0735:   background-color: #fff;
0736:   width: 2px;
0737:   height: 8px;
0738:   border-radius: 1px;
0739:   position: absolute;
0740:   top:4px;
0741:   left: 7px;
0742: }
0743: .ico-triangle-up {
0744:     border-color: transparent transparent #000000;
0745:     border-image: none;
0746:     border-style: solid;
0747:     border-width: 8px;
0748:     bottom: 7px;
0749:     height: 0;
0750:     left: 0;
0751:     position: absolute;
0752:     width: 0;
0753: }
0754: .ico-square {
0755:     background-color: #000000;
0756:     border-bottom-left-radius: 1px;
0757:     border-bottom-right-radius: 1px;
0758:     bottom: 1px;
0759:     height: 10px;
0760:     left: 3px;
0761:     position: absolute;
0762:     width: 10px;
0763: }
0764: .ico-home-line {
0765:     background-color: #000000;
0766:     border-radius: 1px 1px 1px 1px;
0767:     height: 5px;
0768:     left: 3px;
0769:     position: absolute;
0770:     top: 2px;
0771:     width: 2px;
0772: }
0773: 
0774: html, body, .full-height {
0775:   height: 100%;
0776:   overflow: auto;
0777: }
0778: 
0779: li.feed {
0780:   border-bottom: 1px dotted #999;
0781:   font-weight: normal;
0782: }
0783: 
0784: li.feed.has-unread {
0785:   font-weight: bold;
0786: }
0787: 
0788: li.folder {
0789:   font-weight: bold;
0790: }
0791: 
0792: li.item-list {
0793:   border-bottom: 1px dotted #999;
0794: }
0795: 
0796: h5.folder {
0797:   background-color: #ddd;
0798:   border-radius: 4px;
0799:   padding: 2px;
0800:   margin: 2px 0;
0801: }
0802: 
0803: .mark-as {
0804:   float: right;
0805: }
0806: 
0807: .content {
0808:   clear: both;
0809: }
0810: 
0811: .current {
0812:   border-color: red !important;
0813: }
0814: 
0815: .current .item-title {
0816:   font-weight: bold;
0817: }
0818: 
0819: dl {
0820:   margin-bottom: 0px !important;
0821: }
0822: 
0823: .item-info {
0824:   overflow: hidden;
0825:   text-overflow: ellipsis;
0826:   white-space: nowrap;
0827: }
0828: 
0829: .read {
0830:   opacity: 0.4;
0831: }
0832: 
0833: .autohide-feed,.autohide-folder {
0834:   display: none;
0835: }
0836: 
0837: #main-container {
0838:   float: right;
0839: }
0840: 
0841: #minor-container {
0842:   margin-left: 0;
0843: }
0844: 
0845: .clear {
0846:   clear: both;
0847: }
0848: 
0849: #menu-toggle {
0850:   color: #000 !important;
0851: }
0852: 
0853: #status {
0854:   font-size: 85%;
0855: }
0856: 
0857: .item-toggle-plus {
0858:   float: right;
0859: }
0860: 
0861: .item-title {
0862:   margin-bottom: 10px;
0863: }
0864: 
0865: .item-info-end {
0866:   float: right;
0867: }
0868: 
0869: .item-description {
0870:   text-decoration: none;
0871: }
0872: 
0873: .folder-toggle:focus, .folder-toggle:hover, .folder-toggle:active, .item-toggle:focus, .item-toggle:hover, .item-toggle:active {
0874:   text-decoration: none;
0875: }
0876: 
0877: .folder-toggle-open, .item-toggle-open, .item-close {
0878:   display: none;
0879: }
0880: 
0881: .folder-toggle-close, .item-toggle-close, .item-open {
0882:   display: block;
0883: }
0884: 
0885: .label-expanded {
0886:   padding: 6px;
0887: }
0888: 
0889: /* Large desktop */
0890: @media (min-width: 1200px) {
0891: 
0892: }
0893: 
0894: /* Portrait tablet to landscape and desktop */
0895: @media (min-width: 768px) and (max-width: 979px) {
0896: 
0897: }
0898: 
0899: /* Landscape phone to portrait tablet */
0900: @media (max-width: 767px) {
0901:     html, body, .full-height {
0902:         height: auto;
0903:     }
0904: }
0905: 
0906: /* Landscape phones and down */
0907: @media (max-width: 480px) {
0908:   ul.inline {
0909:     width: 100%;
0910:   }
0911: 
0912:   ul.inline > li {
0913:     width: 90%;
0914:     padding-bottom: 10px;
0915:     margin: auto;
0916:   }
0917: 
0918:   .btn-group {
0919:     width: 100%;
0920:   }
0921: 
0922:   .btn-group > a {
0923:     width: 100%;
0924:     margin-left: -1px;
0925:     padding-left: 0;
0926:     padding-right: 0;
0927:   }
0928: 
0929:   .btn-group > .btn {
0930:     width: 100%;
0931:     float: left;
0932:     border-radius: 4px;
0933:   }
0934: 
0935:   .item-title {
0936:     no-wrap: normal;
0937:   }
0938: 
0939:   .paging-by-page {
0940:     width: 100%;
0941:   }
0942: 
0943:   .paging-by-page > a {
0944:     width: 100%;
0945:     margin-left: -1px;
0946:     padding-left: 0;
0947:     padding-right: 0;
0948:     border-radius: 4px;
0949:   }
0950: 
0951:   .paging-by-page > input {
0952:     width: 100%;
0953:     float: left;
0954:     margin-left: -1px;
0955:     padding-left: 0;
0956:     padding-right: 0;
0957:     border-radius: 4px;
0958:   }
0959: 
0960:   .paging-by-page > .btn {
0961:     width: 100%;
0962:     float: left;
0963:     border-radius: 4px !important;
0964:   }
0965: }
0966: </style>
0967: <?php } ?>
0968: <?php if (is_file('inc/user.css')) { ?>
0969: <link type="text/css" rel="stylesheet" href="inc/user.css?version=<?php echo $version;?>" />
0970: <?php } ?>
0971: <meta name="viewport" content="width=device-width">
0972: <?php
0973:     }
0974: 
0975:     public static function installTpl()
0976:     {
0977:         extract(FeedPage::$var);
0978: ?>
0979: <!DOCTYPE html>
0980: <html>
0981:   <head>
0982:     <?php FeedPage::includesTpl(); ?>
0983:   </head>
0984:   <body>
0985:     <div class="container-fluid">
0986:       <div class="row-fluid">
0987:         <div class="span4 offset4">
0988:           <div id="install">
0989:             <form class="form-horizontal" method="post" action="" name="installform">
0990:               <fieldset>
0991:                 <legend>KrISS feed installation</legend>
0992:                 <div class="control-group">
0993:                   <label class="control-label" for="setlogin">Login</label>
0994:                   <div class="controls">
0995:                     <input type="text" id="setlogin" name="setlogin" placeholder="Login">
0996:                   </div>
0997:                 </div>
0998:                 <div class="control-group">
0999:                   <label class="control-label" for="setlogin">Password</label>
1000:                   <div class="controls">
1001:                     <input type="password" id="setpassword" name="setpassword" placeholder="Password">
1002:                   </div>
1003:                 </div>
1004:                 <div class="control-group">
1005:                   <div class="controls">
1006:                     <button type="submit" class="btn">Submit</button>
1007:                   </div>
1008:                 </div>
1009:                 <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
1010:               </fieldset>
1011:             </form>
1012:             <?php FeedPage::statusTpl(); ?>
1013:           </div>
1014:         </div>
1015:         <script>
1016:           document.installform.setlogin.focus();
1017:         </script>
1018:       </div>
1019:     </div>
1020:   </body>
1021: </html>
1022: 
1023: <?php
1024:     }
1025: 
1026:     public static function loginTpl()
1027:     {
1028:         extract(FeedPage::$var);
1029: ?>
1030: <!DOCTYPE html>
1031: <html>
1032:   <head>
1033:     <?php FeedPage::includesTpl(); ?>
1034:   </head>
1035:   <body onload="document.loginform.login.focus();">
1036:     <div class="container-fluid">
1037:       <div class="row-fluid">
1038:         <div class="span4 offset4">
1039:           <div id="login">
1040:             <form class="form-horizontal" method="post" action="?login" name="loginform">
1041:               <fieldset>
1042:                 <legend>Welcome to KrISS feed</legend>
1043:                 <div class="control-group">
1044:                   <label class="control-label" for="login">Login</label>
1045:                   <div class="controls">
1046:                     <input type="text" id="login" name="login" placeholder="Login" tabindex="1">
1047:                   </div>
1048:                 </div>
1049:                 <div class="control-group">
1050:                   <label class="control-label" for="password">Password</label>
1051:                   <div class="controls">
1052:                     <input type="password" id="password" name="password" placeholder="Password" tabindex="2">
1053:                   </div>
1054:                 </div>
1055:                 <div class="control-group">
1056:                   <div class="controls">
1057:                     <label><input type="checkbox" name="longlastingsession" tabindex="3">&nbsp;Stay signed in (Do not check on public computers)</label>
1058:                   </div>
1059:                 </div>
1060:                
1061:                 <div class="control-group">
1062:                   <div class="controls">
1063:                     <button type="submit" class="btn" tabindex="4">Sign in</button>
1064:                   </div>
1065:                 </div>
1066:               </fieldset>
1067: 
1068:               <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>">
1069:               <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
1070:             </form>
1071:             <?php FeedPage::statusTpl(); ?>
1072:           </div>
1073:         </div>
1074:       </div>
1075:     </div>                                          
1076:   </body>
1077: </html>
1078: <?php
1079:     }
1080: 
1081:     public static function navTpl()
1082:     {
1083:         extract(FeedPage::$var);
1084: ?>
1085: <div id="menu" class="navbar">
1086:   <div class="navbar-inner">
1087:     <div class="container">
1088:      
1089:       <!-- .btn-navbar is used as the toggle for collapsed navbar content -->
1090:       <a id="menu-toggle" class="btn btn-navbar" data-toggle="collapse" data-target="#menu-collapse">
1091:         menu
1092:       </a>
1093:       <a id="nav-home" class="brand" href="<?php echo MyTool::getUrl(); ?>" title="Home">
1094:         <span class="ico ico-navbar">
1095:           <span class="ico-square"></span>
1096:           <span class="ico-triangle-up"></span>
1097:           <span class="ico-home-line"></span>
1098:         </span>
1099:         &nbsp;
1100:         &nbsp;
1101:       </a>
1102: 
1103:       <?php if (isset($currentHashView)) { ?>
1104:       <span class="brand">
1105:         <?php echo $currentHashView ?>
1106:       </span>
1107:       <?php } ?>
1108:       <div id="menu-collapse" class="nav-collapse collapse">
1109:         <ul class="nav">
1110:           <?php
1111:              switch($template) {
1112:              case 'index':
1113:              ?>
1114:           <?php foreach(array_keys($menu) as $menuOpt) { ?>
1115:           <?php switch($menuOpt) {
1116:                 case 'menuView': ?>
1117:           <?php if ($view === 'expanded') { ?>
1118:           <li><a href="<?php echo $query.'view=list'; ?>" title="Switch to list view (one line per item)">View as list</a></li>
1119:           <?php } else { ?>
1120:           <li><a href="<?php echo $query.'view=expanded'; ?>" title="Switch to expanded view">View as expanded</a></li>
1121:           <?php } ?>
1122:           <?php break; ?>
1123:           <?php case 'menuListFeeds': ?>
1124:           <?php if ($listFeeds == 'show') { ?>
1125:           <li><a href="<?php echo $query.'listFeeds=hide'; ?>" title="Hide the feeds list">Hide feeds list</a></li>
1126:           <?php } else { ?>
1127:           <li><a href="<?php echo $query.'listFeeds=show'; ?>" title="Show the feeds list">Show feeds list</a></li>
1128:           <?php } ?>
1129:           <?php break; ?>
1130:           <?php case 'menuFilter': ?>
1131:           <?php if ($filter === 'unread') { ?>
1132:           <li><a href="<?php echo $query.'filter=all'; ?>" title="Filter: show all (read and unread) items">Show all items</a></li>
1133:           <?php } else { ?>
1134:           <li><a href="<?php echo $query.'filter=unread'; ?>" title="Filter: show unread items">Show unread items</a></li>
1135:           <?php } ?>
1136:           <?php break; ?>
1137:           <?php case 'menuOrder': ?>
1138:           <?php if ($order === 'newerFirst') { ?>
1139:           <li><a href="<?php echo $query.'order=olderFirst'; ?>" title="Show older first items">Show older first</a></li>
1140:           <?php } else { ?>
1141:           <li><a href="<?php echo $query.'order=newerFirst'; ?>" title="Show newer first items">Show newer first</a></li>
1142:           <?php } ?>
1143:           <?php break; ?>
1144:           <?php case 'menuUpdate': ?>
1145:           <li>
1146:             <a href="<?php echo $query.'update='.$currentHash; ?>" class="admin" title="Update <?php echo $currentHashType; ?> manually">Update <?php echo $currentHashType; ?></a>
1147:           </li>
1148:           <?php break; ?>
1149:           <?php case 'menuRead': ?>
1150:           <li>
1151:             <a href="<?php echo $query.'read='.$currentHash; ?>" class="admin" title="Mark <?php echo $currentHashType; ?> as read">Mark <?php echo $currentHashType; ?> as read</a>
1152:           </li>
1153:           <?php break; ?>
1154:           <?php case 'menuUnread': ?>
1155:           <li>
1156:             <a href="<?php echo $query.'unread='.$currentHash; ?>" class="admin" title="Mark <?php echo $currentHashType; ?> as unread">Mark <?php echo $currentHashType; ?> as unread</a>
1157:           </li>
1158:           <?php break; ?>
1159:           <?php case 'menuEdit': ?>
1160:           <li>
1161:             <a href="<?php echo $query.'edit='.$currentHash; ?>" class="admin" title="Edit <?php echo $currentHashType; ?>">Edit <?php echo $currentHashType; ?></a>
1162:           </li>
1163:           <?php break; ?>
1164:           <?php case 'menuAdd': ?>
1165:           <li>
1166:             <a href="<?php echo $query.'add'; ?>" class="admin" title="Add a new feed">Add a new feed</a>
1167:           </li>
1168:           <?php break; ?>
1169:           <?php case 'menuHelp': ?>
1170:           <li>
1171:             <a href="<?php echo $query.'help'; ?>" title="Help : how to use KrISS feed">Help</a>
1172:           </li>
1173:           <?php break; ?>
1174:           <?php default: ?>
1175:           <?php break; ?>
1176:           <?php } ?>
1177:           <?php } ?>
1178:           <?php if (Session::isLogged()) { ?>
1179:           <li><a href="?config" class="admin" title="Configuration">Configuration</a></li>
1180:           <li><a href="?logout" class="admin" title="Logout">Logout</a></li>
1181:           <?php } else { ?>
1182:           <li><a href="?login">Login</a></li>
1183:           <?php } ?>
1184:           <?php
1185:              break;
1186:              case 'config':
1187:              ?>
1188:           <li><a href="?import" class="admin" title="Import OPML file">Import</a></li>
1189:           <li><a href="?export" class="admin" title="Export OPML file">Export</a></li>
1190:           <li><a href="?logout" class="admin" title="Logout">Logout</a></li>
1191:           <?php
1192:              break;
1193:              default:
1194:              ?>
1195:           <?php if (Session::isLogged()) { ?>
1196:           <li><a href="?config" class="admin text-error" title="Configuration">Configuration</a></li>
1197:           <li><a href="?logout" class="admin" title="Logout">Logout</a></li>
1198:           <?php } else { ?>
1199:           <li><a href="?login">Login</a></li>
1200:           <?php } ?>
1201:           <?php
1202:              break;
1203:              }
1204:              ?>
1205:         </ul>
1206:       </div>
1207:     </div>
1208:   </div>
1209: </div>
1210: <?php
1211:     }
1212: 
1213:     public static function statusTpl()
1214:     {
1215:         extract(FeedPage::$var);
1216: ?>
1217: <div id="status" class="text-center">
1218:   <a href="http://github.com/tontof/kriss_feed">KrISS feed <?php echo $version; ?></a>
1219:   <span class="hidden-phone"> - A simple and smart (or stupid) feed reader</span>. By <a href="http://tontof.net">Tontof</a>
1220: </div>
1221: <?php
1222:     }
1223: 
1224:     public static function configTpl()
1225:     {
1226:         extract(FeedPage::$var);
1227: ?>
1228: <!DOCTYPE html>
1229: <html>
1230:   <head><?php FeedPage::includesTpl(); ?></head>
1231:   <body>
1232:     <div class="container-fluid">
1233:       <div class="row-fluid">
1234:         <div class="span6 offset3">
1235:           <div id="config">
1236:             <?php FeedPage::navTpl(); ?>
1237:             <div id="section">
1238:               <form class="form-horizontal" method="post" action="">
1239:                 <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
1240:                 <input type="hidden" name="returnurl" value="<?php echo $referer; ?>" />
1241:                 <fieldset>
1242:                   <legend>KrISS feed Reader information</legend>
1243: 
1244:                   <div class="control-group">
1245:                     <label class="control-label" for="title">Feed reader title</label>
1246:                     <div class="controls">
1247:                       <input type="text" id="title" name="title" value="<?php echo $kfctitle; ?>">
1248:                     </div>
1249:                   </div>
1250: 
1251:                   <div class="control-group">
1252:                     <label class="control-label">Public/private reader</label>
1253:                     <div class="controls">
1254:                       <label for="publicReader">
1255:                         <input type="radio" id="publicReader" name="public" value="1" <?php echo ($kfcpublic? 'checked="checked"' : ''); ?>/>
1256:                         Public kriss feed
1257:                       </label>
1258:                       <label for="privateReader">
1259:                         <input type="radio" id="privateReader" name="public" value="0" <?php echo (!$kfcpublic? 'checked="checked"' : ''); ?>/>
1260:                         Private kriss feed
1261:                       </label>
1262:                     </div>
1263:                   </div>
1264: 
1265:                   <div class="control-group">
1266:                     <label class="control-label" for="shaarli">Shaarli url</label>
1267:                     <div class="controls">
1268:                       <input type="text" id="shaarli" name="shaarli" value="<?php echo $kfcshaarli; ?>">
1269:                       <span class="help-block">options :<br>
1270:                         - ${url}: link of item<br>
1271:                         - ${title}: title of item<br>
1272:                         - ${via}: if domain of &lt;link&gt; and &lt;guid&gt; are different ${via} is equals to: <code>via &lt;guid&gt;</code><br>
1273:                         - ${sel}: <strong>Only available</strong> with javascript: <code>�� selected text ��</code><br>
1274:                         - example with shaarli : <code>http://your-shaarli/?post=${url}&title=${title}&description=${sel}%0A%0A${via}&source=bookmarklet</code>
1275:                       </span>
1276:                     </div>
1277:                   </div>
1278: 
1279:                   <div class="control-group">
1280:                     <label class="control-label" for="redirector">Feed reader redirector (only for links, media are not considered, <strong>item content is anonymize only with javascript</strong>)</label>
1281:                     <div class="controls">
1282:                       <input type="text" id="redirector" name="redirector" value="<?php echo $kfcredirector; ?>">
1283:                       <span class="help-block"><strong>http://anonym.to/?</strong> will mask the HTTP_REFERER, you can also use <strong>noreferrer</strong> to use HTML5 property</span>
1284:                     </div>
1285:                   </div>
1286: 
1287:                   <div class="control-group">
1288:                     <label class="control-label" for="disablesessionprotection">Session protection</label>
1289:                     <div class="controls">
1290:                       <label><input type="checkbox" id="disablesessionprotection" name="disableSessionProtection"<?php echo ($kfcdisablesessionprotection ? ' checked="checked"' : ''); ?>>Disable session cookie hijacking protection</label>
1291:                       <span class="help-block">Check this if you get disconnected often or if your IP address changes often.</span>
1292:                     </div>
1293:                   </div>
1294: 
1295:                   <div class="control-group">
1296:                     <div class="controls">
1297:                       <input class="btn" type="submit" name="cancel" value="Cancel"/>
1298:                       <input class="btn" type="submit" name="save" value="Save" />
1299:                     </div>
1300:                   </div>
1301:                 </fieldset>
1302:                 <fieldset>
1303:                   <legend>KrISS feed reader preferences</legend>
1304: 
1305:                   <div class="control-group">
1306:                     <label class="control-label" for="maxItems">Maximum number of items by feed</label>
1307:                     <div class="controls">
1308:                       <input type="text" maxlength="3" id="maxItems" name="maxItems" value="<?php echo $kfcmaxitems; ?>">
1309:                       <span class="help-block">Need update to be taken into consideration</span>
1310:                     </div>
1311:                   </div>
1312: 
1313:                   <div class="control-group">
1314:                     <label class="control-label" for="maxUpdate">Maximum delay between feed update (in minutes)</label>
1315:                     <div class="controls">
1316:                       <input type="text" maxlength="3" id="maxUpdate" name="maxUpdate" value="<?php echo $kfcmaxupdate; ?>">
1317:                     </div>
1318:                   </div>
1319: 
1320:                   <div class="control-group">
1321:                     <label class="control-label">Auto read next item option</label>
1322:                     <div class="controls">
1323:                       <label for="donotautoreaditem">
1324:                         <input type="radio" id="donotautoreaditem" name="autoreadItem" value="0" <?php echo (!$kfcautoreaditem ? 'checked="checked"' : ''); ?>/>
1325:                         Do not mark as read when next item
1326:                       </label>
1327:                       <label for="autoread">
1328:                         <input type="radio" id="autoread" name="autoreadItem" value="1" <?php echo ($kfcautoreaditem ? 'checked="checked"' : ''); ?>/>
1329:                         Auto mark current as read when next item
1330:                       </label>
1331:                     </div>
1332:                   </div>
1333: 
1334:                   <div class="control-group">
1335:                     <label class="control-label">Auto read next page option</label>
1336:                     <div class="controls">
1337:                       <label for="donotautoreadpage">
1338:                         <input type="radio" id="donotautoreadpage" name="autoreadPage" value="0" <?php echo (!$kfcautoreadpage ? 'checked="checked"' : ''); ?>/>
1339:                         Do not mark as read when next page
1340:                       </label>
1341:                       <label for="autoreadpage">
1342:                         <input type="radio" id="autoreadpage" name="autoreadPage" value="1" <?php echo ($kfcautoreadpage ? 'checked="checked"' : ''); ?>/>
1343:                         Auto mark current as read when next page
1344:                       </label>
1345:                       <span class="help-block"><strong>Not implemented yet</strong></span>
1346:                     </div>
1347:                   </div>
1348: 
1349:                   <div class="control-group">
1350:                     <label class="control-label">Auto hide option</label>
1351:                     <div class="controls">
1352:                       <label for="donotautohide">
1353:                         <input type="radio" id="donotautohide" name="autohide" value="0" <?php echo (!$kfcautohide ? 'checked="checked"' : ''); ?>/>
1354:                         Always show feed in feeds list
1355:                       </label>
1356:                       <label for="autohide">
1357:                         <input type="radio" id="autohide" name="autohide" value="1" <?php echo ($kfcautohide ? 'checked="checked"' : ''); ?>/>
1358:                         Automatically hide feed when 0 unread item
1359:                       </label>
1360:                     </div>
1361:                   </div>
1362: 
1363:                   <div class="control-group">
1364:                     <label class="control-label">Auto focus option</label>
1365:                     <div class="controls">
1366:                       <label for="donotautofocus">
1367:                         <input type="radio" id="donotautofocus" name="autofocus" value="0" <?php echo (!$kfcautofocus ? 'checked="checked"' : ''); ?>/>
1368:                         Do not automatically jump to current item when it changes
1369:                       </label>
1370:                       <label for="autofocus">
1371:                         <input type="radio" id="autofocus" name="autofocus" value="1" <?php echo ($kfcautofocus ? 'checked="checked"' : ''); ?>/>
1372:                         Automatically jump to the current item position
1373:                       </label>
1374:                     </div>
1375:                   </div>
1376: 
1377:                   <div class="control-group">
1378:                     <label class="control-label">Add favicon option</label>
1379:                     <div class="controls">
1380:                       <label for="donotaddfavicon">
1381:                         <input type="radio" id="donotaddfavicon" name="addFavicon" value="0" <?php echo (!$kfcaddfavicon ? 'checked="checked"' : ''); ?>/>
1382:                         Do not add favicon next to feed on list of feeds
1383:                       </label>
1384:                       <label for="addfavicon">
1385:                         <input type="radio" id="addfavicon" name="addFavicon" value="1" <?php echo ($kfcaddfavicon ? 'checked="checked"' : ''); ?>/>
1386:                         Add favicon next to feed on list of feeds<br><strong>Warning: It depends on http://getfavicon.appspot.com/ <?php if (in_array('curl', get_loaded_extensions())) { echo 'but it will cache favicon on your server'; } ?></strong>
1387:                       </label>
1388:                     </div>
1389:                   </div>
1390: 
1391:                   <div class="control-group">
1392:                     <label class="control-label">Auto update with javascript</label>
1393:                     <div class="controls">
1394:                       <label for="donotautoupdate">
1395:                         <input type="radio" id="donotautoupdate" name="autoUpdate" value="0" <?php echo (!$kfcautoupdate ? 'checked="checked"' : ''); ?>/>
1396:                         Do not auto update with javascript
1397:                       </label>
1398:                       <label for="autoupdate">
1399:                         <input type="radio" id="autoupdate" name="autoUpdate" value="1" <?php echo ($kfcautoupdate ? 'checked="checked"' : ''); ?>/>
1400:                         Auto update with javascript
1401:                       </label>
1402:                     </div>
1403:                   </div>
1404: 
1405:                   <div class="control-group">
1406:                     <div class="controls">
1407:                       <input class="btn" type="submit" name="cancel" value="Cancel"/>
1408:                       <input class="btn" type="submit" name="save" value="Save" />
1409:                     </div>
1410:                   </div>
1411:                 </fieldset>
1412:                 <fieldset>
1413:                   <legend>KrISS feed menu preferences</legend>
1414:                   You can order or remove elements in the menu. Set a position or leave empty if you don't want the element to appear in the menu.
1415:                   <div class="control-group">
1416:                     <label class="control-label" for="menuView">View</label>
1417:                     <div class="controls">
1418:                       <input type="text" id="menuView" name="menuView" value="<?php echo empty($kfcmenu['menuView'])?'0':$kfcmenu['menuView']; ?>">
1419:                       <span class="help-block">If you want to switch between list and expanded view</span>
1420:                     </div>
1421:                   </div>
1422:                   <div class="control-group">
1423:                     <label class="control-label" for="menuListFeeds">List of feeds</label>
1424:                     <div class="controls">
1425:                       <input type="text" id="menuListFeeds" name="menuListFeeds" value="<?php echo empty($kfcmenu['menuListFeeds'])?'0':$kfcmenu['menuListFeeds']; ?>">
1426:                       <span class="help-block">If you want to show or hide list of feeds</span>
1427:                     </div>
1428:                   </div>
1429:                   <div class="control-group">
1430:                     <label class="control-label" for="menuFilter">Filter</label>
1431:                     <div class="controls">
1432:                       <input type="text" id="menuFilter" name="menuFilter" value="<?php echo empty($kfcmenu['menuFilter'])?'0':$kfcmenu['menuFilter']; ?>">
1433:                       <span class="help-block">If you want to filter all or unread items</span>
1434:                     </div>
1435:                   </div>
1436:                   <div class="control-group">
1437:                     <label class="control-label" for="menuOrder">Order</label>
1438:                     <div class="controls">
1439:                       <input type="text" id="menuOrder" name="menuOrder" value="<?php echo empty($kfcmenu['menuOrder'])?'0':$kfcmenu['menuOrder']; ?>">
1440:                       <span class="help-block">If you want to order by newer or older items</span>
1441:                     </div>
1442:                   </div>
1443:                   <div class="control-group">
1444:                     <label class="control-label" for="menuUpdate">Update</label>
1445:                     <div class="controls">
1446:                       <input type="text" id="menuUpdate" name="menuUpdate" value="<?php echo empty($kfcmenu['menuUpdate'])?'0':$kfcmenu['menuUpdate']; ?>">
1447:                       <span class="help-block">If you want to update all, folder or a feed</span>
1448:                     </div>
1449:                   </div>
1450:                   <div class="control-group">
1451:                     <label class="control-label" for="menuRead">Read</label>
1452:                     <div class="controls">
1453:                       <input type="text" id="menuRead" name="menuRead" value="<?php echo empty($kfcmenu['menuRead'])?'0':$kfcmenu['menuRead']; ?>">
1454:                       <span class="help-block">If you want to mark all, folder or a feed as read</span>
1455:                     </div>
1456:                   </div>
1457:                   <div class="control-group">
1458:                     <label class="control-label" for="menuUnread">Unread</label>
1459:                     <div class="controls">
1460:                       <input type="text" id="menuUnread" name="menuUnread" value="<?php echo empty($kfcmenu['menuUnread'])?'0':$kfcmenu['menuUnread']; ?>">
1461:                       <span class="help-block">If you want to mark all, folder or a feed as unread</span>
1462:                     </div>
1463:                   </div>
1464:                   <div class="control-group">
1465:                     <label class="control-label" for="menuEdit">Edit</label>
1466:                     <div class="controls">
1467:                       <input type="text" id="menuEdit" name="menuEdit" value="<?php echo empty($kfcmenu['menuEdit'])?'0':$kfcmenu['menuEdit']; ?>">
1468:                       <span class="help-block">If you want to edit all, folder or a feed</span>
1469:                     </div>
1470:                   </div>
1471:                   <div class="control-group">
1472:                     <label class="control-label" for="menuAdd">Add</label>
1473:                     <div class="controls">
1474:                       <input type="text" id="menuAdd" name="menuAdd" value="<?php echo empty($kfcmenu['menuAdd'])?'0':$kfcmenu['menuAdd']; ?>">
1475:                       <span class="help-block">If you want to add a feed</span>
1476:                     </div>
1477:                   </div>
1478:                   <div class="control-group">
1479:                     <label class="control-label" for="menuHelp">Help</label>
1480:                     <div class="controls">
1481:                       <input type="text" id="menuHelp" name="menuHelp" value="<?php echo empty($kfcmenu['menuHelp'])?'0':$kfcmenu['menuHelp']; ?>">
1482:                       <span class="help-block">If you want to add a link to the help</span>
1483:                     </div>
1484:                   </div>
1485:                   <div class="control-group">
1486:                     <div class="controls">
1487:                       <input class="btn" type="submit" name="cancel" value="Cancel"/>
1488:                       <input class="btn" type="submit" name="save" value="Save" />
1489:                     </div>
1490:                   </div>
1491:                 </fieldset>
1492:                 <fieldset>
1493:                   <legend>KrISS feed paging menu preferences</legend>
1494:                   <div class="control-group">
1495:                     <label class="control-label" for="pagingItem">Item</label>
1496:                     <div class="controls">
1497:                       <input type="text" id="pagingItem" name="pagingItem" value="<?php echo empty($kfcpaging['pagingItem'])?'0':$kfcpaging['pagingItem']; ?>">
1498:                       <span class="help-block">If you want to go previous and next item </span>
1499:                     </div>
1500:                   </div>
1501:                   <div class="control-group">
1502:                     <label class="control-label" for="pagingPage">Page</label>
1503:                     <div class="controls">
1504:                       <input type="text" id="pagingPage" name="pagingPage" value="<?php echo empty($kfcpaging['pagingPage'])?'0':$kfcpaging['pagingPage']; ?>">
1505:                       <span class="help-block">If you want to go previous and next page </span>
1506:                     </div>
1507:                   </div>
1508:                   <div class="control-group">
1509:                     <label class="control-label" for="pagingByPage">Items by page</label>
1510:                     <div class="controls">
1511:                       <input type="text" id="pagingByPage" name="pagingByPage" value="<?php echo empty($kfcpaging['pagingByPage'])?'0':$kfcpaging['pagingByPage']; ?>">
1512:                       <span class="help-block">If you want to modify number of items by page</span>
1513:                     </div>
1514:                   </div>
1515:                   <div class="control-group">
1516:                     <label class="control-label" for="pagingMarkAs">Mark as read</label>
1517:                     <div class="controls">
1518:                       <input type="text" id="pagingMarkAs" name="pagingMarkAs" value="<?php echo empty($kfcpaging['pagingMarkAs'])?'0':$kfcpaging['pagingMarkAs']; ?>">
1519:                       <span class="help-block">If you add a mark as read button into paging</span>
1520:                     </div>
1521:                   </div>
1522:                   <div class="control-group">
1523:                     <div class="controls">
1524:                       <input class="btn" type="submit" name="cancel" value="Cancel"/>
1525:                       <input class="btn" type="submit" name="save" value="Save" />
1526:                     </div>
1527:                   </div>
1528:                 </fieldset>
1529:                 <fieldset>
1530:                   <legend>Cron configuration</legend>
1531:                   <code><?php echo MyTool::getUrl().'?update&cron='.$kfccron; ?></code>
1532:                   You can use <code>&force</code> to force update.<br>
1533:                   To update every 15 minutes
1534:                   <code>*/15 * * * * wget "<?php echo MyTool::getUrl().'?update&cron='.$kfccron; ?>" -O /tmp/kf.cron</code><br>
1535:                   To update every hour
1536:                   <code>0 * * * * wget "<?php echo MyTool::getUrl().'?update&cron='.$kfccron; ?>" -O /tmp/kf.cron</code><br>
1537:                   If you can not use wget, you may try php command line :
1538:                   <code>0 * * * * php -f <?php echo $_SERVER["SCRIPT_FILENAME"].' update '.$kfccron; ?> > /tmp/kf.cron</code>
1539:                   <div class="control-group">
1540:                     <div class="controls">
1541:                       <input class="btn" type="submit" name="cancel" value="Cancel"/>
1542:                       <input class="btn" type="submit" name="save" value="Save" />
1543:                     </div>
1544:                   </div>
1545:                 </fieldset>
1546:               </form><br>
1547:             </div>
1548:           </div>
1549:         </div>
1550:       </div>
1551:     </div>
1552:   </body>
1553: </html>
1554: <?php
1555:     }
1556: 
1557:     public static function helpTpl()
1558:     {
1559:         extract(FeedPage::$var);
1560: ?>
1561: <!DOCTYPE html>
1562: <html>
1563:   <head><?php FeedPage::includesTpl(); ?></head>
1564:   <body>
1565:     <div class="container-fluid">
1566:       <div class="row-fluid">
1567:         <div class="span6 offset3">
1568:           <div id="config">
1569:             <?php FeedPage::navTpl(); ?>
1570:             <div id="section">
1571:               <h2>Keyboard shortcut</h2>
1572:               <h3>Items navigation</h3>
1573:               <dl class="dl-horizontal">
1574:                 <dt>'space' or 't'</dt>
1575:                 <dd>When viewing items as list, let you open or close current item ('t'oggle current item)</dd>
1576:               </dl>
1577:               <dl class="dl-horizontal">
1578:                 <dt>'m'</dt>
1579:                 <dd>'M'ark current item as read if unread or unread if read</dd>
1580:               </dl>
1581:               <dl class="dl-horizontal">
1582:                 <dt>'n' or right arrow</dt>
1583:                 <dd>Go to 'n'ext item</dd>
1584:               </dl>
1585:               <dl class="dl-horizontal">
1586:                 <dt>'p' or left arrow</dt>
1587:                 <dd>Go to 'p'revious item</dd>
1588:               </dl>
1589:               <dl class="dl-horizontal">
1590:                 <dt>'shift' + 'n'</dt>
1591:                 <dd>Go to 'n'ext page</dd>
1592:               </dl>
1593:               <dl class="dl-horizontal">
1594:                 <dt>'shift' + 'p'</dt>
1595:                 <dd>Go to 'p'revious page</dd>
1596:               </dl>
1597:               <dl class="dl-horizontal">
1598:                 <dt>'j'</dt>
1599:                 <dd>Go to 'n'ext item and open it (in list view)</dd>
1600:               </dl>
1601:               <dl class="dl-horizontal">
1602:                 <dt>'k'</dt>
1603:                 <dd>Go to 'p'revious item and open it (in list view)</dd>
1604:               </dl>
1605:               <dl class="dl-horizontal">
1606:                 <dt>'o'</dt>
1607:                 <dd>'O'pen current item in new tab</dd>
1608:                 <dt>'shift' + 'o'</dt>
1609:                 <dd>'O'pen current item in current window</dd>
1610:               </dl>
1611:               <dl class="dl-horizontal">
1612:                 <dt>'s'</dt>
1613:                 <dd>'S'hare current item (go in <a href="?config" title="configuration">configuration</a> to set up you link)</dd>
1614:               </dl>
1615:               <dl class="dl-horizontal">
1616:                 <dt>'a'</dt>
1617:                 <dd>Mark 'a'll items, 'a'll items from current feed or 'a'll items from current folder as read</dd>
1618:               </dl>
1619:               <h3>Menu navigation</h3>
1620:               <dl class="dl-horizontal">
1621:                 <dt>'h'</dt>
1622:                 <dd>Go to 'H'ome page</dd>
1623:               </dl>
1624:               <dl class="dl-horizontal">
1625:                 <dt>'v'</dt>
1626:                 <dd>Change 'v'iew as list or expanded</dd>
1627:               </dl>
1628:               <dl class="dl-horizontal">
1629:                 <dt>'f'</dt>
1630:                 <dd>Show or hide list of 'f'eeds/'f'olders</dd>
1631:               </dl>
1632:               <dl class="dl-horizontal">
1633:                 <dt>'e'</dt>
1634:                 <dd>'E'dit current selection (all, folder or feed)</dd>
1635:               </dl>
1636:               <dl class="dl-horizontal">
1637:                 <dt>'u'</dt>
1638:                 <dd>'U'pdate current selection (all, folder or feed)</dd>
1639:               </dl>
1640:               <dl class="dl-horizontal">
1641:                 <dt>'r'</dt>
1642:                 <dd>'R'eload the page as the 'F5' key in most of browsers</dd>
1643:               </dl>
1644:               <dl class="dl-horizontal">
1645:                 <dt>'?' or 'F1'</dt>
1646:                 <dd>Go to Help page (actually it's shortcut to go to this page)</dd>
1647:               </dl>
1648:             </div>
1649: 
1650:             <div id="section">
1651:               <h2>Check configuration</h2>
1652:               <dl class="dl-horizontal">
1653:                 <dt>open_ssl</dt>
1654:                 <dd>
1655:                   <?php if (extension_loaded('openssl')) { ?>
1656:                   <span class="text-success">You should be able to load https:// rss links.</span>
1657:                   <?php } else { ?>
1658:                   <span class="text-error">You may have problems using https:// rss links.</span>
1659:                   <?php } ?>
1660:                 </dd>
1661:               </dl>
1662:             </div>
1663:           </div>
1664:         </div>
1665:       </div>
1666:     </div>
1667:   </body>
1668: </html>
1669: <?php
1670:     }
1671: 
1672:     public static function addFeedTpl()
1673:     {
1674:         extract(FeedPage::$var);
1675: ?>
1676: <!DOCTYPE html>
1677: <html>
1678:   <head>
1679:     <?php FeedPage::includesTpl(); ?>
1680:   </head>
1681:   <body>
1682:     <div class="container-fluid">
1683:       <div class="row-fluid">
1684:         <div id="edit-all" class="span6 offset3">
1685:           <?php FeedPage::statusTpl(); ?>
1686:           <?php FeedPage::navTpl(); ?>
1687:           <form class="form-horizontal" action="?add" method="POST">
1688:             <fieldset>
1689:               <legend>Add a new feed</legend>
1690:               <div class="control-group">
1691:                 <label class="control-label" > Feed url</label>
1692:                 <div class="controls">
1693:                   <input type="text" id="newfeed" name="newfeed" value="<?php echo $newfeed; ?>">                  
1694:                 </div>
1695:               </div>
1696:             </fieldset>
1697:             <fieldset>
1698:               <legend>Add selected folders to feed</legend>
1699:               <div class="control-group">
1700:                 <div class="controls">
1701:                   <?php foreach ($folders as $hash => $folder) { ?>
1702:                   <label for="add-folder-<?php echo $hash; ?>">
1703:                     <input type="checkbox" id="add-folder-<?php echo $hash; ?>" name="folders[]" value="<?php echo $hash; ?>"> <?php echo htmlspecialchars($folder['title']); ?> (<a href="?edit=<?php echo $hash; ?>">edit</a>)
1704:                   </label>
1705:                   <?php } ?>
1706:                 </div>
1707:               </div>
1708:               <div class="control-group">
1709:                 <label class="control-label" >Add to a new folder</label>
1710:                 <div class="controls">
1711:                   <input type="text" name="newfolder" value="">
1712:                 </div>
1713:               </div>
1714:               <div class="control-group">
1715:                 <div class="controls">
1716:                   <input class="btn" type="submit" name="add" value="Add new feed"/>
1717:                 </div>
1718:               </div>
1719:             </fieldset>
1720:             <fieldset>
1721:               <legend>Use bookmarklet to add a new feed</legend>
1722:               <div id="add-feed-bookmarklet" class="text-center">
1723:                 <a onclick="alert('Drag this link to your bookmarks toolbar, or right-click it and choose Bookmark This Link...');return false;" href="javascript:(function(){var%20url%20=%20location.href;window.open('<?php echo $kfurl;?>?add&amp;newfeed='+encodeURIComponent(url),'_blank','menubar=no,height=390,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1');})();"><b>Add KF</b></a>
1724:               </div>
1725:             </fieldset>
1726:             <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
1727:             <input type="hidden" name="returnurl" value="<?php echo $referer; ?>" />
1728:           </form>
1729:         </div>
1730:       </div>
1731:     </div>
1732:   </body>
1733: </html>
1734: <?php
1735:     }
1736: 
1737:     public static function editAllTpl()
1738:     {
1739:         extract(FeedPage::$var);
1740: ?>
1741: <!DOCTYPE html>
1742: <html>
1743:   <head>
1744:     <?php FeedPage::includesTpl(); ?>
1745:   </head>
1746:   <body>
1747:     <div class="container-fluid">
1748:       <div class="row-fluid">
1749:         <div id="edit-all" class="span6 offset3">
1750:           <?php FeedPage::statusTpl(); ?>
1751:           <?php FeedPage::navTpl(); ?>
1752:           <form class="form-horizontal" method="post" action="">
1753:             <fieldset>
1754:               <legend>Add selected folders to selected feeds</legend>
1755:               <div class="control-group">
1756:                 <div class="controls">
1757:                   <?php foreach ($folders as $hash => $folder) { ?>
1758:                   <label for="add-folder-<?php echo $hash; ?>">
1759:                     <input type="checkbox" id="add-folder-<?php echo $hash; ?>" name="addfolders[]" value="<?php echo $hash; ?>"> <?php echo htmlspecialchars($folder['title']); ?> (<a href="?edit=<?php echo $hash; ?>">edit</a>)
1760:                   </label>
1761:                   <?php } ?>
1762:                 </div>
1763:                 <div class="controls">
1764:                   <input type="text" name="addnewfolder" value="" placeholder="New folder">
1765:                 </div>
1766:               </div>
1767:             </fieldset>
1768: 
1769:             <fieldset>
1770:               <legend>Remove selected folders to selected feeds</legend>
1771:               <div class="control-group">
1772:                 <div class="controls">
1773:                   <?php foreach ($folders as $hash => $folder) { ?>
1774:                   <label for="remove-folder-<?php echo $hash; ?>">
1775:                     <input type="checkbox" id="remove-folder-<?php echo $hash; ?>" name="removefolders[]" value="<?php echo $hash; ?>"> <?php echo htmlspecialchars($folder['title']); ?> (<a href="?edit=<?php echo $hash; ?>">edit</a>)
1776:                   </label>
1777:                   <?php } ?>
1778:                 </div>
1779:               </div>
1780:             </fieldset>
1781: 
1782:             <input class="btn" type="submit" name="cancel" value="Cancel"/>
1783:             <input class="btn" type="submit" name="delete" value="Delete selected" onclick="return confirm('Do really want to delete all selected ?');"/>
1784:             <input class="btn" type="submit" name="save" value="Save selected" />
1785: 
1786:             <fieldset>
1787:               <legend>List of feeds</legend>
1788: 
1789:               <input class="btn" type="button" onclick="var feeds = document.getElementsByName('feeds[]'); for (var i = 0; i < feeds.length; i++) { feeds[i].checked = true; }" value="Select all">
1790:               <input class="btn" type="button" onclick="var feeds = document.getElementsByName('feeds[]'); for (var i = 0; i < feeds.length; i++) { feeds[i].checked = false; }" value="Unselect all">
1791: 
1792:               <ul class="unstyled">
1793:                 <?php foreach ($listFeeds as $feedHash => $feed) { ?>
1794:                 <li>
1795:                   <label for="feed-<?php echo $feedHash; ?>">
1796:                     <input type="checkbox" id="feed-<?php echo $feedHash; ?>" name="feeds[]" value="<?php echo $feedHash; ?>">
1797:                     <?php echo htmlspecialchars($feed['title']); ?> (<a href="?edit=<?php echo $feedHash; ?>">edit</a>)
1798:                   </label>
1799:                 </li>
1800:                 <?php } ?>
1801:               </ul>
1802:             </fieldset>
1803: 
1804:             <input type="hidden" name="returnurl" value="<?php echo $referer; ?>" />
1805:             <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
1806:             <input class="btn" type="submit" name="cancel" value="Cancel"/>
1807:             <input class="btn" type="submit" name="delete" value="Delete selected" onclick="return confirm('Do really want to delete all selected ?');"/>
1808:             <input class="btn" type="submit" name="save" value="Save selected" />
1809:           </form>
1810:         </div>
1811:       </div>
1812:   </body>
1813: </html>
1814: <?php
1815:     }
1816: 
1817:     public static function editFolderTpl()
1818:     {
1819:         extract(FeedPage::$var);
1820: ?>
1821: <!DOCTYPE html>
1822: <html>
1823:   <head>
1824:     <?php FeedPage::includesTpl(); ?>
1825:   </head>
1826:   <body>
1827:     <div class="container-fluid">
1828:       <div class="row-fluid">
1829:         <div id="edit-folder" class="span4 offset4">
1830:           <?php FeedPage::navTpl(); ?>
1831:           <form class="form-horizontal" method="post" action="">
1832:             <fieldset>
1833:               <div class="control-group">
1834:                 <label class="control-label" for="foldertitle">Folder title</label>
1835:                 <div class="controls">
1836:                   <input type="text" id="foldertitle" name="foldertitle" value="<?php echo $foldertitle; ?>">
1837:                   <span class="help-block">Leave empty to delete</span>
1838:                 </div>
1839:               </div>
1840: 
1841:               <div class="control-group">
1842:                 <div class="controls">
1843:                   <input class="btn" type="submit" name="cancel" value="Cancel"/>
1844:                   <input class="btn" type="submit" name="save" value="Save" />
1845:                 </div>
1846:               </div>
1847:             </fieldset>
1848: 
1849:             <input type="hidden" name="returnurl" value="<?php echo $referer; ?>" />
1850:             <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
1851:           </form>
1852:         </div>
1853:       </div>
1854:     </div>
1855:   </body>
1856: </html>
1857: <?php
1858:     }
1859: 
1860:     public static function editFeedTpl()
1861:     {
1862:         extract(FeedPage::$var);
1863: ?>
1864: <!DOCTYPE html>
1865: <html>
1866:   <head>
1867:     <?php FeedPage::includesTpl(); ?>
1868:   </head>
1869:   <body>
1870:     <div class="container-fluid">
1871:       <div class="row-fluid">
1872:         <div id="edit-feed" class="span6 offset3">
1873:           <?php FeedPage::statusTpl(); ?>
1874:           <?php FeedPage::navTpl(); ?>
1875:           <form class="form-horizontal" method="post" action="">
1876:             <fieldset>
1877:               <legend>Feed main information</legend>
1878:               <div class="control-group">
1879:                 <label class="control-label" for="title">Feed title</label>
1880:                 <div class="controls">
1881:                   <input type="text" id="title" name="title" value="<?php echo htmlspecialchars($feed['title']); ?>">
1882:                 </div>
1883:               </div>
1884:               <div class="control-group">
1885:                 <label class="control-label">Feed XML url</label>
1886:                 <div class="controls">
1887:                   <input type="text" readonly="readonly" name="xmlUrl" value="<?php echo htmlspecialchars($feed['xmlUrl']); ?>">
1888:                 </div>
1889:               </div>
1890:               <div class="control-group">
1891:                 <label class="control-label">Feed main url</label>
1892:                 <div class="controls">
1893:                   <input type="text" readonly="readonly" name="htmlUrl" value="<?php echo htmlspecialchars($feed['htmlUrl']); ?>">
1894:                 </div>
1895:               </div>
1896:               <div class="control-group">
1897:                 <label class="control-label" for="description">Feed description</label>
1898:                 <div class="controls">
1899:                   <input type="text" id="description" name="description" value="<?php echo htmlspecialchars($feed['description']); ?>">
1900:                 </div>
1901:               </div>
1902:             </fieldset>
1903:             <fieldset>
1904:               <legend>Feed folders</legend>
1905:               <?php
1906:                  foreach ($folders as $hash => $folder) {
1907:               $checked = '';
1908:               if (in_array($hash, $feed['foldersHash'])) {
1909:               $checked = ' checked="checked"';
1910:               }
1911:               ?>
1912:               <div class="control-group">
1913:                 <div class="controls">
1914:                   <label for="folder-<?php echo $hash; ?>">
1915:                     <input type="checkbox" id="folder-<?php echo $hash; ?>" name="folders[]" <?php echo $checked; ?> value="<?php echo $hash; ?>"> <?php echo htmlspecialchars($folder['title']); ?>
1916:                   </label>
1917:                 </div>
1918:               </div>
1919:               <?php } ?>
1920:               <div class="control-group">
1921:                 <label class="control-label" for="newfolder">New folder</label>
1922:                 <div class="controls">
1923:                   <input type="text" name="newfolder" value="" placeholder="New folder">
1924:                 </div>
1925:               </div>
1926:             </fieldset>
1927:             <fieldset>
1928:               <legend>Feed preferences</legend>
1929:               <div class="control-group">
1930:                 <label class="control-label" for="timeUpdate">Time update </label>
1931:                 <div class="controls">
1932:                   <input type="text" id="timeUpdate" name="timeUpdate" value="<?php echo $feed['timeUpdate']; ?>">
1933:                   <span class="help-block">'auto', 'max' or a number of minutes less than 'max' define in <a href="?config">config</a></span>
1934:                 </div>
1935:               </div>
1936:               <div class="control-group">
1937:                 <label class="control-label">Last update (<em>read only</em>)</label>
1938:                 <div class="controls">
1939:                   <input type="text" readonly="readonly" name="lastUpdate" value="<?php echo $lastUpdate; ?>">
1940:                 </div>
1941:               </div>
1942: 
1943:               <div class="control-group">
1944:                 <div class="controls">
1945:                   <input class="btn" type="submit" name="save" value="Save" />
1946:                   <input class="btn" type="submit" name="cancel" value="Cancel"/>
1947:                   <input class="btn" type="submit" name="delete" value="Delete"/>
1948:                 </div>
1949:               </div>
1950:             </fieldset>
1951:             <input type="hidden" name="returnurl" value="<?php echo $referer; ?>" />
1952:             <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
1953:           </form><br>
1954:         </div>
1955:       </div>
1956:     </div>
1957:   </body>
1958: </html>
1959: <?php
1960:     }
1961: 
1962:     public static function updateTpl()
1963:     {
1964:         extract(FeedPage::$var);
1965: ?>
1966: <!DOCTYPE html>
1967: <html>
1968:   <head>
1969:     <?php FeedPage::includesTpl(); ?>
1970:   </head>
1971:   <body>
1972:     <div class="container-fluid full-height">
1973:       <div class="row-fluid full-height">
1974:         <div class="span12 full-height">
1975:           <?php FeedPage::statusTpl(); ?>
1976:           <?php FeedPage::navTpl(); ?>
1977:           <div class="container-fluid">
1978:             <div class="row-fluid">
1979:               <div class="span6 offset3">
1980:                 <ul class="unstyled">
1981:                   <?php $kf->updateFeedsHash($feedsHash, $forceUpdate, 'html')?>
1982:                 </ul>
1983:                 <a class="btn" href="?">Go home</a>
1984:                 <?php if (!empty($referer)) { ?>
1985:                 <a class="btn" href="<?php echo htmlspecialchars($referer); ?>">Go back</a>
1986:                 <?php } ?>
1987:                 <a class="btn" href="<?php echo $query."update=".$currentHash."&force"; ?>">Force update</a>
1988:               </div>
1989:             </div>
1990:           </div>
1991:         </div>
1992:       </div>
1993:     </div>
1994:     <script type="text/javascript">
1995:       <?php /* include("inc/script.js"); */ ?>
1996:     </script>
1997:   </body>
1998: </html>
1999: <?php
2000:     }
2001: 
2002:     public static function importTpl()
2003:     {
2004:         extract(FeedPage::$var);
2005: ?>
2006: <!DOCTYPE html>
2007: <html>
2008:   <head>
2009:     <?php FeedPage::includesTpl(); ?>
2010:   </head>
2011:   <body>
2012:     <div class="container-fluid">
2013:       <div class="row-fluid">
2014:         <div class="span4 offset4">
2015:           <?php FeedPage::statusTpl(); ?>
2016:           <form class="form-horizontal" method="post" action="?import" enctype="multipart/form-data">
2017:             <fieldset>
2018:               <legend>Import Opml file</legend>
2019:               Import an opml file as exported by Google Reader, Tiny Tiny RSS, RSS lounge...
2020:              
2021:               <div class="control-group">
2022:                 <label class="control-label" for="filetoupload">File (Size max: <?php echo MyTool::humanBytes(MyTool::getMaxFileSize()); ?>)</label>
2023:                 <div class="controls">
2024:                   <input class="btn" type="file" id="filetoupload" name="filetoupload">
2025:                 </div>
2026:               </div>
2027: 
2028:               <div class="control-group">
2029:                 <div class="controls">
2030:                   <label for="overwrite">
2031:                     <input type="checkbox" name="overwrite" id="overwrite">
2032:                     Overwrite existing feeds
2033:                   </label>
2034:                 </div>
2035:               </div>
2036: 
2037:               <div class="control-group">
2038:                 <div class="controls">
2039:                   <input class="btn" type="submit" name="import" value="Import">
2040:                   <input class="btn" type="submit" name="cancel" value="Cancel">
2041:                 </div>
2042:               </div>
2043: 
2044:               <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo MyTool::getMaxFileSize(); ?>">
2045:               <input type="hidden" name="returnurl" value="<?php echo $referer; ?>" />
2046:               <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
2047:             </fieldset>
2048:           </form>
2049:         </div>
2050:       </div>
2051:     </div>
2052:   </body>
2053: </html>
2054: <?php
2055:     }
2056: 
2057:     public static function listFeedsTpl()
2058:     {
2059:         extract(FeedPage::$var);
2060: ?>
2061: <div id="list-feeds">
2062:   <?php
2063:      if ($listFeeds == 'show') {
2064:      ?>
2065:   <ul class="unstyled">
2066:     <li id="all-subscriptions" class="folder">
2067:       <h4><a class="mark-as" href="<?php echo ($feedsView['all']['nbUnread']==0?'?currentHash=all&unread':$query.'read').'=all'; ?>" title="Mark all as <?php echo ($feedsView['all']['nbUnread']==0?'unread':'read');?>"><span class="label"><?php echo $feedsView['all']['nbUnread']; ?></span></a><a href="<?php echo '?currentHash=all'; ?>"><?php echo $feedsView['all']['title']; ?></a></h4>
2068:       <ul class="unstyled">
2069:         <?php
2070:            foreach ($feedsView['all']['feeds'] as $feedHash => $feed) {
2071:         $atitle = trim(htmlspecialchars($feed['description']));
2072:         if (empty($atitle) || $atitle == ' ') {
2073:         $atitle = trim(htmlspecialchars($feed['title']));
2074:         }
2075:         if (isset($feed['error'])) {
2076:         $atitle = $feed['error'];
2077:         }
2078:         ?>
2079:        
2080:         <li id="<?php echo 'feed-'.$feedHash; ?>" class="feed<?php if ($feed['nbUnread']!== 0) echo ' has-unread'?><?php if ($autohide and $feed['nbUnread']== 0) { echo ' autohide-feed';} ?>">
2081:           <?php if ($addFavicon) { ?>
2082:           <img src="<?php echo grabFavicon($feed['htmlUrl'], $feedHash); ?>" height="16px" width="16px" title="favicon" alt="favicon"/>
2083:           <?php } ?>
2084: <a class="mark-as" href="<?php echo $query.'read='.$feedHash; ?>"><span class="label"><?php echo $feed['nbUnread']; ?></span></a><a class="feed<?php echo (isset($feed['error'])?' text-error':''); ?>" href="<?php echo '?currentHash='.$feedHash; ?>" title="<?php echo $atitle; ?>"><?php echo htmlspecialchars($feed['title']); ?></a>
2085:          
2086:         </li>
2087: 
2088:         <?php
2089:            }
2090:            foreach ($feedsView['folders'] as $hashFolder => $folder) {
2091:         $isOpen = $folder['isOpen'];
2092:         ?>
2093:        
2094:         <li id="folder-<?php echo $hashFolder; ?>" class="folder<?php if ($autohide and $folder['nbUnread']== 0) { echo ' autohide-folder';} ?>">
2095:           <h5>
2096:             <a class="mark-as" href="<?php echo $query.'read='.$hashFolder; ?>"><span class="label"><?php echo $folder['nbUnread']; ?></span></a>
2097:             <a class="folder-toggle" href="<?php echo $query.'toggleFolder='.$hashFolder; ?>" data-toggle="collapse" data-target="#folder-ul-<?php echo $hashFolder; ?>">
2098:               <span class="ico">
2099:                 <span class="ico-circle"></span>
2100:                 <span class="ico-line-h"></span>
2101:                 <span class="ico-line-v<?php echo ($isOpen?' folder-toggle-open':' folder-toggle-close'); ?>"></span>
2102:               </span>
2103:             </a>
2104:             <a href="<?php echo '?currentHash='.$hashFolder; ?>"><?php echo htmlspecialchars($folder['title']); ?></a>
2105:           </h5>
2106:           <ul id="folder-ul-<?php echo $hashFolder; ?>" class="collapse unstyled<?php echo $isOpen?' in':''; ?>">
2107:             <?php
2108:                foreach ($folder['feeds'] as $feedHash => $feed) {
2109:             $atitle = trim(htmlspecialchars($feed['description']));
2110:             if (empty($atitle) || $atitle == ' ') {
2111:             $atitle = trim(htmlspecialchars($feed['title']));
2112:             }
2113:             if (isset($feed['error'])) {
2114:             $atitle = $feed['error'];
2115:             }
2116:             ?>
2117: 
2118:             <li id="folder-<?php echo $hashFolder; ?>-feed-<?php echo $feedHash; ?>" class="feed<?php if ($feed['nbUnread']!== 0) echo ' has-unread'?><?php if ($autohide and $feed['nbUnread']== 0) { echo ' autohide-feed';} ?>">
2119:              
2120:               <?php if ($addFavicon) { ?>
2121:               <img src="<?php echo grabFavicon($feed['htmlUrl'], $feedHash); ?>" height="16px" width="16px" title="favicon" alt="favicon"/>
2122:               <?php } ?>
2123:               <a class="mark-as" href="<?php echo $query.'read='.$feedHash; ?>"><span class="label"><?php echo $feed['nbUnread']; ?></span></a><a class="feed<?php echo (isset($feed['error'])?' text-error':''); ?>" href="<?php echo '?currentHash='.$feedHash; ?>" title="<?php echo $atitle; ?>"><?php echo htmlspecialchars($feed['title']); ?></a>
2124:             </li>
2125:             <?php } ?>
2126:           </ul>
2127:         </li>
2128:         <?php
2129:            }
2130:            ?>
2131:       </ul>
2132:   </ul>
2133:   <?php
2134:      }
2135:      ?>
2136: 
2137: </div>
2138: <?php
2139:     }
2140: 
2141:     public static function listItemsTpl()
2142:     {
2143:         extract(FeedPage::$var);
2144: ?>
2145: <ul id="list-items" class="unstyled">
2146:   <?php
2147:      foreach (array_keys($items) as $itemHash){
2148:      $item = $kf->getItem($itemHash);
2149:   ?>
2150:   <li id="item-<?php echo $itemHash; ?>" class="<?php echo ($view==='expanded'?'item-expanded':'item-list'); ?><?php echo ($item['read']==1?' read':''); ?><?php echo ($itemHash==$currentItemHash?' current':''); ?>">
2151: 
2152:     <?php if ($view==='list') { ?>
2153:     <a id="item-toggle-<?php echo $itemHash; ?>" class="item-toggle item-toggle-plus" href="<?php echo $query.'current='.$itemHash.((!isset($_GET['open']) or $currentItemHash != $itemHash)?'&amp;open':''); ?>" data-toggle="collapse" data-target="#item-div-<?php echo $itemHash; ?>">
2154:       <?php echo $item['time']['list']; ?>
2155:       <span class="ico">
2156:         <span class="ico-circle"></span>
2157:         <span class="ico-line-h"></span>
2158:         <span class="ico-line-v<?php echo ((!isset($_GET['open']) or $currentItemHash != $itemHash)?' item-toggle-close':' item-toggle-open'); ?>"></span>
2159:       </span>
2160:     </a>
2161:     <dl class="dl-horizontal item">
2162:       <dt class="item-feed">
2163:         <span class="item-author">
2164:           <?php echo $item['author']; ?>
2165:         </span>
2166:       </dt>
2167:       <dd class="item-info">
2168:         <span class="item-title">
2169:           <?php if ($item['read'] == 1) { ?>
2170:           <a class="item-mark-as" href="<?php echo $query.'unread='.$itemHash; ?>"><span class="label">unread</span></a>
2171:           <?php } else { ?>
2172:           <a class="item-mark-as" href="<?php echo $query.'read='.$itemHash; ?>"><span class="label">read</span></a>
2173:           <?php } ?>
2174:           <a target="_blank"<?php echo ($redirector==='noreferrer'?' rel="noreferrer"':''); ?> class="item-link" href="<?php echo ($redirector!='noreferrer'?$redirector:'').$item['link']; ?>">
2175:             <?php echo $item['title']; ?>
2176:           </a>
2177:         </span>
2178:         <span class="item-description">
2179:           <a class="item-toggle muted" href="<?php echo $query.'current='.$itemHash.((!isset($_GET['open']) or $currentItemHash != $itemHash)?'&amp;open':''); ?>" data-toggle="collapse" data-target="#item-div-<?php echo $itemHash; ?>">
2180:             <?php echo $item['description']; ?>
2181:           </a>
2182:         </span>
2183:       </dd>
2184:     </dl>
2185:     <?php } ?>
2186: 
2187:     <div id="item-div-<?php echo $itemHash; ?>" class="item collapse<?php echo (($view==='expanded' or ($currentItemHash == $itemHash and isset($_GET['open'])))?' in well':''); ?><?php echo ($itemHash==$currentItemHash?' current':''); ?>">
2188:       <?php if ($view==='expanded' or ($currentItemHash == $itemHash and isset($_GET['open']))) { ?>
2189:       <div class="item-title">
2190:         <a class="item-shaarli" href="<?php echo $query.'shaarli='.$itemHash; ?>"><span class="label">share</span></a>
2191:         <?php if ($item['read'] == 1) { ?>
2192:         <a class="item-mark-as" href="<?php echo $query.'unread='.$itemHash; ?>"><span class="label item-label-mark-as">unread</span></a>
2193:         <?php } else { ?>
2194:         <a class="item-mark-as" href="<?php echo $query.'read='.$itemHash; ?>"><span class="label item-label-mark-as">read</span></a>
2195:         <?php } ?>
2196:         <a target="_blank"<?php echo ($redirector==='noreferrer'?' rel="noreferrer"':''); ?> class="item-link" href="<?php echo ($redirector!='noreferrer'?$redirector:'').$item['link']; ?>"><?php echo $item['title']; ?></a>
2197:       </div>
2198:       <div class="clear"></div>
2199:       <div class="item-info-end">
2200:         from <a class="item-via"<?php echo ($redirector==='noreferrer'?' rel="noreferrer"':''); ?> href="<?php echo ($redirector!='noreferrer'?$redirector:'').$item['via']; ?>"><?php echo $item['author']; ?></a>
2201:         <?php echo $item['time']['expanded']; ?>
2202:         <a class="item-xml"<?php echo ($redirector==='noreferrer'?' rel="noreferrer"':''); ?> href="<?php echo ($redirector!='noreferrer'?$redirector:'').$item['xmlUrl']; ?>">
2203:           <span class="ico">
2204:             <span class="ico-feed-dot"></span>
2205:             <span class="ico-feed-circle-1"></span>
2206:             <span class="ico-feed-circle-2"></span>
2207:           </span>
2208:         </a>
2209:       </div>
2210:       <div class="clear"></div>
2211:       <div class="item-content"><article>
2212:         <?php echo $item['content']; ?>
2213:       </article></div>
2214:       <div class="item-info-end">
2215:         <a class="item-shaarli" href="<?php echo $query.'shaarli='.$itemHash; ?>"><span class="label label-expanded">share</span></a>
2216:         <?php if ($item['read'] == 1) { ?>
2217:         <a class="item-mark-as" class="link-mark" href="<?php echo $query.'unread='.$itemHash; ?>"><span class="label label-expanded">unread</span></a>
2218:         <?php } else { ?>
2219:         <a class="item-mark-as" class="link-mark" href="<?php echo $query.'read='.$itemHash; ?>"><span class="label label-expanded">read</span></a>
2220:         <?php } ?>
2221:       </div>
2222:       <div class="clear"></div>
2223:       <?php } ?>
2224:     </div>
2225:   </li>
2226:   <?php } ?>
2227: </ul>
2228: <?php
2229:     }
2230: 
2231:     public static function pagingTpl()
2232:     {
2233:         extract(FeedPage::$var);
2234: ?>
2235: <ul class="inline">
2236:   <?php foreach(array_keys($paging) as $pagingOpt) { ?>
2237:   <?php switch($pagingOpt) {
2238:         case 'pagingItem': ?>
2239:   <li>
2240:     <div class="btn-group">
2241:       <a class="btn btn-info previous-item" href="<?php echo $query.'previous='.$currentItemHash; ?>">Previous item</a>
2242:       <a class="btn btn-info next-item" href="<?php echo $query.'next='.$currentItemHash; ?>">Next item</a>
2243:     </div>
2244:   </li>
2245:   <?php break; ?>
2246:   <?php case 'pagingMarkAs': ?>
2247:   <li>
2248:     <div class="btn-group">
2249:       <a class="btn btn-info" href="<?php echo $query.'read='.$currentHash; ?>">Mark as read</a>
2250:     </div>
2251:   </li>
2252:   <?php break; ?>
2253:   <?php case 'pagingPage': ?>
2254:   <li>
2255:     <div class="btn-group">
2256:       <a class="btn btn-info previous-page<?php echo ($currentPage === 1)?' disabled':''; ?>" href="<?php echo $query.'previousPage='.$currentPage; ?>">Previous page</a>
2257:       <button class="btn disabled current-max-page"><?php echo $currentPage.' / '.$maxPage; ?></button>
2258:       <a class="btn btn-info next-page<?php echo ($currentPage === $maxPage)?' disabled':''; ?>" href="<?php echo $query.'nextPage='.$currentPage; ?>">Next page</a>
2259:     </div>
2260:   </li>
2261:   <?php break; ?>
2262:   <?php case 'pagingByPage': ?>
2263:   <li>
2264:     <form class="form-inline" action="<?php echo $kfurl; ?>" method="GET">
2265:       <div class="input-prepend input-append paging-by-page">
2266:         <a class="btn btn-info" href="<?php echo $query.'byPage=1'; ?>">1</a>
2267:         <a class="btn btn-info" href="<?php echo $query.'byPage=10'; ?>">10</a>
2268:         <a class="btn btn-info" href="<?php echo $query.'byPage=50'; ?>">50</a>
2269:         <input class="input-by-page input-mini" type="text" name="byPage">
2270:         <input type="hidden" name="currentHash" value="<?php echo $currentHash; ?>">
2271:         <button type="submit" class="btn">items per page</button>
2272:       </div>
2273:     </form>
2274:   </li>
2275:   <?php break; ?>
2276:   <?php default: ?>
2277:   <?php break; ?>
2278:   <?php } ?>
2279:   <?php } ?>
2280: </ul>
2281: <div class="clear"></div>
2282: <?php
2283:     }
2284: 
2285:     public static function indexTpl()
2286:     {
2287:         extract(FeedPage::$var);
2288: ?>
2289: <!DOCTYPE html>
2290: <html>
2291:   <head>
2292:     <?php FeedPage::includesTpl(); ?>
2293:   </head>
2294:   <body>
2295:     <div id="index" class="container-fluid full-height" data-view="<?php echo $view; ?>" data-list-feeds="<?php echo $listFeeds; ?>" data-filter="<?php echo $filter; ?>" data-order="<?php echo $order; ?>" data-by-page="<?php echo $byPage; ?>" data-autoread-item="<?php echo $autoreadItem; ?>" data-autoread-page="<?php echo $autoreadPage; ?>" data-autohide="<?php echo $autohide; ?>" data-current-hash="<?php echo $currentHash; ?>" data-current-page="<?php echo $currentPage; ?>" data-nb-items="<?php echo $nbItems; ?>" data-shaarli="<?php echo $shaarli; ?>" data-redirector="<?php echo $redirector; ?>" data-autoupdate="<?php echo $autoupdate; ?>" data-autofocus="<?php echo $autofocus; ?>">
2296:       <div class="row-fluid full-height">
2297:         <?php if ($listFeeds == 'show') { ?>
2298:         <div id="main-container" class="span9 full-height">
2299:           <?php FeedPage::statusTpl(); ?>
2300:           <?php FeedPage::navTpl(); ?>
2301:           <div id="paging-up">
2302:             <?php if (!empty($paging)) {FeedPage::pagingTpl();} ?>
2303:           </div>
2304:           <?php FeedPage::listItemsTpl(); ?>
2305:           <div id="paging-down">
2306:             <?php if (!empty($paging)) {FeedPage::pagingTpl();} ?>
2307:           </div>
2308:         </div>
2309:         <div id="minor-container" class="span3 full-height minor-container">
2310:           <?php FeedPage::listFeedsTpl(); ?>
2311:         </div>
2312:         <?php } else { ?>
2313:         <div id="main-container" class="span12 full-height">
2314:           <?php FeedPage::statusTpl(); ?>
2315:           <?php FeedPage::navTpl(); ?>
2316:           <div id="paging-up">
2317:             <?php if (!empty($paging)) {FeedPage::pagingTpl();} ?>
2318:           </div>
2319:           <?php FeedPage::listItemsTpl(); ?>
2320:           <div id="paging-down">
2321:             <?php if (!empty($paging)) {FeedPage::pagingTpl();} ?>
2322:           </div>
2323:         </div>
2324:         <?php } ?>
2325:       </div>
2326:     </div>
2327:     <?php if (is_file('inc/script.js')) { ?>
2328:     <script type="text/javascript" src="inc/script.js?version=<?php echo $version;?>"></script>
2329:     <?php } else { ?>
2330:     <script type="text/javascript">
2331: (function () {
2332: 
2333:   var view = '', // data-view
2334:       listFeeds = '', // data-list-feeds
2335:       filter = '', // data-filter
2336:       order = '', // data-order
2337:       autoreadItem = '', // data-autoread-item
2338:       autoreadPage = '', // data-autoread-page
2339:       autohide = '', // data-autohide
2340:       byPage = -1, // data-by-page
2341:       shaarli = '', // data-shaarli
2342:       redirector = '', // data-redirector
2343:       currentHash = '', // data-current-hash
2344:       currentPage = 1, // data-current-page
2345:       currentNbItems = 0, // data-nb-items
2346:       autoupdate = false, // data-autoupdate
2347:       autofocus = false, // data-autofocus
2348:       status = '',
2349:       listUpdateFeeds = [],
2350:       listItemsHash = [],
2351:       currentItemHash = '',
2352:       currentUnread = 0,
2353:       title = '',
2354:       cache = {};
2355: 
2356:   if(!String.prototype.trim) {
2357:     String.prototype.trim = function () {
2358:       return this.replace(/^\s+|\s+$/g,'');
2359:     };
2360:   }
2361: 
2362:   if (!window.JSON) {
2363:     window.JSON = {
2364:       parse: function (sJSON) { return eval("(" + sJSON + ")"); },
2365:       stringify: function (vContent) {
2366:         if (vContent instanceof Object) {
2367:           var sOutput = "";
2368:           if (vContent.constructor === Array) {
2369:             for (var nId = 0; nId < vContent.length; sOutput += this.stringify(vContent[nId]) + ",", nId++);
2370:             return "[" + sOutput.substr(0, sOutput.length - 1) + "]";
2371:           }
2372:           if (vContent.toString !== Object.prototype.toString) { return "\"" + vContent.toString().replace(/"/g, "\\$&") + "\""; }
2373:           for (var sProp in vContent) { sOutput += "\"" + sProp.replace(/"/g, "\\$&") + "\":" + this.stringify(vContent[sProp]) + ","; }
2374:           return "{" + sOutput.substr(0, sOutput.length - 1) + "}";
2375:         }
2376:         return typeof vContent === "string" ? "\"" + vContent.replace(/"/g, "\\$&") + "\"" : String(vContent);
2377:       }
2378:     };
2379:   }
2380: 
2381:   function getXHR() {
2382:     var httpRequest = false;
2383: 
2384:     if (window.XMLHttpRequest) { // Mozilla, Safari, ...
2385:       httpRequest = new XMLHttpRequest();
2386:     } else if (window.ActiveXObject) { // IE
2387:       try {
2388:         httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
2389:       }
2390:       catch (e) {
2391:         try {
2392:           httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
2393:         }
2394:         catch (e) {}
2395:       }
2396:     }
2397: 
2398:     return httpRequest;
2399:   }
2400: 
2401:   // Constructor for generic HTTP client
2402:   function HTTPClient() {};
2403:   HTTPClient.prototype = {
2404:     url: null,
2405:     xhr: null,
2406:     callinprogress: false,
2407:     userhandler: null,
2408:     init: function(url) {
2409:       this.url = url;
2410:       this.xhr = new getXHR();
2411:     },
2412:     asyncGET: function (handler) {
2413:       // Prevent multiple calls
2414:       if (this.callinprogress) {
2415:         throw "Call in progress";
2416:       };
2417:       this.callinprogress = true;
2418:       this.userhandler = handler;
2419:       // Open an async request - third argument makes it async
2420:       this.xhr.open('GET', this.url, true);
2421:       var self = this;
2422:       // Assign a closure to the onreadystatechange callback
2423:       this.xhr.onreadystatechange = function() {
2424:         self.stateChangeCallback(self);
2425:       }
2426:       this.xhr.send(null);
2427:     },
2428:     stateChangeCallback: function(client) {
2429:       switch (client.xhr.readyState) {
2430:         // Request not yet made
2431:         case 1:
2432:         try { client.userhandler.onInit(); }
2433:         catch (e) { /* Handler method not defined */ }
2434:         break;
2435:         // Contact established with server but nothing downloaded yet
2436:         case 2:
2437:         try {
2438:           // Check for HTTP status 200
2439:           if ( client.xhr.status != 200 ) {
2440:             client.userhandler.onError(
2441:               client.xhr.status,
2442:               client.xhr.statusText
2443:             );
2444:             // Abort the request
2445:             client.xhr.abort();
2446:             // Call no longer in progress
2447:             client.callinprogress = false;
2448:           }
2449:         }
2450:         catch (e) { /* Handler method not defined */ }
2451:         break;
2452:         // Called multiple while downloading in progress
2453:         case 3:
2454:         // Notify user handler of download progress
2455:         try {
2456:           // Get the total content length
2457:           // -useful to work out how much has been downloaded
2458:           var contentLength;
2459:           try {
2460:             contentLength = client.xhr.getResponseHeader("Content-Length");
2461:           }
2462:           catch (e) { contentLength = NaN; }
2463:           // Call the progress handler with what we've got
2464:           client.userhandler.onProgress(
2465:             client.xhr.responseText,
2466:             contentLength
2467:           );
2468:         }
2469:         catch (e) { /* Handler method not defined */ }
2470:         break;
2471:         // Download complete
2472:         case 4:
2473:         try {
2474:           client.userhandler.onSuccess(client.xhr.responseText);
2475:         }
2476:         catch (e) { /* Handler method not defined */ }
2477:         finally { client.callinprogress = false; }
2478:         break;
2479:       }
2480:     }
2481:   }
2482: 
2483:   var ajaxHandler = {
2484:     onInit: function() {},
2485:     onError: function(status, statusText) {},
2486:     onProgress: function(responseText, length) {},
2487:     onSuccess: function(responseText) {
2488:       var result = JSON.parse(responseText);
2489: 
2490:       if (result['item']) {
2491:         cache['item-' + result['item']['itemHash']] = result['item'];
2492:         loadDivItem(result['item']['itemHash']);
2493:       }
2494:       if (result['page']) {
2495:         updateListItems(result['page']);
2496:         setCurrentItem();
2497:       }
2498:       if (result['read']) {
2499:         markAsRead(result['read']);
2500:       }
2501:       if (result['unread']) {
2502:         markAsUnread(result['unread']);
2503:       }
2504:       if (result['update']) {
2505:         updateNewItems(result['update']);
2506:       }
2507:     }
2508:   };
2509: 
2510:   function getSelectionHtml() {
2511:     var html = '';
2512:     if (typeof window.getSelection != 'undefined') {
2513:       var sel = window.getSelection();
2514:       if (sel.rangeCount) {
2515:         var container = document.createElement('div');
2516:         for (var i = 0, len = sel.rangeCount; i < len; ++i) {
2517:           container.appendChild(sel.getRangeAt(i).cloneContents());
2518:         }
2519:         html = container.innerHTML;
2520:       }
2521:     } else if (typeof document.selection != 'undefined') {
2522:       if (document.selection.type == 'Text') {
2523:         html = document.selection.createRange().htmlText;
2524:       }
2525:     }
2526:     return html;
2527:   }
2528: 
2529:   function removeChildren(elt) {
2530:     while (elt.hasChildNodes()) {
2531:       elt.removeChild(elt.firstChild);
2532:     }
2533:   }
2534: 
2535:   function removeElement(elt) {
2536:     if (elt && elt.parentNode) {
2537:       elt.parentNode.removeChild(elt);
2538:     }
2539:   }
2540: 
2541:   function addClass(elt, cls) {
2542:     if (elt) {
2543:       elt.className = (elt.className + ' ' + cls).trim();
2544:     }
2545:   }
2546: 
2547:   function removeClass(elt, cls) {
2548:     if (elt) {
2549:       elt.className = (' ' + elt.className + ' ').replace(cls, ' ').trim();
2550:     }
2551:   }
2552: 
2553:   function hasClass(elt, cls) {
2554:     if (elt && (' ' + elt.className + ' ').indexOf(' ' + cls + ' ') > -1) {
2555:       return true;
2556:     }
2557:     return false;
2558:   }
2559: 
2560:   function anonymize(elt) {
2561:     if (redirector !== '') {
2562:       var domain, a_to_anon = elt.getElementsByTagName("a");
2563:       for (var i = 0; i < a_to_anon.length; i++) {
2564:         domain = a_to_anon[i].href.replace('http://','').replace('https://','').split(/[/?#]/)[0];
2565:         if (domain !== window.location.host) {
2566:           if (redirector !== 'noreferrer') {
2567:             a_to_anon[i].href = redirector+a_to_anon[i].href;
2568:           } else {
2569:             a_to_anon[i].setAttribute('rel', 'noreferrer');
2570:           }
2571:         }
2572:       }
2573:     }
2574:   }
2575: 
2576:   function initAnonyme() {
2577:     if (redirector !== '') {
2578:       var i = 0, elements = document.getElementById('list-items');
2579:       elements = elements.getElementsByTagName('div');
2580:       for (i = 0; i < elements.length; i += 1) {
2581:         if (hasClass(elements[i], 'item-content')) {
2582:           anonymize(elements[i]);
2583:         }
2584:       }
2585:     }
2586:   }
2587: 
2588:   function collapseElement(element) {
2589:     if (element !== null) {
2590:       var targetElement = document.getElementById(
2591:         element.getAttribute('data-target').substring(1)
2592:       );
2593: 
2594:       if (hasClass(targetElement, 'in')) {
2595:         removeClass(targetElement, 'in');
2596:         targetElement.style.height = 0;
2597:       } else {
2598:         addClass(targetElement, 'in');
2599:         targetElement.style.height = 'auto';
2600:       }
2601:     }
2602:   }
2603: 
2604:   function collapseClick() {
2605:     collapseElement(this);
2606:   }
2607: 
2608:   function initCollapse(list) {
2609:     var i = 0;
2610: 
2611:     for (i = 0; i < list.length; i += 1) {
2612:       if (list[i].hasAttribute('data-toggle') && list[i].hasAttribute('data-target')) {
2613:         addEvent(list[i], 'click', collapseClick);
2614:       }
2615:     }
2616:   }
2617: 
2618:   function htmlspecialchars_decode(string) {
2619:     return string
2620:            .replace(/&lt;/g, '<')
2621:            .replace(/&gt;/g, '>')
2622:            .replace(/&quot;/g, '"')
2623:            .replace(/&amp;/g, '&')
2624:            .replace(/&#0*39;/g, "'");
2625:   }
2626: 
2627:   function shaarliItem(itemHash) {
2628:     var domainUrl, url, domainVia, via, title, sel, element;
2629: 
2630:    element = document.getElementById('item-div-'+itemHash);
2631:     if (element.childNodes.length > 1) {
2632:       title = getTitleItem(itemHash);
2633:       url = getUrlItem(itemHash);
2634:       if (redirector != 'noreferrer') {
2635:         url = url.replace(redirector,'');
2636:       }
2637:       via = getViaItem(itemHash);
2638:       domainUrl = url.replace('http://','').replace('https://','').split(/[/?#]/)[0];
2639:       domainVia = via.replace('http://','').replace('https://','').split(/[/?#]/)[0];
2640:       if (domainUrl !== domainVia) {
2641:         via = 'via ' + via;
2642:       } else {
2643:         via = '';
2644:       }
2645:       sel = getSelectionHtml();
2646:       if (sel != '') {
2647:         sel = '��' + sel + '��';
2648:       }
2649: 
2650:       window.open(
2651:         shaarli
2652:         .replace('${url}', encodeURIComponent(htmlspecialchars_decode(url)))
2653:         .replace('${title}', encodeURIComponent(htmlspecialchars_decode(title)))
2654:         .replace('${via}', encodeURIComponent(htmlspecialchars_decode(via)))
2655:         .replace('${sel}', encodeURIComponent(htmlspecialchars_decode(sel))),
2656:         '_blank',
2657:         'height=390, width=600, menubar=no, toolbar=no, scrollbars=no, status=no'
2658:       );
2659:     } else {
2660:       loadDivItem(itemHash);
2661:       alert('Sorry ! This item is not loaded, try again !');
2662:     }
2663:   }
2664: 
2665:   function shaarliCurrentItem() {
2666:     shaarliItem(currentItemHash);
2667:   }
2668: 
2669:   function shaarliClickItem() {
2670:     shaarliItem(getItemHash(this));
2671: 
2672:     return false;
2673:   }
2674: 
2675:   function getFolder(element) {
2676:     var folder = null
2677: 
2678:     while (folder === null && element !== null) {
2679:       if (element.tagName === 'LI' && element.id.indexOf('folder-') === 0) {
2680:         folder = element;
2681:       }
2682:       element = element.parentNode;
2683:     }
2684: 
2685:     return folder;
2686:   }
2687: 
2688:   function getFolderHash(element) {
2689:     var folder = getFolder(element);
2690: 
2691:     if (folder !== null) {
2692:       return folder.id.replace('folder-','');
2693:     }
2694: 
2695:     return null;
2696:   }
2697: 
2698:   function toggleFolder(folderHash) {
2699:     var i, listElements, url, client;
2700: 
2701:     listElements = document.getElementById('folder-' + folderHash);
2702:     listElements = listElements.getElementsByTagName('h5');
2703:     if (listElements.length > 0) {
2704:       listElements = listElements[0].getElementsByTagName('span');
2705: 
2706:       for (i = 0; i < listElements.length; i += 1) {
2707:         if (hasClass(listElements[i], 'folder-toggle-open')) {
2708:           removeClass(listElements[i], 'folder-toggle-open');
2709:           addClass(listElements[i], 'folder-toggle-close');
2710:         } else if (hasClass(listElements[i], 'folder-toggle-close')) {
2711:           removeClass(listElements[i], 'folder-toggle-close');
2712:           addClass(listElements[i], 'folder-toggle-open');
2713:         }
2714:       }
2715:     }
2716: 
2717:     url = '?toggleFolder=' + folderHash + '&ajax';
2718:     client = new HTTPClient();
2719: 
2720:     client.init(url);
2721:     try {
2722:       client.asyncGET(ajaxHandler);
2723:     } catch (e) {
2724:       alert(e);
2725:     }
2726:   }
2727: 
2728:   function toggleClickFolder() {
2729:     toggleFolder(getFolderHash(this));
2730: 
2731:     return false;
2732:   }
2733: 
2734:   function initLinkFolders(listFolders) {
2735:     var i = 0;
2736: 
2737:     for (i = 0; i < listFolders.length; i += 1) {
2738:       if (listFolders[i].hasAttribute('data-toggle') && listFolders[i].hasAttribute('data-target')) {
2739:         listFolders[i].onclick = toggleClickFolder;
2740:       }
2741:     }
2742:   }
2743: 
2744:   function getListLinkFolders() {
2745:     var i = 0,
2746:         listFolders = [],
2747:         listElements = document.getElementById('list-feeds');
2748: 
2749:     if (listElements) {
2750:       listElements = listElements.getElementsByTagName('a');
2751: 
2752:       for (i = 0; i < listElements.length; i += 1) {
2753:         listFolders.push(listElements[i]);
2754:       }
2755:     }
2756: 
2757:     return listFolders;
2758:   }
2759: 
2760:   function toggleMarkAsLinkItem(itemHash) {
2761:     var i, item = getItem(itemHash), listLinks;
2762: 
2763:     if (item !== null) {
2764:       listLinks = item.getElementsByTagName('a');
2765: 
2766:       for (i = 0; i < listLinks.length; i += 1) {
2767:         if (hasClass(listLinks[i], 'item-mark-as')) {
2768:           if (listLinks[i].href.indexOf('unread=') > -1) {
2769:             listLinks[i].href = listLinks[i].href.replace('unread=','read=');
2770:             listLinks[i].firstChild.innerHTML = 'read';
2771:           } else {
2772:             listLinks[i].href = listLinks[i].href.replace('read=','unread=');
2773:             listLinks[i].firstChild.innerHTML = 'unread';
2774:           }
2775:         }
2776:       }
2777:     }
2778:   }
2779: 
2780:   function markAsItem(itemHash) {
2781:     var item, url, client, indexItem;
2782: 
2783:     item = getItem(itemHash);
2784: 
2785:     if (item !== null) {
2786:       if (hasClass(item, 'read')) {
2787:         url = '?unread=' + itemHash;
2788:         removeClass(item, 'read');
2789:         toggleMarkAsLinkItem(itemHash);
2790:       } else {
2791:         url = '?read=' + itemHash;
2792:         addClass(item, 'read');
2793:         toggleMarkAsLinkItem(itemHash);
2794:         if (filter === 'unread') {
2795:           url += '&currentHash=' + currentHash
2796:                + '&page=' + currentPage
2797:                + '&last=' + listItemsHash[listItemsHash.length - 1];
2798: 
2799:           removeElement(item);
2800:           indexItem = listItemsHash.indexOf(itemHash);
2801:           listItemsHash.splice(listItemsHash.indexOf(itemHash), 1);
2802:           if (listItemsHash.length <= byPage) {
2803:             appendItem(listItemsHash[listItemsHash.length - 1]);
2804:           }
2805:           setCurrentItem(listItemsHash[indexItem]);
2806:         }
2807:       }
2808:     } else {
2809:       url = '?currentHash=' + currentHash
2810:           + '&page=' + currentPage;
2811:     }
2812: 
2813:     client = new HTTPClient();
2814:     client.init(url + '&ajax');
2815:     try {
2816:       client.asyncGET(ajaxHandler);
2817:     } catch (e) {
2818:       alert(e);
2819:     }
2820:   }
2821: 
2822:   function markAsCurrentItem() {
2823:     markAsItem(currentItemHash);
2824:   }
2825: 
2826:   function markAsClickItem() {
2827:     markAsItem(getItemHash(this));
2828: 
2829:     return false;
2830:   }
2831: 
2832:   function markAsRead(itemHash) {
2833:     setNbUnread(currentUnread - 1);
2834: 
2835:   }
2836: 
2837:   function markAsUnread(itemHash) {
2838:     setNbUnread(currentUnread + 1);
2839: 
2840:   }
2841: 
2842:   function loadDivItem(itemHash) {
2843:     var element, url, client, cacheItem;
2844: 
2845:     element = document.getElementById('item-div-'+itemHash);
2846:     if (element.childNodes.length <= 1) {
2847:       cacheItem = getCacheItem(itemHash);
2848:       if (cacheItem != null) {
2849:         setDivItem(element, cacheItem);
2850:         removeCacheItem(itemHash);
2851:       } else {
2852:         url = '?currentHash=' + currentHash
2853:             + '&current=' + itemHash
2854:             + '&ajax';
2855:         client = new HTTPClient();
2856:         client.init(url, element);
2857:         try {
2858:           client.asyncGET(ajaxHandler);
2859:         } catch (e) {
2860:           alert(e);
2861:         }
2862:       }
2863:     }
2864:   }
2865: 
2866:   function toggleItem(itemHash) {
2867:     var i, listElements, element, targetElement;
2868: 
2869:     if (view === 'expanded') {
2870:       return;
2871:     }
2872: 
2873:     if (currentItemHash != itemHash) {
2874:       closeCurrentItem();
2875:     }
2876: 
2877:     // looking for ico + or -
2878:     listElements = document.getElementById('item-toggle-' + itemHash);
2879:     listElements = listElements.getElementsByTagName('span');
2880:     for (i = 0; i < listElements.length; i += 1) {
2881:       if (hasClass(listElements[i], 'item-toggle-open')) {
2882:         removeClass(listElements[i], 'item-toggle-open');
2883:         addClass(listElements[i], 'item-toggle-close');
2884:       } else if (hasClass(listElements[i], 'item-toggle-close')) {
2885:         removeClass(listElements[i], 'item-toggle-close');
2886:         addClass(listElements[i], 'item-toggle-open');
2887:       }
2888:     }
2889: 
2890:     element = document.getElementById('item-toggle-'+itemHash);
2891:     targetElement = document.getElementById(
2892:       element.getAttribute('data-target').substring(1)
2893:     );
2894:     if (element.href.indexOf('&open') > -1) {
2895:       element.href = element.href.replace('&open','');
2896:       addClass(targetElement, 'well');
2897:       setCurrentItem(itemHash);
2898:       loadDivItem(itemHash);
2899:     } else {
2900:       element.href = element.href + '&open';
2901:       removeClass(targetElement, 'well');
2902:     }
2903:   }
2904: 
2905:   function toggleCurrentItem() {
2906:     toggleItem(currentItemHash);
2907:     collapseElement(document.getElementById('item-toggle-' + currentItemHash));
2908:   }
2909: 
2910:   function toggleClickItem() {
2911:     toggleItem(getItemHash(this));
2912: 
2913:     return false;
2914:   }
2915: 
2916:   function getItem(itemHash) {
2917:     return document.getElementById('item-' + itemHash);
2918:   }
2919: 
2920:   function getTitleItem(itemHash) {
2921:     var i = 0, element = document.getElementById('item-div-'+itemHash), listElements = element.getElementsByTagName('a'), title = '';
2922: 
2923:     for (i = 0; title === '' && i < listElements.length; i += 1) {
2924:       if (hasClass(listElements[i], 'item-link')) {
2925:         title = listElements[i].innerHTML;
2926:       }
2927:     }
2928: 
2929:     return title;
2930:   }
2931: 
2932:   function getUrlItem(itemHash) {
2933:     var i = 0, element = document.getElementById('item-'+itemHash), listElements = element.getElementsByTagName('a'), url = '';
2934: 
2935:     for (i = 0; url === '' && i < listElements.length; i += 1) {
2936:       if (hasClass(listElements[i], 'item-link')) {
2937:         url = listElements[i].href;
2938:       }
2939:     }
2940: 
2941:     return url;
2942:   }
2943: 
2944:   function getViaItem(itemHash) {
2945:     var i = 0, element = document.getElementById('item-div-'+itemHash), listElements = element.getElementsByTagName('a'), via = '';
2946: 
2947:     for (i = 0; via === '' && i < listElements.length; i += 1) {
2948:       if (hasClass(listElements[i], 'item-via')) {
2949:         via = listElements[i].href;
2950:       }
2951:     }
2952: 
2953:     return via;
2954:   }
2955: 
2956:   function getLiItem(element) {
2957:     var item = null
2958: 
2959:     while (item === null && element !== null) {
2960:       if (element.tagName === 'LI' && element.id.indexOf('item-') === 0) {
2961:         item = element;
2962:       }
2963:       element = element.parentNode;
2964:     }
2965: 
2966:     return item;
2967:   }
2968: 
2969:   function getItemHash(element) {
2970:     var item = getLiItem(element);
2971: 
2972:     if (item !== null) {
2973:       return item.id.replace('item-','');
2974:     }
2975: 
2976:     return null;
2977:   }
2978: 
2979:   function getCacheItem(itemHash) {
2980:     if (typeof cache['item-' + itemHash] !== 'undefined') {
2981:       return cache['item-' + itemHash];
2982:     }
2983: 
2984:     return null;
2985:   }
2986: 
2987:   function removeCacheItem(itemHash) {
2988:     if (typeof cache['item-' + itemHash] !== 'undefined') {
2989:       delete cache['item-' + itemHash];
2990:     }
2991:   }
2992: 
2993:   function isCurrentUnread() {
2994:     var item = getItem(currentItemHash);
2995: 
2996:     if (hasClass(item, 'read')) {
2997:       return false;
2998:     }
2999: 
3000:     return true;
3001:   }
3002: 
3003:   function setDivItem(div, item) {
3004:     var markAs = 'read';
3005: 
3006:       if (item['read'] == 1) {
3007:         markAs = 'unread';
3008:       }
3009: 
3010:     div.innerHTML = '<div class="item-title">' +
3011:       '<a class="item-shaarli" href="' + '?currentHash=' + currentHash + '&shaarli=' + item['itemHash'] + '"><span class="label">share</span></a> ' +
3012:       '<a class="item-mark-as" href="' + '?currentHash=' + currentHash + '&' + markAs + '=' + item['itemHash'] + '"><span class="label item-label-mark-as">' + markAs + '</span></a> ' +
3013:       '<a target="_blank" class="item-link" href="' + item['link'] + '">' +
3014:       item['title'] +
3015:       '</a>' +
3016:       '</div>' +
3017:       '<div class="clear"></div>' +
3018:       '<div class="item-info-end">' +
3019:       'from <a class="item-via" href="' + item['via'] + '">' +
3020:       item['author'] +
3021:       '</a> ' +
3022:       item['time']['expanded'] +
3023:       ' <a class="item-xml" href="' + item['xmlUrl'] + '">' +
3024:       '<span class="ico">' +
3025:       '<span class="ico-feed-dot"></span>' +
3026:       '<span class="ico-feed-circle-1"></span>' +
3027:       '<span class="ico-feed-circle-2"></span>'+
3028:       '</span>' +
3029:       '</a>' +
3030:       '</div>' +
3031:       '<div class="clear"></div>' +
3032:       '<div class="item-content"><article>' +
3033:       item['content'] +
3034:       '</article></div>' +
3035:       '<div class="item-info-end">' +
3036:       '<a class="item-shaarli" href="' + '?currentHash=' + currentHash + '&shaarli=' + item['itemHash'] + '"><span class="label label-expanded">share</span></a> ' +
3037:       '<a class="item-mark-as" href="' + '?currentHash=' + currentHash + '&' + markAs + '=' + item['itemHash'] + '"><span class="label label-expanded">' + markAs + '</span></a>' +
3038:       '</div>' +
3039:       '<div class="clear"></div>';
3040: 
3041:     initLinkItems(div.getElementsByTagName('a'));
3042: 
3043:     anonymize(div);
3044:   }
3045: 
3046:   function setLiItem(li, item) {
3047:     var markAs = 'read';
3048: 
3049:     if (item['read'] == 1) {
3050:       markAs = 'unread';
3051:     }
3052: 
3053:     li.innerHTML = '<a id="item-toggle-'+ item['itemHash'] +'" class="item-toggle item-toggle-plus" href="' + '?currentHash=' + currentHash + '&current=' + item['itemHash'] +'&open" data-toggle="collapse" data-target="#item-div-'+ item['itemHash'] + '"> ' +
3054:       item['time']['list'] +
3055:       ' <span class="ico">' +
3056:       '<span class="ico-circle"></span>' +
3057:       '<span class="ico-line-h"></span>' +
3058:       '<span class="ico-line-v item-toggle-close"></span>' +
3059:       '</span>' +
3060:       '</a>' +
3061:       '<dl class="dl-horizontal item">' +
3062:       '<dt class="item-feed">' +
3063:       '<span class="item-author">' +
3064:       item['author'] +
3065:       '</span>' +
3066:       '</dt>' +
3067:       '<dd class="item-info">' +
3068:       '<span class="item-title">' +
3069:       '<a class="item-mark-as" href="' + '?currentHash=' + currentHash + '&' + markAs + '=' + item['itemHash'] + '"><span class="label">' + markAs + '</span></a> ' +
3070:       '<a target="_blank" class="item-link" href="' + item['link'] + '">' +
3071:       item['title'] +
3072:       '</a> ' +
3073:       '</span>' +
3074:       '<span class="item-description">' +
3075:       '<a class="item-toggle muted" href="' + '?currentHash=' + currentHash + '&current=' + item['itemHash'] + '&open" data-toggle="collapse" data-target="#item-div-'+ item['itemHash'] + '">' +
3076:       item['description'] +
3077:       '</a> ' +
3078:       '</span>' +
3079:       '</dd>' +
3080:       '</dl>';
3081: 
3082:     initCollapse(li.getElementsByTagName('a'));
3083:     initLinkItems(li.getElementsByTagName('a'));
3084: 
3085:     anonymize(li);
3086:   }
3087: 
3088:   function createLiItem(item) {
3089:     var li = document.createElement('li'),
3090:         div = document.createElement('div');
3091: 
3092:     div.id = 'item-div-'+item['itemHash'];
3093:     div.className= 'item collapse'+(view === 'expanded' ? ' in well' : '');
3094: 
3095:     li.id = 'item-'+item['itemHash'];
3096:     if (view === 'list') {
3097:       li.className = 'item-list';
3098:       setLiItem(li, item);
3099:     } else {
3100:       li.className = 'item-expanded';
3101:       setDivItem(div, item);
3102:     }
3103:     li.className += (item['read'] === 1)?' read':'';
3104:     li.appendChild(div);
3105: 
3106:     return li;
3107:   }
3108: 
3109:   function getListItems() {
3110:     return document.getElementById('list-items');
3111:   }
3112: 
3113:   function updateListItems(itemsList) {
3114:     var i;
3115: 
3116:     for (i = 0; i < itemsList.length; i++) {
3117:       if (listItemsHash.indexOf(itemsList[i]['itemHash']) === -1 && listItemsHash.length <= byPage) {
3118:         cache['item-' + itemsList[i]['itemHash']] = itemsList[i];
3119:         listItemsHash.push(itemsList[i]['itemHash']);
3120:         if (listItemsHash.length <= byPage) {
3121:           appendItem(itemsList[i]['itemHash']);
3122:         }
3123:       }
3124:     }
3125:   }
3126: 
3127:   function appendItem(itemHash) {
3128:     var listItems = getListItems(),
3129:         item = getCacheItem(itemHash),
3130:         li;
3131: 
3132:     if (item !== null) {
3133:       li = createLiItem(item);
3134:       listItems.appendChild(li);
3135:       removeCacheItem(itemHash);
3136:     }
3137:   }
3138: 
3139:   function getListLinkItems() {
3140:     var i = 0,
3141:         listItems = [],
3142:         listElements = document.getElementById('list-items');
3143: 
3144:     listElements = listElements.getElementsByTagName('a');
3145: 
3146:     for (i = 0; i < listElements.length; i += 1) {
3147:       listItems.push(listElements[i]);
3148:     }
3149: 
3150:     return listItems;
3151:   }
3152: 
3153:   function initListItemsHash() {
3154:     var i,
3155:         listElements = document.getElementById('list-items');
3156: 
3157:     listElements = listElements.getElementsByTagName('li');
3158:     for (i = 0; i < listElements.length; i += 1) {
3159:       if (hasClass(listElements[i], 'item-list') || hasClass(listElements[i], 'item-expanded')) {
3160:         if (hasClass(listElements[i], 'current')) {
3161:           currentItemHash = getItemHash(listElements[i]);
3162:         }
3163:         listItemsHash.push(listElements[i].id.replace('item-',''));
3164:       }
3165:     }
3166:   }
3167: 
3168:   function initLinkItems(listItems) {
3169:     var i = 0;
3170: 
3171:     for (i = 0; i < listItems.length; i += 1) {
3172:       if (hasClass(listItems[i], 'item-toggle')) {
3173:         listItems[i].onclick = toggleClickItem;
3174:       }
3175:       if (hasClass(listItems[i], 'item-mark-as')) {
3176:         listItems[i].onclick = markAsClickItem;
3177:       }
3178:       if (hasClass(listItems[i], 'item-shaarli')) {
3179:         listItems[i].onclick = shaarliClickItem;
3180:       }
3181:     }
3182:   }
3183: 
3184:   function initListItems() {
3185:     var url, client;
3186: 
3187:     url = '?currentHash=' + currentHash
3188:         + '&page=' + currentPage
3189:         + '&last=' + listItemsHash[listItemsHash.length -1]
3190:         + '&ajax';
3191: 
3192:     client = new HTTPClient();
3193:     client.init(url);
3194:     try {
3195:       client.asyncGET(ajaxHandler);
3196:     } catch (e) {
3197:       alert(e);
3198:     }
3199:   }
3200: 
3201:   function setStatus(text) {
3202:     if (text === '') {
3203:       document.getElementById('status').innerHTML = status;
3204:     } else {
3205:       document.getElementById('status').innerHTML = text;
3206:     }
3207:   }
3208: 
3209:   function getTimeMin() {
3210:     return Math.round((new Date().getTime()) / 1000 / 60);
3211:   }
3212: 
3213:   function updateFeed(feedHashIndex) {
3214:     var i = 0, url, client, feedHash = '';
3215: 
3216:     if (feedHashIndex !== '') {
3217:       setStatus('updating ' + listUpdateFeeds[feedHashIndex][1]);
3218:       feedHash = listUpdateFeeds[feedHashIndex][0];
3219:       listUpdateFeeds[feedHashIndex][2] = getTimeMin();
3220:     }
3221: 
3222:     url = '?update'+(feedHash === ''?'':'='+feedHash)+'&ajax';
3223: 
3224:     client = new HTTPClient();
3225:     client.init(url);
3226:     try {
3227:       client.asyncGET(ajaxHandler);
3228:     } catch (e) {
3229:       alert(e);
3230:     }
3231:   }
3232: 
3233:   function updateNextFeed() {
3234:     var i = 0, nextTimeUpdate = 0, currentMin, diff, minDiff = -1, feedToUpdateIndex = '', minFeedToUpdateIndex = '';
3235:     if (listUpdateFeeds.length !== 0) {
3236:       currentMin = getTimeMin();
3237:       for (i = 0; feedToUpdateIndex === '' && i < listUpdateFeeds.length; i++) {
3238:         diff = currentMin - listUpdateFeeds[i][2];
3239:         if (diff >= listUpdateFeeds[i][3]) {
3240:           //need update
3241:           feedToUpdateIndex = i;
3242:         } else {
3243:           if (minDiff === -1 || diff < minDiff) {
3244:             minDiff = diff;
3245:             minFeedToUpdateIndex = i;
3246:           }
3247:         }
3248:       }
3249:       if (feedToUpdateIndex === '') {
3250:         feedToUpdateIndex = minFeedToUpdateIndex;
3251:       }
3252:       updateFeed(feedToUpdateIndex);
3253:     } else {
3254:       updateFeed('');
3255:     }
3256:   }
3257: 
3258:   function updateTimeout() {
3259:     var i = 0, nextTimeUpdate = 0, currentMin, diff, minDiff = -1, feedToUpdateIndex = '';
3260: 
3261:     if (listUpdateFeeds.length !== 0) {
3262:       currentMin = getTimeMin();
3263:       for (i = 0; minDiff !== 0 && i < listUpdateFeeds.length; i++) {
3264:         diff = currentMin - listUpdateFeeds[i][2];
3265:         if (diff >= listUpdateFeeds[i][3]) {
3266:           //need update
3267:           minDiff = 0;
3268:         } else {
3269:           if (minDiff === -1 || (listUpdateFeeds[i][3] - diff) < minDiff) {
3270:             minDiff = listUpdateFeeds[i][3] - diff;
3271:           }
3272:         }
3273:       }
3274:       window.setTimeout(updateNextFeed, minDiff * 1000 * 60 + 200);
3275:     }
3276:   }
3277: 
3278:   function updateNewItems(result) {
3279:     var i = 0, list, currentMin;
3280:     setStatus('');
3281:     if (result !== false) {
3282:       if (result['feeds']) {
3283:         // init list of feeds information for update
3284:         listUpdateFeeds = result['feeds'];
3285:         currentMin = getTimeMin();
3286:         for (i = 0; i < listUpdateFeeds.length; i++) {
3287:           listUpdateFeeds[i][2] = currentMin - listUpdateFeeds[i][2];
3288:         }
3289:       }
3290:       if (result['newItems']) {
3291:         currentNbItems += result['newItems'].length;
3292:         setNbUnread(currentUnread + result['newItems'].length);
3293:       }
3294:       updateTimeout();
3295:     }
3296:   }
3297: 
3298:   function initUpdate() {
3299:     window.setTimeout(updateNextFeed, 1000);
3300:   }
3301: 
3302:   function setWindowLocation() {
3303:     if (currentItemHash != '' && autofocus) {
3304:       window.location = '#item-' + currentItemHash;
3305:     }
3306:   }
3307: 
3308:   function previousClickPage() {
3309:     previousPage();
3310: 
3311:     return false;
3312:   }
3313: 
3314:   function nextClickPage() {
3315:     nextPage();
3316: 
3317:     return false;
3318:   }
3319: 
3320:   function nextPage() {
3321:     currentPage = currentPage + 1;
3322:     if (currentPage > Math.ceil(currentNbItems / byPage)) {
3323:       currentPage = Math.ceil(currentNbItems / byPage);
3324:     }
3325:     if (listItemsHash.length == 0) {
3326:       currentPage = 1;
3327:     }
3328:     listItemsHash = [];
3329:     initListItems();
3330:     removeChildren(getListItems());
3331:   }
3332: 
3333:   function previousPage() {
3334:     currentPage = currentPage - 1;
3335:     if (currentPage < 1) {
3336:       currentPage = 1;
3337:     }
3338:     listItemsHash = [];
3339:     initListItems();
3340:     removeChildren(getListItems());
3341:   }
3342: 
3343:   function previousClickItem() {
3344:     previousItem();
3345: 
3346:     return false;
3347:   }
3348: 
3349:   function nextClickItem() {
3350:     nextItem();
3351: 
3352:     return false;
3353:   }
3354: 
3355:   function nextItem() {
3356:     var nextItemIndex = listItemsHash.indexOf(currentItemHash) + 1, nextCurrentItemHash;
3357: 
3358:     closeCurrentItem();
3359:     if (autoreadItem && isCurrentUnread()) {
3360:       markAsCurrentItem();
3361:       if (filter == 'unread') {
3362:         nextItemIndex -= 1;
3363:       }
3364:     }
3365: 
3366:     if (nextItemIndex < 0) { nextItemIndex = 0; }
3367: 
3368:     if (nextItemIndex < listItemsHash.length) {
3369:       nextCurrentItemHash = listItemsHash[nextItemIndex];
3370:     }
3371: 
3372:     if (nextItemIndex >= byPage) {
3373:       nextPage();
3374:     } else {
3375:       setCurrentItem(nextCurrentItemHash);
3376:     }
3377:   }
3378: 
3379:   function previousItem() {
3380:     var previousItemIndex = listItemsHash.indexOf(currentItemHash) - 1, previousCurrentItemHash;
3381: 
3382:     if (previousItemIndex < listItemsHash.length && previousItemIndex >= 0) {
3383:       previousCurrentItemHash = listItemsHash[previousItemIndex];
3384:     }
3385: 
3386:     closeCurrentItem();
3387:     if (previousItemIndex < 0) {
3388:       previousPage();
3389:     } else {
3390:       setCurrentItem(previousCurrentItemHash);
3391:     }
3392:   }
3393: 
3394:   function closeCurrentItem() {
3395:     var element = document.getElementById('item-toggle-' + currentItemHash);
3396: 
3397:     if (element && view === 'list') {
3398:       var targetElement = document.getElementById(
3399:             element.getAttribute('data-target').substring(1)
3400:           );
3401: 
3402:       if (element.href.indexOf('&open') < 0) {
3403:         element.href = element.href + '&open';
3404:         removeClass(targetElement, 'well');
3405:         collapseElement(element);
3406:       }
3407: 
3408:       var i = 0,
3409:           listElements = element.getElementsByTagName('span');
3410: 
3411:       // looking for ico + or -
3412:       for (i = 0; i < listElements.length; i += 1) {
3413:         if (hasClass(listElements[i], 'item-toggle-open')) {
3414:           removeClass(listElements[i], 'item-toggle-open');
3415:           addClass(listElements[i], 'item-toggle-close');
3416:         }
3417:       }
3418:     }
3419:   }
3420: 
3421:   function setCurrentItem(itemHash) {
3422:     var currentItemIndex;
3423: 
3424:     if (itemHash !== currentItemHash) {
3425:       removeClass(document.getElementById('item-'+currentItemHash), 'current');
3426:       removeClass(document.getElementById('item-div-'+currentItemHash), 'current');
3427:       if (typeof itemHash !== 'undefined') {
3428:         currentItemHash = itemHash;
3429:       }
3430:       currentItemIndex = listItemsHash.indexOf(currentItemHash);
3431:       if (currentItemIndex === -1) {
3432:         if (listItemsHash.length > 0) {
3433:           currentItemHash = listItemsHash[0];
3434:         } else {
3435:           currentItemHash = '';
3436:         }
3437:       } else {
3438:         if (currentItemIndex >= byPage) {
3439:           currentItemHash = listItemsHash[byPage - 1];
3440:         }
3441:       }
3442: 
3443:       if (currentItemHash !== '') {
3444:         addClass(document.getElementById('item-'+currentItemHash), 'current');
3445:         addClass(document.getElementById('item-div-'+currentItemHash), 'current');
3446:         setWindowLocation();
3447:         updateItemButton();
3448:       }
3449:     }
3450:     updatePageButton();
3451:   }
3452: 
3453:   function openCurrentItem(blank) {
3454:     var url;
3455: 
3456:     url = getUrlItem(currentItemHash);
3457:     if (blank) {
3458:       window.location.href = url;
3459:     } else {
3460:       window.open(url);
3461:     }
3462:   }
3463: 
3464:   // http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.js (swipe)
3465:   function checkMove(e) {
3466:     // More than this horizontal displacement, and we will suppress scrolling.
3467:     var scrollSupressionThreshold = 10,
3468:     // More time than this, and it isn't a swipe.
3469:         durationThreshold = 500,
3470:     // Swipe horizontal displacement must be more than this.
3471:         horizontalDistanceThreshold = 30,
3472:     // Swipe vertical displacement must be less than this.
3473:         verticalDistanceThreshold = 75;
3474: 
3475:     if (e.targetTouches.length == 1) {
3476:       var touch = e.targetTouches[0],
3477:       start = { time: ( new Date() ).getTime(),
3478:                 coords: [ touch.pageX, touch.pageY ] },
3479:       stop;
3480:       function moveHandler( e ) {
3481: 
3482:         if ( !start ) {
3483:           return;
3484:         }
3485: 
3486:         if (e.targetTouches.length == 1) {
3487:           var touch = e.targetTouches[0];
3488:           stop = { time: ( new Date() ).getTime(),
3489:                    coords: [ touch.pageX, touch.pageY ] };
3490: 
3491:           // prevent scrolling
3492:           if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] )
3493:                                         >  scrollSupressionThreshold
3494:              ) {
3495:             e.preventDefault();
3496:           }
3497:         }
3498:       }
3499: 
3500:       addEvent(window, 'touchmove', moveHandler);
3501:       addEvent(window, 'touchend', function (e) {
3502:         removeEvent(window, 'touchmove', moveHandler);
3503:         if ( start && stop ) {
3504:           if ( stop.time - start.time < durationThreshold
3505:             && Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] )
3506:              > horizontalDistanceThreshold
3507:             && Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] )
3508:              < verticalDistanceThreshold
3509:              ) {
3510:             start.coords[0] > stop.coords[ 0 ]
3511:                 ? nextItem()
3512:                 : previousItem() ;
3513:           }
3514:           start = stop = undefined;
3515:         }
3516:       });
3517:     }
3518:   }
3519: 
3520:   function checkKey(e) {
3521:     var code;
3522:     if (!e) e = window.event;
3523:     if (e.keyCode) code = e.keyCode;
3524:     else if (e.which) code = e.which;
3525: 
3526:     if (!e.ctrlKey && !e.altKey) {
3527:       switch(code) {
3528:         case 32: // 'space'
3529:         toggleCurrentItem();
3530:         break;
3531:         case 65: // 'A'
3532:         if (window.confirm('Mark all current as read ?')) {
3533:           window.location.href = '?read=' + currentHash;
3534:         }
3535:         break;
3536:         case 67: // 'C'
3537:         window.location.href = '?config';
3538:         break;
3539:         case 69: // 'E'
3540:         window.location.href = (currentHash==''?'?edit':'?edit='+currentHash);
3541:         break;
3542:         case 70: // 'F'
3543:         if (listFeeds =='show') {
3544:           window.location.href = (currentHash==''?'?':'?currentHash='+currentHash+'&')+'listFeeds=hide';
3545:         } else {
3546:           window.location.href = (currentHash==''?'?':'?currentHash='+currentHash+'&')+'listFeeds=show';
3547:         }
3548:         break;
3549:         case 72: // 'H'
3550:         window.location.href = document.getElementById('nav-home').href;
3551:         break;
3552:         case 74: // 'J'
3553:         nextItem();
3554:         toggleCurrentItem();
3555:         break;
3556:         case 75: // 'K'
3557:         previousItem();
3558:         toggleCurrentItem();
3559:         break;
3560:         case 77: // 'M'
3561:         markAsCurrentItem();
3562:         break;
3563:         case 39: // right arrow
3564:         case 78: // 'N'
3565:         if (e.shiftKey) {
3566:           nextPage();
3567:         } else {
3568:           nextItem();
3569:         }
3570:         break;
3571:         case 79: // 'O'
3572:         if (e.shiftKey) {
3573:           openCurrentItem(true);
3574:         } else {
3575:           openCurrentItem(false);
3576:         }
3577:         break;
3578:         case 37: // left arrow
3579:         case 80 : // 'P'
3580:         if (e.shiftKey) {
3581:           previousPage();
3582:         } else {
3583:           previousItem();
3584:         }
3585:         break;
3586:         case 82: // 'R'
3587:         window.location.reload(true);
3588:         break;
3589:         case 83: // 'S'
3590:         shaarliCurrentItem();
3591:         break;
3592:         case 84: // 'T'
3593:         toggleCurrentItem();
3594:         break;
3595:         case 85: // 'U'
3596:         window.location.href = (currentHash==''?'?update':'?currentHash=' + currentHash + '&update='+currentHash);
3597:         break;
3598:         case 86: // 'V'
3599:         if (view == 'list') {
3600:           window.location.href = (currentHash==''?'?':'?currentHash='+currentHash+'&')+'view=expanded';
3601:         } else {
3602:           window.location.href = (currentHash==''?'?':'?currentHash='+currentHash+'&')+'view=list';
3603:         }
3604:         break;
3605:         case 112: // 'F1'
3606:         case 188: // '?'
3607:         case 191: // '?'
3608:         window.location.href = '?help';
3609:         break;
3610:         default:
3611:         break;
3612:       }
3613:     }
3614:     // e.ctrlKey e.altKey e.shiftKey
3615:   }
3616: 
3617:   function initPageButton() {
3618:     var i = 0, paging, listElements;
3619: 
3620:     paging = document.getElementById('paging-up');
3621:     if (paging) {
3622:       listElements = paging.getElementsByTagName('a');
3623:       for (i = 0; i < listElements.length; i += 1) {
3624:         if (hasClass(listElements[i], 'previous-page')) {
3625:           listElements[i].onclick = previousClickPage;
3626:         }
3627:         if (hasClass(listElements[i], 'next-page')) {
3628:           listElements[i].onclick = nextClickPage;
3629:         }
3630:       }
3631:     }
3632: 
3633:     paging = document.getElementById('paging-down');
3634:     if (paging) {
3635:       listElements = paging.getElementsByTagName('a');
3636:       for (i = 0; i < listElements.length; i += 1) {
3637:         if (hasClass(listElements[i], 'previous-page')) {
3638:           listElements[i].onclick = previousClickPage;
3639:         }
3640:         if (hasClass(listElements[i], 'next-page')) {
3641:           listElements[i].onclick = nextClickPage;
3642:         }
3643:       }
3644:     }
3645:   }
3646: 
3647:   function updatePageButton() {
3648:     var i = 0, paging, listElements, maxPage;
3649: 
3650:     if (filter == 'unread') {
3651:       currentNbItems = currentUnread;
3652:     }
3653: 
3654:     if (currentNbItems < byPage) {
3655:       maxPage = 1;
3656:     } else {
3657:       maxPage = Math.ceil(currentNbItems / byPage);
3658:     }
3659: 
3660:     paging = document.getElementById('paging-up');
3661:     if (paging) {
3662:       listElements = paging.getElementsByTagName('a');
3663:       for (i = 0; i < listElements.length; i += 1) {
3664:         if (hasClass(listElements[i], 'previous-page')) {
3665:           listElements[i].href = '?currentHash=' + currentHash
3666:                                + '&previousPage=' + currentPage;
3667:           if (currentPage === 1) {
3668:             if (!hasClass(listElements[i], 'disabled')) {
3669:               addClass(listElements[i], 'disabled');
3670:             }
3671:           } else {
3672:             if (hasClass(listElements[i], 'disabled')) {
3673:               removeClass(listElements[i], 'disabled');
3674:             }
3675:           }
3676:         }
3677:         if (hasClass(listElements[i], 'next-page')) {
3678:           listElements[i].href = '?currentHash=' + currentHash
3679:                                + '&nextPage=' + currentPage;
3680:           if (currentPage === maxPage) {
3681:             if (!hasClass(listElements[i], 'disabled')) {
3682:               addClass(listElements[i], 'disabled');
3683:             }
3684:           } else {
3685:             if (hasClass(listElements[i], 'disabled')) {
3686:               removeClass(listElements[i], 'disabled');
3687:             }
3688:           }
3689:         }
3690:       }
3691:       listElements = paging.getElementsByTagName('button');
3692:       for (i = 0; i < listElements.length; i += 1) {
3693:         if (hasClass(listElements[i], 'current-max-page')) {
3694:           listElements[i].innerHTML = currentPage + ' / ' + maxPage;
3695:         }
3696:       }
3697:     }
3698:     paging = document.getElementById('paging-down');
3699:     if (paging) {
3700:       listElements = paging.getElementsByTagName('a');
3701:       for (i = 0; i < listElements.length; i += 1) {
3702:         if (hasClass(listElements[i], 'previous-page')) {
3703:           listElements[i].href = '?currentHash=' + currentHash
3704:                                + '&previousPage=' + currentPage;
3705:           if (currentPage === 1) {
3706:             if (!hasClass(listElements[i], 'disabled')) {
3707:               addClass(listElements[i], 'disabled');
3708:             }
3709:           } else {
3710:             if (hasClass(listElements[i], 'disabled')) {
3711:               removeClass(listElements[i], 'disabled');
3712:             }
3713:           }
3714:         }
3715:         if (hasClass(listElements[i], 'next-page')) {
3716:           listElements[i].href = '?currentHash=' + currentHash
3717:                                + '&nextPage=' + currentPage;
3718:           if (currentPage === maxPage) {
3719:             if (!hasClass(listElements[i], 'disabled')) {
3720:               addClass(listElements[i], 'disabled');
3721:             }
3722:           } else {
3723:             if (hasClass(listElements[i], 'disabled')) {
3724:               removeClass(listElements[i], 'disabled');
3725:             }
3726:           }
3727:         }
3728:       }
3729:       listElements = paging.getElementsByTagName('button');
3730:       for (i = 0; i < listElements.length; i += 1) {
3731:         if (hasClass(listElements[i], 'current-max-page')) {
3732:           listElements[i].innerHTML = currentPage + ' / ' + maxPage;
3733:         }
3734:       }
3735:     }
3736:   }
3737: 
3738:   function initItemButton() {
3739:     var i = 0, paging, listElements;
3740: 
3741:     paging = document.getElementById('paging-up');
3742:     if (paging) {
3743:       listElements = paging.getElementsByTagName('a');
3744:       for (i = 0; i < listElements.length; i += 1) {
3745:         if (hasClass(listElements[i], 'previous-item')) {
3746:           listElements[i].onclick = previousClickItem;
3747:         }
3748:         if (hasClass(listElements[i], 'next-item')) {
3749:           listElements[i].onclick = nextClickItem;
3750:         }
3751:       }
3752:     }
3753: 
3754:     paging = document.getElementById('paging-down');
3755:     if (paging) {
3756:       listElements = paging.getElementsByTagName('a');
3757:       for (i = 0; i < listElements.length; i += 1) {
3758:         if (hasClass(listElements[i], 'previous-item')) {
3759:           listElements[i].onclick = previousClickItem;
3760:         }
3761:         if (hasClass(listElements[i], 'next-item')) {
3762:           listElements[i].onclick = nextClickItem;
3763:         }
3764:       }
3765:     }
3766:   }
3767: 
3768:   function updateItemButton() {
3769:     var i = 0, paging, listElements;
3770: 
3771:     paging = document.getElementById('paging-up');
3772:     if (paging) {
3773:       listElements = paging.getElementsByTagName('a');
3774:       for (i = 0; i < listElements.length; i += 1) {
3775:         if (hasClass(listElements[i], 'previous-item')) {
3776:           listElements[i].href = '?currentHash=' + currentHash
3777:                                + '&previous=' + currentItemHash;
3778:         }
3779:         if (hasClass(listElements[i], 'next-item')) {
3780:           listElements[i].href = '?currentHash=' + currentHash
3781:                                + '&next=' + currentItemHash;
3782: 
3783:         }
3784:       }
3785:     }
3786: 
3787:     paging = document.getElementById('paging-down');
3788:     if (paging) {
3789:       listElements = paging.getElementsByTagName('a');
3790:       for (i = 0; i < listElements.length; i += 1) {
3791:         if (hasClass(listElements[i], 'previous-item')) {
3792:           listElements[i].href = '?currentHash=' + currentHash
3793:                                + '&previous=' + currentItemHash;
3794:         }
3795:         if (hasClass(listElements[i], 'next-item')) {
3796:           listElements[i].href = '?currentHash=' + currentHash
3797:                                + '&next=' + currentItemHash;
3798: 
3799:         }
3800:       }
3801:     }
3802:   }
3803: 
3804:   function initUnread() {
3805:     var element = document.getElementById('nb-unread');
3806: 
3807:     currentUnread = parseInt(element.innerHTML, 10);
3808: 
3809:     title = document.title;
3810:     setNbUnread(currentUnread);
3811:   }
3812: 
3813:   function setNbUnread(nb) {
3814:     var element = document.getElementById('nb-unread');
3815: 
3816:     if (nb < 0) {
3817:       nb = 0;
3818:     }
3819: 
3820:     currentUnread = nb;
3821:     element.innerHTML = currentUnread;
3822: 
3823:     document.title = title + ' (' + currentUnread + ')';
3824:   }
3825: 
3826:   function initOptions() {
3827:     var elementIndex = document.getElementById('index');
3828: 
3829:     if (elementIndex.hasAttribute('data-view')) {
3830:       view = elementIndex.getAttribute('data-view');
3831:     }
3832:     if (elementIndex.hasAttribute('data-list-feeds')) {
3833:       listFeeds = elementIndex.getAttribute('data-list-feeds');
3834:     }
3835:     if (elementIndex.hasAttribute('data-filter')) {
3836:       filter = elementIndex.getAttribute('data-filter');
3837:     }
3838:     if (elementIndex.hasAttribute('data-order')) {
3839:       order = elementIndex.getAttribute('data-order');
3840:     }
3841:     if (elementIndex.hasAttribute('data-autoread-item')) {
3842:       autoreadItem = parseInt(elementIndex.getAttribute('data-autoread-item'), 10);
3843:       autoreadItem = (autoreadItem === 1)?true:false;
3844:     }
3845:     if (elementIndex.hasAttribute('data-autoread-page')) {
3846:       autoreadPage = parseInt(elementIndex.getAttribute('data-autoread-page'), 10);
3847:       autoreadPage = (autoreadPage === 1)?true:false;
3848:     }
3849:     if (elementIndex.hasAttribute('data-autohide')) {
3850:       autohide = parseInt(elementIndex.getAttribute('data-autohide'), 10);
3851:       autohide = (autohide === 1)?true:false;
3852:     }
3853:     if (elementIndex.hasAttribute('data-autofocus')) {
3854:       autofocus = parseInt(elementIndex.getAttribute('data-autofocus'), 10);
3855:       autofocus = (autofocus === 1)?true:false;
3856:     }
3857:     if (elementIndex.hasAttribute('data-autoupdate')) {
3858:       autoupdate = parseInt(elementIndex.getAttribute('data-autoupdate'), 10);
3859:       autoupdate = (autoupdate === 1)?true:false;
3860:     }
3861:     if (elementIndex.hasAttribute('data-by-page')) {
3862:       byPage = parseInt(elementIndex.getAttribute('data-by-page'), 10);
3863:     }
3864:     if (elementIndex.hasAttribute('data-shaarli')) {
3865:       shaarli = elementIndex.getAttribute('data-shaarli');
3866:     }
3867:     if (elementIndex.hasAttribute('data-redirector')) {
3868:       redirector = elementIndex.getAttribute('data-redirector');
3869:     }
3870:     if (elementIndex.hasAttribute('data-current-hash')) {
3871:       currentHash = elementIndex.getAttribute('data-current-hash');
3872:     }
3873:     if (elementIndex.hasAttribute('data-current-page')) {
3874:       currentPage = parseInt(elementIndex.getAttribute('data-current-page'), 10);
3875:     }
3876:     if (elementIndex.hasAttribute('data-nb-items')) {
3877:       currentNbItems = parseInt(elementIndex.getAttribute('data-nb-items'), 10);
3878:     }
3879: 
3880:     status = document.getElementById('status').innerHTML;
3881:   }
3882: 
3883:   function initKF() {
3884:     var listItems,
3885:         listLinkFolders = [],
3886:         listLinkItems = [];
3887: 
3888:     initOptions();
3889: 
3890:     listLinkFolders = getListLinkFolders();
3891:     listLinkItems = getListLinkItems();
3892:     if (!window.jQuery || (window.jQuery && !window.jQuery().collapse)) {
3893:       document.getElementById('menu-toggle'). onclick = collapseClick;
3894:       initCollapse(listLinkFolders);
3895:       initCollapse(listLinkItems);
3896:     }
3897:     initLinkFolders(listLinkFolders);
3898:     initLinkItems(listLinkItems);
3899: 
3900:     initListItemsHash();
3901:     initListItems();
3902:     initUnread();
3903: 
3904:     initItemButton();
3905:     initPageButton();
3906: 
3907:     initAnonyme();
3908: 
3909:     addEvent(window, 'keydown', checkKey);
3910:     addEvent(window, 'touchstart', checkMove);
3911: 
3912:     if (autoupdate) {
3913:       initUpdate();
3914:     }
3915: 
3916:     listItems = getListItems();
3917:     listItems.focus();
3918:   }
3919: 
3920:   //http://scottandrew.com/weblog/articles/cbs-events
3921:   function addEvent(obj, evType, fn, useCapture) {
3922:     if (obj.addEventListener) {
3923:       obj.addEventListener(evType, fn, useCapture);
3924:     } else {
3925:       if (obj.attachEvent) {
3926:         obj.attachEvent('on' + evType, fn);
3927:       } else {
3928:         window.alert('Handler could not be attached');
3929:       }
3930:     }
3931:   }
3932: 
3933:   function removeEvent(obj, evType, fn, useCapture) {
3934:     if (obj.removeEventListener) {
3935:       obj.removeEventListener(evType, fn, useCapture);
3936:     } else if (obj.detachEvent) {
3937:       obj.detachEvent("on"+evType, fn);
3938:     } else {
3939:       alert("Handler could not be removed");
3940:     }
3941:   }
3942: 
3943:   // when document is loaded init KrISS feed
3944:   if (document.getElementById && document.createTextNode) {
3945:     addEvent(window, 'load', initKF);
3946:   }
3947: 
3948:   window.checkKey = checkKey;
3949:   window.removeEvent = removeEvent;
3950:   window.addEvent = addEvent;
3951: })();    </script>
3952:     <?php } ?>
3953:   </body>
3954: </html>
3955: <?php
3956:     }
3957: }
3958: 
3959: class Feed
3960: {
3961:     public $dataFile = '';
3962: 
3963:     public $cacheDir = '';
3964: 
3965:     public $kfc;
3966: 
3967:     private $_data = array();
3968: 
3969:     public function __construct($dataFile, $cacheDir, $kfc)
3970:     {
3971:         $this->kfc = $kfc;
3972:         $this->dataFile = $dataFile;
3973:         $this->cacheDir = $cacheDir;
3974:     }
3975: 
3976:     public function getData()
3977:     {
3978:         return $this->_data;
3979:     }
3980: 
3981:     public function setData($data)
3982:     {
3983:         $this->_data = $data;
3984:     }
3985: 
3986:     public function loadData()
3987:     {
3988:         if (empty($this->_data)) {
3989:             if (file_exists($this->dataFile)) {
3990:                 $this->_data = unserialize(
3991:                     gzinflate(
3992:                         base64_decode(
3993:                             substr(
3994:                                 file_get_contents($this->dataFile),
3995:                                 strlen(PHPPREFIX),
3996:                                 -strlen(PHPSUFFIX)
3997:                                 )
3998:                             )
3999:                         )
4000:                     );
4001:                 return true;
4002:             } else {
4003:                 $this->_data['feeds'] = array(
4004:                     MyTool::smallHash('http://tontof.net/?rss') => array(
4005:                         'title' => 'Tontof',
4006:                         'foldersHash' => array(),
4007:                         'timeUpdate' => 'auto',
4008:                         'lastUpdate' => 0,
4009:                         'nbUnread' => 0,
4010:                         'nbAll' => 0,
4011:                         'htmlUrl' => 'http://tontof.net',
4012:                         'xmlUrl' => 'http://tontof.net/?rss',
4013:                         'description' => 'A simple and smart (or stupid) blog'));
4014:                 $this->_data['folders'] = array();
4015:                 $this->_data['items'] = array();
4016:                 $this->_data['newItems'] = array();
4017: 
4018:                 return false;
4019:             }
4020:         }
4021: 
4022:         // data already loaded
4023:         return true;
4024:     }
4025: 
4026:     public function writeData()
4027:     {
4028:         if (Session::isLogged() || (isset($_GET['cron']) && $_GET['cron'] === sha1($this->kfc->salt.$this->kfc->hash))) {
4029:             $write = @file_put_contents(
4030:                 $this->dataFile,
4031:                 PHPPREFIX
4032:                 . base64_encode(gzdeflate(serialize($this->_data)))
4033:                 . PHPSUFFIX
4034:                 );
4035:             if (!$write) {
4036:                 die("Can't write to " . $this->dataFile);
4037:             }
4038:         }
4039:     }
4040: 
4041:     public function getFeeds()
4042:     {
4043:         return $this->_data['feeds'];
4044:     }
4045: 
4046:     public function sortFeeds()
4047:     {
4048:         uasort(
4049:             $this->_data['feeds'],
4050:             'Feed::sortByTitle'
4051:             );
4052:     }
4053: 
4054:     public function getFeedsView()
4055:     {
4056:         $feedsView = array('all' => array('title' => 'All feeds', 'nbUnread' => 0, 'nbAll' => 0, 'feeds' => array()), 'folders' => array());
4057:        
4058:         foreach ($this->_data['feeds'] as $feedHash => $feed) {
4059:             if (isset($feed['error'])) {
4060:                 $feed['error'] = $this->getError($feed['error']);
4061:             }
4062:             $feedsView['all']['nbUnread'] += $feed['nbUnread'];
4063:             $feedsView['all']['nbAll'] += $feed['nbAll'];
4064:             if (empty($feed['foldersHash'])) {
4065:                 $feedsView['all']['feeds'][$feedHash] = $feed;
4066:             } else {
4067:                 foreach ($feed['foldersHash'] as $folderHash) {
4068:                     $folder = $this->getFolder($folderHash);
4069:                     if ($folder !== false) {
4070:                         if (!isset($feedsView['folders'][$folderHash]['title'])) {
4071:                             $feedsView['folders'][$folderHash]['title'] = $folder['title'];
4072:                             $feedsView['folders'][$folderHash]['isOpen'] = $folder['isOpen'];
4073:                             $feedsView['folders'][$folderHash]['nbUnread'] = 0;
4074:                             $feedsView['folders'][$folderHash]['nbAll'] = 0;
4075:                         }
4076:                         $feedsView['folders'][$folderHash]['feeds'][$feedHash] = $feed;
4077:                         $feedsView['folders'][$folderHash]['nbUnread'] += $feed['nbUnread'];
4078:                         $feedsView['folders'][$folderHash]['nbAll'] += $feed['nbAll'];
4079:                     }
4080:                 }
4081:             }
4082:         }
4083: 
4084:         return $feedsView;
4085:     }
4086: 
4087:     public function getFeed($feedHash)
4088:     {
4089:         if (isset($this->_data['feeds'][$feedHash])) {
4090:             $this->_data['feeds'][$feedHash]['xmlUrl'] = htmlspecialchars($this->_data['feeds'][$feedHash]['xmlUrl']);
4091:             $this->_data['feeds'][$feedHash]['htmlUrl'] = htmlspecialchars($this->_data['feeds'][$feedHash]['htmlUrl']);
4092:             return $this->_data['feeds'][$feedHash];
4093:         }
4094: 
4095:         return false;
4096:     }
4097: 
4098:     public function getFeedHtmlUrl($feedHash)
4099:     {
4100:         if (isset($this->_data['feeds'][$feedHash]['htmlUrl'])) {
4101:             return $this->_data['feeds'][$feedHash]['htmlUrl'];
4102:         }
4103: 
4104:         return false;
4105:     }
4106: 
4107:     public function getFeedTitle($feedHash)
4108:     {
4109:         if (isset($this->_data['feeds'][$feedHash]['title'])) {
4110:             return $this->_data['feeds'][$feedHash]['title'];
4111:         }
4112: 
4113:         return false;
4114:     }
4115: 
4116:     public function loadFeed($feedHash)
4117:     {
4118:         if (!isset($this->_data['feeds'][$feedHash]['items'])) {
4119:             $this->_data['feeds'][$feedHash]['items'] = array();
4120: 
4121:             if (file_exists($this->cacheDir.'/'.$feedHash.'.php')) {
4122:                 $items = unserialize(
4123:                     gzinflate(
4124:                         base64_decode(
4125:                             substr(
4126:                                 file_get_contents($this->cacheDir.'/'.$feedHash.'.php'),
4127:                                 strlen(PHPPREFIX),
4128:                                 -strlen(PHPSUFFIX)
4129:                                 )
4130:                             )
4131:                         )
4132:                     );
4133: 
4134:                 $this->_data['feeds'][$feedHash]['items'] = $items;
4135:             }
4136:         }
4137:     }
4138: 
4139:     public function editFeed(
4140:         $feedHash,
4141:         $title,
4142:         $description,
4143:         $foldersHash,
4144:         $timeUpdate)
4145:     {
4146:         if (isset($this->_data['feeds'][$feedHash])) {
4147:             if (!empty($title)) {
4148:                 $this->_data['feeds'][$feedHash]['title'] = $title;
4149:             }
4150:             if (!empty($description)) {
4151:                 $this->_data['feeds'][$feedHash]['description'] = $description;
4152:             }
4153:            
4154:             $this->_data['feeds'][$feedHash]['foldersHash'] = $foldersHash;
4155:             $this->_data['feeds'][$feedHash]['timeUpdate'] = 'auto';
4156:             if (!empty($timeUpdate)) {
4157:                 if ($timeUpdate == 'max') {
4158:                     $this->_data['feeds'][$feedHash]['timeUpdate'] = $timeUpdate;
4159:                 } else {
4160:                     $this->_data['feeds'][$feedHash]['timeUpdate'] = (int) $timeUpdate;
4161:                     $maxUpdate = $this->kfc->maxUpdate;
4162:                     if ($this->_data['feeds'][$feedHash]['timeUpdate'] < MIN_TIME_UPDATE
4163:                         || $this->_data['feeds'][$feedHash]['timeUpdate'] > $maxUpdate
4164:                     ) {
4165:                         $this->_data['feeds'][$feedHash]['timeUpdate'] = 'auto';
4166:                     }
4167:                 }
4168:             }
4169:         }
4170:     }
4171: 
4172:     public function removeFeed($feedHash)
4173:     {
4174:         if (isset($this->_data['feeds'][$feedHash])) {
4175:             unset($this->_data['feeds'][$feedHash]);
4176:             unlink($this->cacheDir. '/' .$feedHash.'.php' );
4177:             foreach (array_keys($this->_data['items']) as $itemHash) {
4178:                 if (substr($itemHash, 0, 6) === $feedHash) {
4179:                     unset($this->_data['items'][$itemHash]);
4180:                 }
4181:             }
4182:             foreach (array_keys($this->_data['newItems']) as $itemHash) {
4183:                 if (substr($itemHash, 0, 6) === $feedHash) {
4184:                     unset($this->_data['newItems'][$itemHash]);
4185:                 }
4186:             }
4187:         }
4188:     }
4189: 
4190:     public function writeFeed($feedHash, $feed)
4191:     {
4192:         if (Session::isLogged() || (isset($_GET['cron']) && $_GET['cron'] === sha1($this->kfc->salt.$this->kfc->hash))) {
4193:             if (!is_dir($this->cacheDir)) {
4194:                 if (!@mkdir($this->cacheDir, 0755)) {
4195:                     die("Can not create cache dir: ".$this->cacheDir);
4196:                 }
4197:                 @chmod($this->cacheDir, 0755);
4198:                 if (!is_file($this->cacheDir.'/.htaccess')) {
4199:                     if (!@file_put_contents(
4200:                             $this->cacheDir.'/.htaccess',
4201:                             "Allow from none\nDeny from all\n"
4202:                             )) {
4203:                         die("Can not protect cache dir: ".$this->cacheDir);
4204:                     }
4205:                 }
4206:             }
4207: 
4208:             $write = @file_put_contents(
4209:                 $this->cacheDir.'/'.$feedHash.'.php',
4210:                 PHPPREFIX
4211:                 . base64_encode(gzdeflate(serialize($feed)))
4212:                 . PHPSUFFIX
4213:                 );
4214: 
4215:             if (!$write) {
4216:                 die("Can't write to " . $this->cacheDir.'/'.$feedHash.'.php');
4217:             }
4218:         }
4219:     }
4220: 
4221:     public function orderFeedsForUpdate($feedsHash)
4222:     {
4223:         $newFeedsHash = array();
4224:         foreach(array_keys($this->_data['items']) as $itemHash) {
4225:             $feedHash = substr($itemHash, 0, 6);
4226:             if (in_array($feedHash, $feedsHash) and !in_array($feedHash, $newFeedsHash)) {
4227:                 $newFeedsHash[] = $feedHash;
4228:             }
4229:         }
4230:         foreach($feedsHash as $feedHash) {
4231:             if (!in_array($feedHash, $newFeedsHash)) {
4232:                 $newFeedsHash[] = $feedHash;
4233:             }
4234:         }
4235: 
4236:         return $newFeedsHash;
4237:     }
4238: 
4239:     public function getFeedsHashFromFolderHash($folderHash)
4240:     {
4241:         $list = array();
4242:         $folders = $this->getFolders();
4243: 
4244:         if (isset($folders[$folderHash])) {
4245:             foreach ($this->_data['feeds'] as $feedHash => $feed) {
4246:                 if (in_array($folderHash, $feed['foldersHash'])) {
4247:                     $list[] = $feedHash;
4248:                 }
4249:             }
4250:         }
4251: 
4252:         return $list;
4253:     }
4254: 
4255:     public function getFolders()
4256:     {
4257:         return $this->_data['folders'];
4258:     }
4259: 
4260:     public function getFolder($folderHash)
4261:     {
4262:         if (isset($this->_data['folders'][$folderHash])) {
4263:             return $this->_data['folders'][$folderHash];
4264:         }
4265: 
4266:         return false;
4267:     }
4268: 
4269:     public function addFolder($folderTitle, $newFolderHash = '')
4270:     {
4271:         if (empty($newFolderHash)) {
4272:             $newFolderHash = MyTool::smallHash($newFolderTitle);
4273:         }
4274:         $this->_data['folders'][$newFolderHash] = array(
4275:             'title' => $folderTitle,
4276:             'isOpen' => 1
4277:         );
4278:     }
4279: 
4280:     public function renameFolder($oldFolderHash, $newFolderTitle)
4281:     {
4282:         $newFolderHash = '';
4283:         if (!empty($newFolderTitle)) {
4284:             $newFolderHash = MyTool::smallHash($newFolderTitle);
4285:             $this->addFolder($newFolderTitle, $newFolderHash);
4286:             $this->_data['folders'][$newFolderHash]['isOpen'] = $this->_data['folders'][$oldFolderHash]['isOpen'];
4287:         }
4288:         unset($this->_data['folders'][$oldFolderHash]);
4289: 
4290:         foreach ($this->_data['feeds'] as $feedHash => $feed) {
4291:             $i = array_search($oldFolderHash, $feed['foldersHash']);
4292:             if ($i !== false) {
4293:                 unset($this->_data['feeds'][$feedHash]['foldersHash'][$i]);
4294:                 if (!empty($newFolderTitle)) {
4295:                     $this->_data['feeds'][$feedHash]['foldersHash'][] = $newFolderHash;
4296:                 }
4297:             }
4298:         }
4299:     }
4300: 
4301:     public function toggleFolder($hash)
4302:     {
4303:         if ($this->_data['folders'][$hash]) {
4304:             $isOpen = $this->_data['folders'][$hash]['isOpen'];
4305:             if ($isOpen) {
4306:                 $this->_data['folders'][$hash]['isOpen'] = 0;
4307:             } else {
4308:                 $this->_data['folders'][$hash]['isOpen'] = 1;
4309:             }
4310:         }
4311: 
4312:         return true;
4313:     }
4314: 
4315:     public function getFolderTitle($folderHash)
4316:     {
4317:         if (isset($this->_data['folders'][$folderHash])) {
4318:             return $this->_data['folders'][$folderHash]['title'];
4319:         }
4320: 
4321:         return false;
4322:     }
4323: 
4324:     public function getItems($hash = 'all', $filter = 'all')
4325:     {
4326:         if (empty($hash) or $hash == 'all' and $filter == 'all') {
4327:             return $this->_data['items']+$this->_data['newItems'];
4328:         }
4329: 
4330:         if (empty($hash) or $hash == 'all' and $filter == 'old') {
4331:             return $this->_data['items'];
4332:         }
4333: 
4334:         if (empty($hash) or $hash == 'all' and $filter == 'new') {
4335:             return $this->_data['newItems'];
4336:         }
4337:        
4338:         $list = array();
4339:         $isRead = 1;
4340:         if ($filter === 'unread') {
4341:             $isRead = 0;
4342:         }
4343: 
4344:         if (empty($hash) || $hash == 'all') {
4345:             // all items
4346:             foreach ($this->_data['items'] as $itemHash => $item) {
4347:                 if ($item[1] === $isRead) {
4348:                     $list[$itemHash] = $item;
4349:                 }
4350:             }
4351:             foreach ($this->_data['newItems'] as $itemHash => $item) {
4352:                 if ($item[1] === $isRead) {
4353:                     $list[$itemHash] = $item;
4354:                 }
4355:             }
4356:         } else {
4357:             if (strlen($hash) === 12) {
4358:                 // an item
4359:                 if (isset($this->_data['items'][$hash])) {
4360:                     $list[$hash] = $this->_data['items'][$hash];
4361:                 } else if (isset($this->_data['newItems'][$hash])) {
4362:                     $list[$hash] = $this->_data['newItems'][$hash];
4363:                 }
4364:             } else {
4365:                 $feedsHash = array();
4366:                 if (isset($this->_data['feeds'][$hash])) {
4367:                     // a feed
4368:                     $feedsHash[] = $hash;
4369:                 } else if (isset($this->_data['folders'][$hash])) {
4370:                     // a folder
4371:                     foreach ($this->_data['feeds'] as $feedHash => $feed) {
4372:                         if (in_array($hash, $feed['foldersHash'])) {
4373:                             $feedsHash[] = $feedHash;
4374:                         }
4375:                     }
4376:                 }
4377: 
4378:                 // get items from a list of feeds
4379:                 if (!empty($feedsHash)) {
4380:                     $flipFeedsHash = array_flip($feedsHash);
4381:                     foreach ($this->_data['items'] as $itemHash => $item) {
4382:                         if (isset($flipFeedsHash[substr($itemHash, 0, 6)])) {
4383:                             if ($filter === 'all' or $item[1] === $isRead) {
4384:                                 $list[$itemHash] = $item;
4385:                             }
4386:                         }
4387:                     }
4388:                     foreach ($this->_data['newItems'] as $itemHash => $item) {
4389:                         if (isset($flipFeedsHash[substr($itemHash, 0, 6)])) {
4390:                             if ($filter === 'all' or $item[1] === $isRead) {
4391:                                 $list[$itemHash] = $item;
4392:                             }
4393:                         }
4394:                     }
4395:                 }
4396:             }
4397:         }
4398: 
4399:         return $list;
4400:     }
4401: 
4402:     public function loadItem($itemHash, $keep)
4403:     {
4404:         $feedHash = substr($itemHash, 0, 6);
4405:         $item = array();
4406:         if (isset($this->_data['feeds'][$feedHash]['items'])) {
4407:             if (isset($this->_data['feeds'][$feedHash]['items'][$itemHash])) {
4408:                 $item = $this->_data['feeds'][$feedHash]['items'][$itemHash];
4409:             }
4410:         } else {
4411:             $this->loadFeed($feedHash);
4412: 
4413:             return $this->loadItem($itemHash, $keep);
4414:         }
4415: 
4416:         if (!$keep) {
4417:             unset($this->_data['feeds'][$feedHash]['items']);
4418:         }
4419: 
4420:         return $item;
4421:     }
4422: 
4423:     public function getItem($itemHash, $keep = true)
4424:     {
4425:         $item = $this->loadItem($itemHash, $keep);
4426: 
4427:         if (!empty($item)) {
4428:             $item['itemHash'] = $itemHash;
4429:             $time = $item['time'];
4430:             if (strftime('%Y%m%d', $time) == strftime('%Y%m%d', time())) {
4431:                 // Today
4432:                 $item['time'] = array('list' => utf8_encode(strftime('%R %p', $time)), 'expanded' => utf8_encode(strftime('%A %d %B %Y - %H:%M', $time)));
4433:             } else {
4434:                 $item['time'] = array('list' => utf8_encode(strftime('%b %e, %Y', $time)), 'expanded' => utf8_encode(strftime('%A %d %B %Y - %H:%M', $time)));                
4435:             }
4436:             if (isset($this->_data['items'][$itemHash])) {
4437:                 $item['read'] = $this->_data['items'][$itemHash][1];
4438:             } else if (isset($this->_data['newItems'][$itemHash])) {
4439:                 $item['read'] = $this->_data['newItems'][$itemHash][1];
4440: 
4441:                 $currentNewItemIndex = array_search($itemHash, array_keys($this->_data['newItems']));
4442:                 if (isset($_SESSION['lastNewItemsHash'])) {
4443:                     $lastNewItemIndex = array_search($_SESSION['lastNewItemsHash'], array_keys($this->_data['newItems']));
4444: 
4445:                     if ($lastNewItemIndex < $currentNewItemIndex) {
4446:                         $_SESSION['lastNewItemsHash'] = $itemHash;
4447:                     }
4448:                 } else {
4449:                     $_SESSION['lastNewItemsHash'] = $itemHash;
4450:                 }
4451:             } else {
4452:                 // FIX: data may be corrupted
4453:                 return false;
4454:             }
4455:            
4456:             $item['author'] = htmlspecialchars(htmlspecialchars_decode(strip_tags($item['author']), ENT_QUOTES), ENT_NOQUOTES);
4457:             $item['title'] = htmlspecialchars(htmlspecialchars_decode(strip_tags($item['title']), ENT_QUOTES), ENT_NOQUOTES);
4458:             $item['link'] = htmlspecialchars($item['link']);
4459:             $item['via'] = htmlspecialchars($item['via']);
4460:            
4461:             return $item;
4462:         }
4463: 
4464:         return false;
4465:     }
4466: 
4467:     public function updateItems()
4468:     {
4469:         if (isset($this->_data['needSort']) or (isset($this->_data['order']) and $this->_data['order'] != $this->kfc->order)) {
4470:             unset($this->_data['needSort']);
4471: 
4472:             $this->_data['items'] = $this->_data['items']+$this->_data['newItems'];
4473:             $this->_data['newItems'] = array();
4474:             // sort items
4475:             if ($this->kfc->order === 'newerFirst') {
4476:                 arsort($this->_data['items']);
4477:             } else {
4478:                 asort($this->_data['items']);
4479:             }
4480:             $this->_data['order'] = $this->kfc->order;
4481: 
4482:             return true;
4483:         }
4484: 
4485:         return false;
4486:     }
4487: 
4488:     public function formatChannel($channel)
4489:     {
4490:         $newChannel = array();
4491: 
4492:         // list of format for each info in order of importance
4493:         $formats = array('title' => array('title'),
4494:                          'description' => array('description', 'subtitle'),
4495:                          'htmlUrl' => array('link', 'id', 'guid'));
4496: 
4497:         foreach ($formats as $format => $list) {
4498:             $newChannel[$format] = '';
4499:             $len = count($list);
4500:             for ($i = 0; $i < $len; $i++) {
4501:                 if ($channel->hasChildNodes()) {
4502:                     $child = $channel->childNodes;
4503:                     for ($j = 0, $lenChannel = $child->length;
4504:                          $j<$lenChannel;
4505:                          $j++) {
4506:                         if (isset($child->item($j)->tagName)
4507:                             && $child->item($j)->tagName == $list[$i]
4508:                         ) {
4509:                             $newChannel[$format]
4510:                                 = $child->item($j)->textContent;
4511:                         }
4512:                     }
4513:                 }
4514:             }
4515:         }
4516: 
4517:         return $newChannel;
4518:     }
4519: 
4520:     public function getChannelFromXml($xml)
4521:     {
4522:         $channel = array();
4523: 
4524:         // find feed type RSS, Atom
4525:         $feed = $xml->getElementsByTagName('channel');
4526:         if ($feed->item(0)) {
4527:             // RSS/rdf:RDF feed
4528:             $channel = $feed->item(0);
4529:         } else {
4530:             $feed = $xml->getElementsByTagName('feed');
4531:             if ($feed->item(0)) {
4532:                 // Atom feed
4533:                 $channel = $feed->item(0);
4534:             } else {
4535:                 // unknown feed
4536:             }
4537:         }
4538: 
4539:         if (!empty($channel)) {
4540:             $channel = $this->formatChannel($channel);
4541:         }
4542: 
4543:         return $channel;
4544:     }
4545: 
4546:     public function formatItems($items, $formats)
4547:     {
4548:         $newItems = array();
4549: 
4550:         foreach ($items as $item) {
4551:             $tmpItem = array();
4552:             foreach ($formats as $format => $list) {
4553:                 $tmpItem[$format] = '';
4554:                 $len = count($list);
4555:                 for ($i = 0; $i < $len; $i++) {
4556:                     if (is_array($list[$i])) {
4557:                         $tag = $item->getElementsByTagNameNS(
4558:                             $list[$i][0],
4559:                             $list[$i][1]
4560:                         );
4561:                     } else {
4562:                         $tag = $item->getElementsByTagName($list[$i]);
4563:                         // wrong detection : e.g. media:content for content
4564:                         if ($tag->length != 0) {
4565:                             for ($j = $tag->length; --$j >= 0;) {
4566:                                 $elt = $tag->item($j);
4567:                                 if ($tag->item($j)->tagName != $list[$i]) {
4568:                                     $elt->parentNode->removeChild($elt);
4569:                                 }
4570:                             }
4571:                         }
4572:                     }
4573:                     if ($tag->length != 0) {
4574:                         // we find a correspondence for the current format
4575:                         // select first item (item(0)), (may not work)
4576:                         // stop to search for another one
4577:                         if ($format == 'link') {
4578:                             $tmpItem[$format] = '';
4579:                             for ($j = 0; $j < $tag->length; $j++) {
4580:                                 if ($tag->item($j)->hasAttribute('rel') && $tag->item($j)->getAttribute('rel') == 'alternate') {
4581:                                     $tmpItem[$format]
4582:                                         = $tag->item($j)->getAttribute('href');
4583:                                     $j = $tag->length;
4584:                                 }
4585:                             }
4586:                             if ($tmpItem[$format] == '') {
4587:                                 $tmpItem[$format]
4588:                                     = $tag->item(0)->getAttribute('href');
4589:                             }
4590:                         }
4591:                         if (empty($tmpItem[$format])) {
4592:                             $tmpItem[$format] = $tag->item(0)->textContent;
4593:                         }
4594:                         $i = $len;
4595:                     }
4596:                 }
4597:             }
4598:             if (!empty($tmpItem['link'])) {
4599:                 $hashUrl = MyTool::smallHash($tmpItem['link']);
4600:                 $newItems[$hashUrl] = array();
4601:                 $newItems[$hashUrl]['title'] = $tmpItem['title'];
4602:                 $newItems[$hashUrl]['time']  = strtotime($tmpItem['time'])
4603:                     ? strtotime($tmpItem['time'])
4604:                     : time();
4605:                 if (MyTool::isUrl($tmpItem['via'])
4606:                     && $tmpItem['via'] != $tmpItem['link']) {
4607:                     $newItems[$hashUrl]['via'] = $tmpItem['via'];
4608:                 } else {
4609:                     $newItems[$hashUrl]['via'] = '';
4610:                 }
4611:                 $newItems[$hashUrl]['link'] = $tmpItem['link'];
4612:                 $newItems[$hashUrl]['author'] = $tmpItem['author'];
4613:                 mb_internal_encoding("UTF-8");
4614:                 $newItems[$hashUrl]['description'] = mb_substr(
4615:                     strip_tags($tmpItem['description']), 0, 500
4616:                 );
4617:                 $newItems[$hashUrl]['content'] = $tmpItem['content'];
4618:             }
4619:         }
4620: 
4621:         return $newItems;
4622:     }
4623: 
4624:     public function getItemsFromXml ($xml)
4625:     {
4626:         $items = array();
4627: 
4628:         // find feed type RSS, Atom
4629:         $feed = $xml->getElementsByTagName('channel');
4630:         if ($feed->item(0)) {
4631:             // RSS/rdf:RDF feed
4632:             $feed = $xml->getElementsByTagName('item');
4633:             $len = $feed->length;
4634:             for ($i = 0; $i < $len; $i++) {
4635:                 $items[$i] = $feed->item($i);
4636:             }
4637:             $feed = $xml->getElementsByTagName('rss');
4638:             if (!$feed->item(0)) {
4639:                 $feed = $xml->getElementsByTagNameNS(
4640:                     "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
4641:                     'RDF'
4642:                 );
4643:             }
4644:         } else {
4645:             $feed = $xml->getElementsByTagName('feed');
4646:             if ($feed->item(0)) {
4647:                 // Atom feed
4648:                 $feed = $xml->getElementsByTagName('entry');
4649:                 $len = $feed->length;
4650:                 for ($i = 0; $i < $len; $i++) {
4651:                     $items[$i] = $feed->item($i);
4652:                 }
4653:                 $feed = $xml->getElementsByTagName('feed');
4654:             }
4655:         }
4656: 
4657:         // list of format for each info in order of importance
4658:         $formats = array(
4659:             'author'      => array('author', 'creator', 'dc:author',
4660:                                    'dc:creator'),
4661:             'content'     => array('content:encoded', 'content', 'description',
4662:                                'summary', 'subtitle'),
4663:             'description' => array('description', 'summary', 'subtitle',
4664:                                    'content', 'content:encoded'),
4665:             'via'        => array('guid', 'id'),
4666:             'link'        => array('feedburner:origLink', 'link', 'guid', 'id'),
4667:             'time'        => array('pubDate', 'updated', 'lastBuildDate',
4668:                                    'published', 'dc:date', 'date'),
4669:             'title'       => array('title'));
4670: 
4671:         if ($feed->item(0)) {
4672:             $formats = $this->formatRDF($formats, $feed->item(0));
4673:         }
4674: 
4675:         return $this->formatItems($items, $formats);
4676:     }
4677: 
4678:     public function getAttributeNS ($feed, $name)
4679:     {
4680:         $res = '';
4681:         if ($feed->nodeName === $name) {
4682:             $ns = explode(':', $name);
4683:             $res = $feed->getAttribute('xmlns:'.$ns[0]);
4684:         } else {
4685:             if ($feed->hasChildNodes()) {
4686:                 foreach ($feed->childNodes as $childNode) {
4687:                     if ($res === '') {
4688:                         $res = $this->getAttributeNS($childNode, $name);
4689:                     } else {
4690:                         break;
4691:                     }
4692:                 }
4693:             }
4694:         }
4695: 
4696:         return $res;
4697:     }
4698: 
4699:     public function formatRDF($formats, $feed)
4700:     {
4701:         foreach ($formats as $format => $list) {
4702:             for ($i = 0, $len = count($list); $i < $len; $i++) {
4703:                 $name = explode(':', $list[$i]);
4704:                 if (count($name)>1) {
4705:                     $res = $feed->getAttribute('xmlns:'.$name[0]);
4706:                     if (!empty($res)) {
4707:                         $ns = $res;
4708:                     } else {
4709:                         $ns = $this->getAttributeNS($feed, $list[$i]);
4710:                     }
4711:                     $formats[$format][$i] = array($ns, $name[1]);
4712:                 }
4713:             }
4714:         }
4715: 
4716:         return $formats;
4717:     }
4718: 
4719:     public function loadUrl($url, $opts = array()){
4720:         $ch = curl_init($url);
4721:         if (!empty($opts)) {
4722:             curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $opts['http']['timeout']);
4723:             curl_setopt($ch, CURLOPT_TIMEOUT, $opts['http']['timeout']);
4724:             curl_setopt($ch, CURLOPT_USERAGENT, $opts['http']['user_agent']);
4725:         }
4726:         curl_setopt($ch, CURLOPT_ENCODING, true);
4727:         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
4728:         curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
4729:         curl_setopt($ch, CURLOPT_URL, $url);
4730: 
4731:         $output = $this->curl_exec_follow($ch);
4732: 
4733:         curl_close($ch);
4734: 
4735:         return $output;
4736:     }
4737:  
4738:     public function curl_exec_follow(&$ch, $redirects = 20, $curloptHeader = false) {
4739:         if ((!ini_get('open_basedir') && !ini_get('safe_mode')) || $redirects < 1) {
4740:             curl_setopt($ch, CURLOPT_HEADER, $curloptHeader);
4741:             curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $redirects > 0);
4742:             curl_setopt($ch, CURLOPT_MAXREDIRS, $redirects);
4743:             return curl_exec($ch);
4744:         } else {
4745:             curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
4746:             curl_setopt($ch, CURLOPT_HEADER, true);
4747:             curl_setopt($ch, CURLOPT_FORBID_REUSE, false);
4748: 
4749:             do {
4750:                 $data = curl_exec($ch);
4751:                 if (curl_errno($ch))
4752:                     break;
4753:                 $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
4754:                 // 301 Moved Permanently
4755:                 // 302 Found
4756:                 // 303 See Other
4757:                 // 307 Temporary Redirect
4758:                 if ($code != 301 && $code != 302 && $code!=303 && $code!=307)
4759:                     break;
4760:                 $header_start = strpos($data, "\r\n")+2;
4761:                 $headers = substr($data, $header_start, strpos($data, "\r\n\r\n", $header_start)+2-$header_start);
4762:                 if (!preg_match("!\r\n(?:Location|location|URI): *(.*?) *\r\n!", $headers, $matches))
4763:                     break;
4764:                 curl_setopt($ch, CURLOPT_URL, $matches[1]);
4765:             } while (--$redirects);
4766:             if (!$redirects)
4767:                 trigger_error('Too many redirects. When following redirects, libcurl hit the maximum amount.', E_USER_WARNING);
4768:             if (!$curloptHeader)
4769:                 $data = substr($data, strpos($data, "\r\n\r\n")+4);
4770: 
4771:             return $data;
4772:         }
4773:     }
4774: 
4775:     public function loadXml($xmlUrl)
4776:     {
4777:         // hide warning/error
4778:         set_error_handler(array('MyTool', 'silence_errors'));
4779: 
4780:         // set user agent
4781:         // http://php.net/manual/en/function.libxml-set-streams-context.php
4782:         $opts = array(
4783:             'http' => array(
4784:                 'timeout' => 4,
4785:                 'user_agent' => 'KrISS feed agent '.$this->kfc->version.' by Tontof.net http://github.com/tontof/kriss_feed',
4786:                 )
4787:             );
4788:         $document = new DOMDocument();
4789: 
4790:         if (in_array('curl', get_loaded_extensions())) {
4791:             $output = $this->loadUrl($xmlUrl, $opts);
4792:             $document->loadXML($output);
4793:         } else {
4794:             // try using libxml
4795:             $context = stream_context_create($opts);
4796:             libxml_set_streams_context($context);
4797: 
4798:             // request a file through HTTP
4799:             $document->load($xmlUrl);
4800:         }
4801:         // show back warning/error
4802:         restore_error_handler();
4803: 
4804:         return $document;
4805:     }
4806: 
4807:     public function addChannel($xmlUrl)
4808:     {
4809:         $feedHash = MyTool::smallHash($xmlUrl);
4810:         if (!isset($this->_data['feeds'][$feedHash])) {
4811:             $xml = $this->loadXml($xmlUrl);
4812: 
4813:             if (!$xml) {
4814:                 return false;
4815:             } else {
4816:                 $channel = $this->getChannelFromXml($xml);
4817:                 $items = $this->getItemsFromXml($xml);
4818:                 if (count($items) == 0) {
4819:                     return false;
4820:                 }
4821:                 foreach (array_keys($items) as $itemHash) {
4822:                     if (empty($items[$itemHash]['via'])) {
4823:                         $items[$itemHash]['via'] = $channel['htmlUrl'];
4824:                     }
4825:                     if (empty($items[$itemHash]['author'])) {
4826:                         $items[$itemHash]['author'] = $channel['title'];
4827:                     } else {
4828:                         $items[$itemHash]['author']
4829:                             = $channel['title'] . ' ('
4830:                             . $items[$itemHash]['author'] . ')';
4831:                     }
4832:                     $items[$itemHash]['xmlUrl'] = $xmlUrl;
4833: 
4834:                     $this->_data['newItems'][$feedHash . $itemHash] = array(
4835:                         $items[$itemHash]['time'],
4836:                         0
4837:                     );
4838:                     $items[$feedHash . $itemHash] = $items[$itemHash];
4839:                     unset($items[$itemHash]);
4840:                 }
4841: 
4842:                 $channel['xmlUrl'] = $xmlUrl;
4843:                 $channel['foldersHash'] = array();
4844:                 $channel['nbUnread'] = count($items);
4845:                 $channel['nbAll'] = count($items);
4846:                 $channel['timeUpdate'] = 'auto';
4847:                 $channel['lastUpdate'] = time();
4848: 
4849:                 $this->_data['feeds'][$feedHash] = $channel;
4850:                 $this->_data['needSort'] = true;
4851: 
4852:                 $this->writeFeed($feedHash, $items);
4853: 
4854:                 return true;
4855:             }
4856:         }
4857: 
4858:         return false;
4859:     }
4860: 
4861:     public function getTimeUpdate($feed)
4862:     {
4863:         $max = $feed['timeUpdate'];
4864: 
4865:         if ($max == 'auto') {
4866:             $max = $this->kfc->maxUpdate;
4867:         } elseif ($max == 'max') {
4868:             $max = $this->kfc->maxUpdate;
4869:         } elseif ((int) $max < MIN_TIME_UPDATE
4870:                   || (int) $max > $this->kfc->maxUpdate) {
4871:             $max = $this->kfc->maxUpdate;
4872:         }
4873: 
4874:         return (int) $max;
4875:     }
4876: 
4877:     public function needUpdate($feed)
4878:     {
4879:         $diff = (int) (time()-$feed['lastUpdate']);
4880:         if ($diff > $this->getTimeUpdate($feed) * 60) {
4881:             return true;
4882:         }
4883: 
4884:         return false;
4885:     }
4886: 
4887:     public static function getError($error)
4888:     {
4889:         switch ($error) {
4890:         case ERROR_NO_XML:
4891:             return 'Feed is not in XML format';
4892:             break;
4893:         case ERROR_ITEMS_MISSED:
4894:             return 'Items may have been missed since last update';
4895:             break;
4896:         case ERROR_LAST_UPDATE:
4897:         case ERROR_UNKNOWN:
4898:             return 'Problem with the last update';
4899:             break;
4900:         default:
4901:             return 'unknown error';
4902:             break;
4903:         }
4904:     }
4905: 
4906:     public function updateChannel($feedHash)
4907:     {
4908:         $error = '';
4909:         $newItems = array();
4910: 
4911:         if (!isset($this->_data['feeds'][$feedHash])) {
4912:             return array(
4913:                 'error' => $error,
4914:                 'newItems' => $newItems
4915:                 );
4916:         }
4917: 
4918:         unset($this->_data['feeds'][$feedHash]['error']);
4919:         $xmlUrl = $this->_data['feeds'][$feedHash]['xmlUrl'];
4920:         $xml = $this->loadXml($xmlUrl);
4921: 
4922:         if (!$xml) {
4923:             if (file_exists($this->cacheDir.'/'.$feedHash.'.php')) {
4924:                 $error = ERROR_LAST_UPDATE;
4925:             } else {
4926:                 $error = ERROR_NO_XML;
4927:             }
4928:         } else {
4929:             // if feed description is empty try to update description
4930:             // (after opml import, description is often empty)
4931:             if (empty($this->_data['feeds'][$feedHash]['description'])) {
4932:                 $channel = $this->getChannelFromXml($xml);
4933:                 if (isset($channel['description'])) {
4934:                     $this->_data['feeds'][$feedHash]['description']
4935:                         = $channel['description'];
4936:                 }
4937:                 // Check description only the first time description is empty
4938:                 if (empty($this->_data['feeds'][$feedHash]['description'])) {
4939:                     $this->_data['feeds'][$feedHash]['description'] = ' ';
4940:                 }
4941:             }
4942: 
4943:             $this->loadFeed($feedHash);
4944:             $oldItems = $this->_data['feeds'][$feedHash]['items'];
4945: 
4946:             $rssItems = $this->getItemsFromXml($xml);
4947:             $rssItems = array_slice($rssItems, 0, $this->kfc->maxItems, true);
4948:             $rssItemsHash = array_keys($rssItems);
4949: 
4950:             if (count($rssItemsHash) !== 0) {
4951: 
4952:                 // Look for new items
4953:                 foreach ($rssItemsHash as $itemHash) {
4954:                     // itemHash is smallHash of link. To compare to item
4955:                     // hashes into data, we need to concatenate to feedHash.
4956:                     if (!isset($oldItems[$feedHash.$itemHash])) {
4957:                         if (empty($rssItems[$itemHash]['via'])) {
4958:                             $rssItems[$itemHash]['via']
4959:                                 = $this->_data['feeds'][$feedHash]['htmlUrl'];
4960:                         }
4961:                         if (empty($rssItems[$itemHash]['author'])) {
4962:                             $rssItems[$itemHash]['author']
4963:                                 = $this->_data['feeds'][$feedHash]['title'];
4964:                         } else {
4965:                             $rssItems[$itemHash]['author']
4966:                                 = $this->_data['feeds'][$feedHash]['title'] . ' ('
4967:                                 . $rssItems[$itemHash]['author'] . ')';
4968:                         }
4969:                         $rssItems[$itemHash]['xmlUrl'] = $xmlUrl;
4970:                         $newItems[$feedHash . $itemHash] = $rssItems[$itemHash];
4971:                     }
4972:                 }
4973:                 $newItemsHash = array_keys($newItems);
4974:                 $this->_data['feeds'][$feedHash]['items']
4975:                     = $newItems+$oldItems;
4976: 
4977:                 // Check if items may have been missed
4978:                 if (count($oldItems) !== 0 and count($rssItemsHash) === count($newItemsHash)) {
4979:                     $error = ERROR_ITEMS_MISSED;
4980:                 }
4981: 
4982:                 // Remove useless items
4983:                 foreach ($this->getItems($feedHash) as $itemHash => $item) {
4984:                     $itemRssHash = substr($itemHash, 6, 6);
4985:                     // Remove from cache already read items not any more in the feed
4986:                     if (!isset($rssItems[$itemRssHash]) and $item[1] == 1) {
4987:                         unset($this->_data['feeds'][$feedHash]['items'][$itemHash]);
4988:                     }
4989:                
4990:                     if (!isset($this->_data['feeds'][$feedHash]['items'][$itemHash])) {
4991:                         // Remove items not any more in the cache
4992:                         unset($this->_data['items'][$itemHash]);
4993:                         unset($this->_data['newItems'][$itemHash]);
4994:                     }
4995:                 }
4996: 
4997:                 // Check if quota exceeded
4998:                 $nbAll = count($this->_data['feeds'][$feedHash]['items']);
4999:                 if ($nbAll > $this->kfc->maxItems) {
5000:                     $this->_data['feeds'][$feedHash]['items']
5001:                         = array_slice(
5002:                             $this->_data['feeds'][$feedHash]['items'],
5003:                             0,
5004:                             $this->kfc->maxItems, true
5005:                             );
5006:                     $nbAll = $this->kfc->maxItems;
5007:                 }
5008: 
5009:                 // Update items list and feed information (nbUnread, nbAll)
5010:                 $this->_data['feeds'][$feedHash]['nbAll'] = $nbAll;
5011:                 $nbUnread = 0;
5012:                 foreach ($this->_data['feeds'][$feedHash]['items'] as $itemHash => $item) {
5013:                     if (isset($this->_data['items'][$itemHash])) {
5014:                         if ($this->_data['items'][$itemHash][1] === 0) {
5015:                             $nbUnread++;
5016:                         }
5017:                     } else if (isset($this->_data['newItems'][$itemHash])) {
5018:                         if ($this->_data['newItems'][$itemHash][1] === 0) {
5019:                             $nbUnread++;
5020:                         }
5021:                     } else {
5022:                         // TODO: Is appended at the end ??
5023:                         $this->_data['newItems'][$itemHash] = array(
5024:                             $item['time'],
5025:                             0                        
5026:                             );
5027:                         $nbUnread++;
5028:                     }
5029:                 }
5030:                 $this->_data['feeds'][$feedHash]['nbUnread'] = $nbUnread;
5031:             } else {
5032:                 $error = ERROR_UNKNOWN;
5033:             }
5034:         }
5035: 
5036:         // update feed information
5037:         $this->_data['feeds'][$feedHash]['lastUpdate'] = time();
5038:         if (!empty($error)) {
5039:             $this->_data['feeds'][$feedHash]['error'] = $error;
5040:         }
5041: 
5042:         if (empty($newItems)) {
5043:             unset($this->_data['feeds'][$feedHash]['items']);
5044:             $this->writeData();
5045:         } else {
5046:             $this->writeFeed($feedHash, $this->_data['feeds'][$feedHash]['items']);
5047:             unset($this->_data['feeds'][$feedHash]['items']);
5048:             $this->_data['needSort'] = true;
5049: 
5050:             if (isset($_SESSION['lastNewItemsHash'])) {
5051:                 $lastNewItemIndex = array_search($_SESSION['lastNewItemsHash'], array_keys($this->_data['newItems']));
5052:                 $this->_data['items'] = $this->_data['items']+array_slice($this->_data['newItems'], 0, $lastNewItemIndex + 1, true);
5053:                 $this->_data['newItems'] = array_slice($this->_data['newItems'], $lastNewItemIndex + 1, count($this->_data['newItems']) - $lastNewItemIndex, true);
5054:                 unset($_SESSION['lastNewItemsHash']);
5055:             }
5056: 
5057:             if ($this->kfc->order === 'newerFirst') {
5058:                 arsort($this->_data['newItems']);
5059:             } else {
5060:                 asort($this->_data['newItems']);
5061:             }
5062:             $this->_data['order'] = $this->kfc->order;
5063: 
5064:             $this->writeData();
5065:         }
5066: 
5067:         return array(
5068:             'error' => $error,
5069:             'newItems' => $newItems
5070:             );
5071:     }
5072: 
5073:     public function updateFeedsHash($feedsHash, $force, $format = '')
5074:     {
5075:         $i = 0;
5076: 
5077:         $feedsHash = $this->orderFeedsForUpdate($feedsHash);
5078: 
5079:         ob_end_flush();
5080:         if (ob_get_level() == 0) ob_start();
5081:         $start = microtime(true);
5082:         foreach ($feedsHash as $feedHash) {
5083:             $i++;
5084:             $feed = $this->getFeed($feedHash);
5085:             $str = '<li>'.number_format(microtime(true)-$start,3).' seconds ('.$i.'/'.count($feedsHash).'): Updating: <a href="?currentHash='.$feedHash.'">'.$feed['title'].'</a></li>';
5086:             echo ($format==='html'?$str:strip_tags($str)).str_pad('',4096)."\n";
5087:             ob_flush();
5088:             flush();
5089:             if ($force or $this->needUpdate($feed)) {
5090:                 $info = $this->updateChannel($feedHash);
5091:                 $str = '<li>'.number_format(microtime(true)-$start,3).' seconds: Updated: <span class="text-success">'.count($info['newItems']).' new item(s)</span>';
5092:                 if (empty($info['error'])) {
5093:                     $str .= '</li>';
5094:                 } else {
5095:                     $str .= ' <span class="text-error">('.$this->getError($info['error']).')</span></li>';
5096:                 }
5097:             } else {
5098:                 $str = '<li>'.number_format(microtime(true)-$start,3).' seconds: Already up-to-date: <span class="text-warning">'.$feed['title'].'</span></li>';
5099: 
5100:             }
5101:             echo ($format==='html'?$str:strip_tags($str)).str_pad('',4096)."\n";
5102:             ob_flush();
5103:             flush();
5104:         }
5105:     }
5106: 
5107:     public function markAll($read) {
5108:         $save = false;
5109: 
5110:         foreach (array_keys($this->_data['items']) as $itemHash) {
5111:             if (!$save and $this->_data['items'][$itemHash][1] != $read) {
5112:                 $save = true;
5113:             }
5114:             $this->_data['items'][$itemHash][1] = $read;
5115:         }
5116:         foreach (array_keys($this->_data['newItems']) as $itemHash) {
5117:             if (!$save and $this->_data['newItems'][$itemHash][1] != $read) {
5118:                 $save = true;
5119:             }
5120:             $this->_data['newItems'][$itemHash][1] = $read;
5121:         }
5122: 
5123:         if ($save) {
5124:             foreach ($this->_data['feeds'] as $feedHash => $feed) {
5125:                 if ($read == 1) {
5126:                     $this->_data['feeds'][$feedHash]['nbUnread'] = 0;
5127:                 } else {
5128:                     $this->_data['feeds'][$feedHash]['nbUnread'] = $this->_data['feeds'][$feedHash]['nbAll'];
5129:                 }
5130:             }
5131:         }
5132: 
5133:         return $save;
5134:     }
5135: 
5136:     public function markItem($itemHash, $read) {
5137:         $save = false;
5138: 
5139:         if (isset($this->_data['items'][$itemHash])) {
5140:             if ($this->_data['items'][$itemHash][1] != $read) {
5141:                 $save = true;
5142:                 $this->_data['items'][$itemHash][1] = $read;
5143:             }
5144:         } else if (isset($this->_data['newItems'][$itemHash])) {
5145:             if ($this->_data['newItems'][$itemHash][1] != $read) {
5146:                 $save = true;
5147:                 $this->_data['newItems'][$itemHash][1] = $read;
5148:             }
5149:         }
5150: 
5151:         if ($save) {
5152:             $feedHash = substr($itemHash, 0, 6);
5153:             if ($read == 1) {
5154:                 $this->_data['feeds'][$feedHash]['nbUnread']--;
5155:             } else {
5156:                 $this->_data['feeds'][$feedHash]['nbUnread']++;
5157:             }
5158:         }
5159: 
5160:         return $save;
5161:     }
5162: 
5163:     public function markFeeds($feedsHash, $read) {
5164:         $save = false;
5165: 
5166:         // get items from a list of feeds
5167:         $flipFeedsHash = array_flip($feedsHash);
5168:         foreach ($this->_data['items'] as $itemHash => $item) {
5169:             if (isset($flipFeedsHash[substr($itemHash, 0, 6)])) {
5170:                 if ($this->_data['items'][$itemHash][1] != $read) {
5171:                     $save = true;
5172:                     $this->_data['items'][$itemHash][1] = $read;
5173:                 }
5174:             }
5175:         }
5176:         foreach ($this->_data['newItems'] as $itemHash => $item) {
5177:             if (isset($flipFeedsHash[substr($itemHash, 0, 6)])) {
5178:                 if ($this->_data['newItems'][$itemHash][1] != $read) {
5179:                     $save = true;
5180:                     $this->_data['newItems'][$itemHash][1] = $read;
5181:                 }
5182:             }
5183:         }
5184: 
5185:         if ($save) {
5186:             foreach (array_values($feedsHash) as $feedHash) {
5187:                 if ($read == 1) {
5188:                     $this->_data['feeds'][$feedHash]['nbUnread'] = 0;
5189:                 } else {
5190:                     $this->_data['feeds'][$feedHash]['nbUnread'] = $this->_data['feeds']['nbAll'];
5191:                 }
5192:             }
5193:         }
5194: 
5195:         return $save;
5196:     }
5197:        
5198:     public function mark($hash, $read)
5199:     {
5200:         if (empty($hash) || $hash == 'all') {
5201:             // all items
5202:             return $this->markAll($read);
5203:         } else {
5204:             if (strlen($hash) === 12) {
5205:                 // an item
5206:                 return $this->markItem($hash, $read);
5207:             } else {
5208:                 $feedsHash = array();
5209:                 if (isset($this->_data['feeds'][$hash])) {
5210:                     // a feed
5211:                     $feedsHash[] = $hash;
5212:                 } else if (isset($this->_data['folders'][$hash])) {
5213:                     // a folder
5214:                     foreach ($this->_data['feeds'] as $feedHash => $feed) {
5215:                         if (in_array($hash, $feed['foldersHash'])) {
5216:                             $feedsHash[] = $feedHash;
5217:                         }
5218:                     }
5219:                 }
5220: 
5221:                 return $this->markFeeds($feedsHash, $read);
5222:             }
5223:         }
5224: 
5225:         return false;
5226:     }
5227: 
5228:     public function hashType($hash)
5229:     {
5230:         $type = '';
5231:         if (empty($hash) || $hash=='all') {
5232:             $type = 'all';
5233:         } else {
5234:             if (strlen($hash) === 12) {
5235:                 // should be an item
5236:                 $type = 'item';
5237:             } else {
5238:                 if (isset($this->_data['folders'][$hash])) {
5239:                     // a folder
5240:                     $type = 'folder';
5241:                 } else {
5242:                     if (isset($this->_data['feeds'][$hash])) {
5243:                         // a feed
5244:                         $type = 'feed';
5245:                     } else {
5246:                         $type = 'unknown';
5247:                     }
5248:                 }
5249:             }
5250:         }
5251: 
5252:         return $type;
5253:     }
5254: 
5255:     public static function sortByTitle($a, $b) {
5256:         return strnatcasecmp($a['title'], $b['title']);
5257:     }
5258: }
5259: 
5260: 
5261: class MyTool
5262: {
5263:     public static function initPhp()
5264:     {
5265:         define('START_TIME', microtime(true));
5266: 
5267:         if (phpversion() < 5) {
5268:             die("Argh you don't have PHP 5 !");
5269:         }
5270: 
5271:         error_reporting(E_ALL);
5272: 
5273:         function stripslashesDeep($value) {
5274:             return is_array($value)
5275:                 ? array_map('stripslashesDeep', $value)
5276:                 : stripslashes($value);
5277:         }
5278: 
5279:         if (get_magic_quotes_gpc()) {
5280:             $_POST = array_map('stripslashesDeep', $_POST);
5281:             $_GET = array_map('stripslashesDeep', $_GET);
5282:             $_COOKIE = array_map('stripslashesDeep', $_COOKIE);
5283:         }
5284: 
5285:         ob_start();
5286:         register_shutdown_function('ob_end_flush');
5287:     }
5288: 
5289:     public static function isUrl($url)
5290:     {
5291:         // http://neo22s.com/check-if-url-exists-and-is-online-php/
5292:         $pattern='|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i';
5293: 
5294:         return preg_match($pattern, $url);
5295:     }
5296: 
5297:     public static function isEmail($email)
5298:     {
5299:         $pattern = "/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2, 4}$/i";
5300: 
5301:         return (preg_match($pattern, $email));
5302:     }
5303: 
5304:     public static function formatBBCode($text)
5305:     {
5306:         $replace = array(
5307:             '/\[m\](.+?)\[\/m\]/is'
5308:             => '/* moderate */',
5309:             '/\[b\](.+?)\[\/b\]/is'
5310:             => '<strong>$1</strong>',
5311:             '/\[i\](.+?)\[\/i\]/is'
5312:             => '<em>$1</em>',
5313:             '/\[s\](.+?)\[\/s\]/is'
5314:             => '<del>$1</del>',
5315:             '/\[u\](.+?)\[\/u\]/is'
5316:             => '<span style="text-decoration: underline;">$1</span>',
5317:             '/\[url\](.+?)\[\/url]/is'
5318:             => '<a href="$1">$1</a>',
5319:             '/\[url=(\w+:\/\/[^\]]+)\](.+?)\[\/url]/is'
5320:             => '<a href="$1">$2</a>',
5321:             '/\[quote\](.+?)\[\/quote\]/is'
5322:             => '<blockquote>$1</blockquote>',
5323:             '/\[code\](.+?)\[\/code\]/is'
5324:             => '<code>$1</code>',
5325:             '/\[([^[]+)\|([^[]+)\]/is'
5326:             => '<a href="$2">$1</a>'
5327:             );
5328:         $text = preg_replace(
5329:             array_keys($replace),
5330:             array_values($replace),
5331:             $text
5332:         );
5333: 
5334:         return $text;
5335:     }
5336: 
5337:     public static function formatText($text)
5338:     {
5339:         $text = preg_replace_callback(
5340:             '/<code_html>(.*?)<\/code_html>/is',
5341:             create_function(
5342:                 '$matches',
5343:                 'return htmlspecialchars($matches[1]);'
5344:             ),
5345:             $text
5346:         );
5347:         $text = preg_replace_callback(
5348:             '/<code_php>(.*?)<\/code_php>/is',
5349:             create_function(
5350:                 '$matches',
5351:                 'return highlight_string("<?php $matches[1] ?>", true);'
5352:             ),
5353:             $text
5354:         );
5355:         $text = preg_replace('/<br \/>/is', '', $text);
5356: 
5357:         $text = preg_replace(
5358:             '#(^|\s)([a-z]+://([^\s\w/]?[\w/])*)(\s|$)#im',
5359:             '\\1<a href="\\2">\\2</a>\\4',
5360:             $text
5361:         );
5362:         $text = preg_replace(
5363:             '#(^|\s)wp:?([a-z]{2}|):([\w]+)#im',
5364:             '\\1<a href="http://\\2.wikipedia.org/wiki/\\3">\\3</a>',
5365:             $text
5366:         );
5367:         $text = str_replace(
5368:             'http://.wikipedia.org/wiki/',
5369:             'http://www.wikipedia.org/wiki/',
5370:             $text
5371:         );
5372:         $text = str_replace('\wp:', 'wp:', $text);
5373:         $text = str_replace('\http:', 'http:', $text);
5374:         $text = MyTool::formatBBCode($text);
5375:         $text = nl2br($text);
5376: 
5377:         return $text;
5378:     }
5379: 
5380:     public static function getUrl()
5381:     {
5382:         $https = (!empty($_SERVER['HTTPS'])
5383:                   && (strtolower($_SERVER['HTTPS']) == 'on'))
5384:             || (isset($_SERVER["SERVER_PORT"])
5385:                 && $_SERVER["SERVER_PORT"] == '443'); // HTTPS detection.
5386:         $serverport = (!isset($_SERVER["SERVER_PORT"])
5387:                        || $_SERVER["SERVER_PORT"] == '80'
5388:                        || ($https && $_SERVER["SERVER_PORT"] == '443')
5389:                        ? ''
5390:                        : ':' . $_SERVER["SERVER_PORT"]);
5391: 
5392:         $scriptname = ($_SERVER["SCRIPT_NAME"] == 'index.php' ? '' : $_SERVER["SCRIPT_NAME"]);
5393: 
5394:         if (!isset($_SERVER["SERVER_NAME"])) {
5395:             return $scriptname;
5396:         }
5397: 
5398:         return 'http' . ($https ? 's' : '') . '://'
5399:             . $_SERVER["SERVER_NAME"] . $serverport . $scriptname;
5400:     }
5401: 
5402:     public static function rrmdir($dir)
5403:     {
5404:         if (is_dir($dir) && ($d = @opendir($dir))) {
5405:             while (($file = @readdir($d)) !== false) {
5406:                 if ( $file == '.' || $file == '..' ) {
5407:                     continue;
5408:                 } else {
5409:                     unlink($dir . '/' . $file);
5410:                 }
5411:             }
5412:         }
5413:     }
5414: 
5415:     public static function humanBytes($bytes)
5416:     {
5417:         $siPrefix = array( 'bytes', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB' );
5418:         $base = 1024;
5419:         $class = min((int) log($bytes, $base), count($siPrefix) - 1);
5420:         $val = sprintf('%1.2f', $bytes / pow($base, $class));
5421: 
5422:         return $val . ' ' . $siPrefix[$class];
5423:     }
5424: 
5425:     public static function returnBytes($val)
5426:     {
5427:         $val  = trim($val);
5428:         $last = strtolower($val[strlen($val)-1]);
5429:         switch($last)
5430:         {
5431:         case 'g': $val *= 1024;
5432:         case 'm': $val *= 1024;
5433:         case 'k': $val *= 1024;
5434:         }
5435: 
5436:         return $val;
5437:     }
5438: 
5439:     public static function getMaxFileSize()
5440:     {
5441:         $sizePostMax   = MyTool::returnBytes(ini_get('post_max_size'));
5442:         $sizeUploadMax = MyTool::returnBytes(ini_get('upload_max_filesize'));
5443: 
5444:         // Return the smaller of two:
5445:         return min($sizePostMax, $sizeUploadMax);
5446:     }
5447: 
5448:     public static function smallHash($text)
5449:     {
5450:         $t = rtrim(base64_encode(hash('crc32', $text, true)), '=');
5451:         // Get rid of characters which need encoding in URLs.
5452:         $t = str_replace('+', '-', $t);
5453:         $t = str_replace('/', '_', $t);
5454:         $t = str_replace('=', '@', $t);
5455: 
5456:         return $t;
5457:     }
5458: 
5459:     public static function renderJson($data)
5460:     {
5461:         header('Cache-Control: no-cache, must-revalidate');
5462:         header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
5463:         header('Content-type: application/json; charset=UTF-8');
5464: 
5465:         echo json_encode($data);
5466:         exit();
5467:     }
5468:     public static function redirect($rurl = '')
5469:     {
5470:         if ($rurl === '') {
5471:             // if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['SERVER_NAME'])==0)
5472:             $rurl = (empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']);
5473:             if (!empty($_POST)) {
5474:                 $rurl = $_POST['returnurl'];
5475:             }
5476:         }
5477: 
5478:         // prevent loop
5479:         if (empty($rurl) || parse_url($rurl, PHP_URL_QUERY) === $_SERVER['QUERY_STRING']) {
5480:             $rurl = MyTool::getUrl();
5481:         }
5482: 
5483:         if (substr($rurl, 0, 1) !== '?') {
5484:             $ref = MyTool::getUrl();
5485:             if (substr($rurl, 0, strlen($ref)) != $ref) {
5486:                 $rurl = $ref;
5487:             }
5488:         }
5489:         header('Location: '.$rurl);
5490:         exit();
5491:     }
5492: 
5493:     public static function silence_errors($num, $str)
5494:     {
5495:     // No-op                                                      
5496:     }
5497: }
5498: 
5499: class Opml
5500: {
5501:     public static function importOpml($kfData)
5502:     {
5503:         $feeds = $kfData['feeds'];
5504:         $folders = $kfData['folders'];
5505: 
5506:         $filename  = $_FILES['filetoupload']['name'];
5507:         $filesize  = $_FILES['filetoupload']['size'];
5508:         $data      = file_get_contents($_FILES['filetoupload']['tmp_name']);
5509:         $overwrite = isset($_POST['overwrite']);
5510: 
5511:         $opml = new DOMDocument('1.0', 'UTF-8');
5512: 
5513:         $importCount=0;
5514:         if ($opml->loadXML($data)) {
5515:             $body = $opml->getElementsByTagName('body');
5516:             $xmlArray = Opml::getArrayFromXml($body->item(0));
5517:             $array = Opml::convertOpmlArray($xmlArray['outline']);
5518: 
5519:             foreach ($array as $hashUrl => $arrayInfo) {
5520:                 $title = '';
5521:                 if (isset($arrayInfo['title'])) {
5522:                     $title = $arrayInfo['title'];
5523:                 } else if (isset($arrayInfo['text'])) {
5524:                     $title = $arrayInfo['text'];
5525:                 }
5526:                 $foldersHash = array();
5527:                 if (isset($arrayInfo['folders'])) {
5528:                     foreach ($arrayInfo['folders'] as $folder) {
5529:                         $folderTitle = html_entity_decode(
5530:                             $folder,
5531:                             ENT_QUOTES,
5532:                             'UTF-8'
5533:                         );
5534:                         $folderHash = MyTool::smallHash($folderTitle);
5535:                         if (!isset($folders[$folderHash])) {
5536:                             $folders[$folderHash] = array('title' => $folderTitle, 'isOpen' => true);
5537:                         }
5538:                         $foldersHash[] = $folderHash;
5539:                     }
5540:                 }
5541:                 $timeUpdate = 'auto';
5542:                 $lastUpdate = 0;
5543:                 $xmlUrl = '';
5544:                 if (isset($arrayInfo['xmlUrl'])) {
5545:                     $xmlUrl = $arrayInfo['xmlUrl'];
5546:                 }
5547:                 $htmlUrl = '';
5548:                 if (isset($arrayInfo['htmlUrl'])) {
5549:                     $htmlUrl = $arrayInfo['htmlUrl'];
5550:                 }
5551:                 $description = '';
5552:                 if (isset($arrayInfo['description'])) {
5553:                     $description = $arrayInfo['description'];
5554:                 }
5555:                 // create new feed
5556:                 if (!empty($xmlUrl)) {
5557:                     $oldFeed = array('nbUnread' => 0, 'nbAll' => 0);
5558:                     if (isset($feeds[$hashUrl])) {
5559:                         $oldFeed['nbUnread'] = $feeds[$hashUrl]['nbUnread'];
5560:                         $oldFeed['nbAll'] = $feeds[$hashUrl]['nbAll'];
5561:                     }
5562:                     $currentFeed = array(
5563:                         'title'
5564:                         =>
5565:                         html_entity_decode($title, ENT_QUOTES, 'UTF-8'),
5566:                         'description'
5567:                         =>
5568:                         html_entity_decode($description, ENT_QUOTES, 'UTF-8'),
5569:                         'htmlUrl'
5570:                         =>
5571:                         html_entity_decode($htmlUrl, ENT_QUOTES, 'UTF-8'),
5572:                         'xmlUrl'
5573:                         =>
5574:                         html_entity_decode($xmlUrl, ENT_QUOTES, 'UTF-8'),
5575:                         'nbUnread' => $oldFeed['nbUnread'],
5576:                         'nbAll' => $oldFeed['nbAll'],
5577:                         'foldersHash' => $foldersHash,
5578:                         'timeUpdate' => $timeUpdate,
5579:                         'lastUpdate' => $lastUpdate);
5580: 
5581:                     if ($overwrite || !isset($feeds[$hashUrl])) {
5582:                         $feeds[$hashUrl] = $currentFeed;
5583:                         $importCount++;
5584:                     }
5585:                 }
5586:             }
5587: 
5588:             echo '<script>alert("File '
5589:                 . htmlspecialchars($filename) . ' (' . MyTool::humanBytes($filesize)
5590:                 . ') was successfully processed: ' . $importCount
5591:                 . ' links imported.");document.location=\'?\';</script>';
5592: 
5593:             $kfData['feeds'] = $feeds;
5594:             $kfData['folders'] = $folders;
5595: 
5596:             return $kfData;
5597:         } else {
5598:             echo '<script>alert("File ' . htmlspecialchars($filename) . ' ('
5599:                 . MyTool::humanBytes($filesize) . ') has an unknown'
5600:                 . ' file format. Check encoding, try to remove accents'
5601:                 . ' and try again. Nothing was imported.");'
5602:                 . 'document.location=\'?\';</script>';
5603:             exit;
5604:         }
5605:     }
5606: 
5607:     public static function exportOpml($feeds, $folders)
5608:     {
5609:         $withoutFolder = array();
5610:         $withFolder = array();
5611: 
5612:         // get a new representation of data using folders as key
5613:         foreach ($feeds as $hashUrl => $arrayInfo) {
5614:             if (empty($arrayInfo['foldersHash'])) {
5615:                 $withoutFolder[] = $hashUrl;
5616:             } else {
5617:                 foreach ($arrayInfo['foldersHash'] as $folderHash) {
5618:                     $withFolder[$folderHash][] = $hashUrl;
5619:                 }
5620:             }
5621:         }
5622: 
5623:         // generate opml file
5624:         header('Content-Type: text/xml; charset=utf-8');
5625:         header(
5626:             'Content-disposition: attachment; filename=kriss_feed_'
5627:             . strval(date('Ymd_His')) . '.opml'
5628:         );
5629:         $opmlData = new DOMDocument('1.0', 'UTF-8');
5630: 
5631:         // we want a nice output
5632:         $opmlData->formatOutput = true;
5633: 
5634:         // opml node creation
5635:         $opml = $opmlData->createElement('opml');
5636:         $opmlVersion = $opmlData->createAttribute('version');
5637:         $opmlVersion->value = '1.0';
5638:         $opml->appendChild($opmlVersion);
5639: 
5640:         // head node creation
5641:         $head = $opmlData->createElement('head');
5642:         $title = $opmlData->createElement('title', 'KrISS Feed');
5643:         $head->appendChild($title);
5644:         $opml->appendChild($head);
5645: 
5646:         // body node creation
5647:         $body = $opmlData->createElement('body');
5648: 
5649:         // without folder outline node
5650:         foreach ($withoutFolder as $hashUrl) {
5651:             $outline = $opmlData->createElement('outline');
5652:             $outlineTitle = $opmlData->createAttribute('title');
5653:             $outlineTitle->value = htmlspecialchars(
5654:                 $feeds[$hashUrl]['title']
5655:             );
5656:             $outline->appendChild($outlineTitle);
5657:             $outlineText = $opmlData->createAttribute('text');
5658:             $outlineText->value
5659:                 = htmlspecialchars($feeds[$hashUrl]['title']);
5660:             $outline->appendChild($outlineText);
5661:             if (!empty($feeds[$hashUrl]['description'])) {
5662:                 $outlineDescription
5663:                     = $opmlData->createAttribute('description');
5664:                 $outlineDescription->value
5665:                     = htmlspecialchars($feeds[$hashUrl]['description']);
5666:                 $outline->appendChild($outlineDescription);
5667:             }
5668:             $outlineXmlUrl = $opmlData->createAttribute('xmlUrl');
5669:             $outlineXmlUrl->value
5670:                 = htmlspecialchars($feeds[$hashUrl]['xmlUrl']);
5671:             $outline->appendChild($outlineXmlUrl);
5672:             $outlineHtmlUrl = $opmlData->createAttribute('htmlUrl');
5673:             $outlineHtmlUrl->value = htmlspecialchars(
5674:                 $feeds[$hashUrl]['htmlUrl']
5675:             );
5676:             $outline->appendChild($outlineHtmlUrl);
5677:             $body->appendChild($outline);
5678:         }
5679: 
5680:         // with folder outline node
5681:         foreach ($withFolder as $folderHash => $arrayHashUrl) {
5682:             $outline = $opmlData->createElement('outline');
5683:             $outlineTitle = $opmlData->createAttribute('title');
5684:             $outlineTitle->value = htmlspecialchars($folders[$folderHash]['title']);
5685:             $outline->appendChild($outlineTitle);
5686:             $outlineText = $opmlData->createAttribute('text');
5687:             $outlineText->value = htmlspecialchars($folders[$folderHash]['title']);
5688:             $outline->appendChild($outlineText);
5689: 
5690:             foreach ($arrayHashUrl as $hashUrl) {
5691:                 $outlineKF = $opmlData->createElement('outline');
5692:                 $outlineTitle = $opmlData->createAttribute('title');
5693:                 $outlineTitle->value
5694:                     = htmlspecialchars($feeds[$hashUrl]['title']);
5695:                 $outlineKF->appendChild($outlineTitle);
5696:                 $outlineText = $opmlData->createAttribute('text');
5697:                 $outlineText->value
5698:                     = htmlspecialchars($feeds[$hashUrl]['title']);
5699:                 $outlineKF->appendChild($outlineText);
5700:                 if (!empty($feeds[$hashUrl]['description'])) {
5701:                     $outlineDescription
5702:                         = $opmlData->createAttribute('description');
5703:                     $outlineDescription->value = htmlspecialchars(
5704:                         $feeds[$hashUrl]['description']
5705:                     );
5706:                     $outlineKF->appendChild($outlineDescription);
5707:                 }
5708:                 $outlineXmlUrl = $opmlData->createAttribute('xmlUrl');
5709:                 $outlineXmlUrl->value
5710:                     = htmlspecialchars($feeds[$hashUrl]['xmlUrl']);
5711:                 $outlineKF->appendChild($outlineXmlUrl);
5712:                 $outlineHtmlUrl = $opmlData->createAttribute('htmlUrl');
5713:                 $outlineHtmlUrl->value
5714:                     = htmlspecialchars($feeds[$hashUrl]['htmlUrl']);
5715:                 $outlineKF->appendChild($outlineHtmlUrl);
5716:                 $outline->appendChild($outlineKF);
5717:             }
5718:             $body->appendChild($outline);
5719:         }
5720: 
5721:         $opml->appendChild($body);
5722:         $opmlData->appendChild($opml);
5723: 
5724:         echo $opmlData->saveXML();
5725:         exit();
5726:     }
5727: 
5728:     public static function getArrayFromXml($node)
5729:     {
5730:         $array = false;
5731: 
5732:         if ($node->hasAttributes()) {
5733:             foreach ($node->attributes as $attr) {
5734:                 $array[$attr->nodeName] = $attr->nodeValue;
5735:             }
5736:         }
5737: 
5738:         if ($node->hasChildNodes()) {
5739:             if ($node->childNodes->length == 1) {
5740:                 $array[$node->firstChild->nodeName]
5741:                     = $node->firstChild->nodeValue;
5742:             } else {
5743:                 foreach ($node->childNodes as $childNode) {
5744:                     if ($childNode->nodeType != XML_TEXT_NODE) {
5745:                         $array[$childNode->nodeName][]
5746:                             = Opml::getArrayFromXml($childNode);
5747:                     }
5748:                 }
5749:             }
5750:         }
5751: 
5752:         return $array;
5753:     }
5754: 
5755:     public static function convertOpmlArray($array, $listFolders = array())
5756:     {
5757:         $newArray = array();
5758: 
5759:         for ($i = 0, $len = count($array); $i < $len; $i++) {
5760:             if (isset($array[$i]['outline'])
5761:                 && (isset($array[$i]['text'])
5762:                 || isset($array[$i]['title']))
5763:             ) {
5764:                 // here is a folder
5765:                 if (isset($array[$i]['text'])) {
5766:                     $listFolders[] = $array[$i]['text'];
5767:                 } else {
5768:                     $listFolders[] = $array[$i]['title'];
5769:                 }
5770:                 $newArray = array_merge(
5771:                     $newArray,
5772:                     Opml::convertOpmlArray(
5773:                         $array[$i]['outline'],
5774:                         $listFolders
5775:                     )
5776:                 );
5777:                 array_pop($listFolders);
5778:             } else {
5779:                 if (isset($array[$i]['xmlUrl'])) {
5780:                     // here is a feed
5781:                     $xmlUrl = MyTool::smallHash($array[$i]['xmlUrl']);
5782:                     if (isset($newArray[$xmlUrl])) {
5783:                         //feed already exists
5784:                         foreach ($listFolders as $val) {
5785:                             // add folder to the feed
5786:                             if (!in_array(
5787:                                 $val,
5788:                                 $newArray[$xmlUrl]['folders']
5789:                             )) {
5790:                                 $newArray[$xmlUrl]['folders'][] = $val;
5791:                             }
5792:                         }
5793:                     } else {
5794:                         // here is a new feed
5795:                         foreach ($array[$i] as $attr => $val) {
5796:                             $newArray[$xmlUrl][$attr] = $val;
5797:                         }
5798:                         $newArray[$xmlUrl]['folders'] = $listFolders;
5799:                     }
5800:                 }
5801:             }
5802:         }
5803: 
5804:         return $newArray;
5805:     }
5806: }
5807: 
5808: 
5809: class PageBuilder
5810: {
5811:     private $tpl; // For lazy initialization
5812: 
5813:     private $pageClass;
5814: 
5815:     public $var = array();
5816: 
5817:     public function __construct($pageClass)
5818:     {
5819:         $this->tpl = false;
5820:         $this->pageClass = $pageClass;
5821:     }
5822: 
5823:     private function initialize()
5824:     {
5825:         $this->tpl = true;
5826:         $ref = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
5827:         $this->assign('referer', $ref);
5828:     }
5829: 
5830:     //
5831:     public function assign($variable, $value = null)
5832:     {
5833:         if ($this->tpl === false) {
5834:             $this->initialize(); // Lazy initialization
5835:         }
5836:         if (is_array($variable)) {
5837:             $this->var += $variable;
5838:         } else {
5839:             $this->var[$variable] = $value;
5840:         }
5841:     }
5842: 
5843:     public function renderPage($page)
5844:     {
5845:         if ($this->tpl===false) {
5846:             $this->initialize(); // Lazy initialization
5847:         }
5848:         $method = $page.'Tpl';
5849:         if (method_exists($this->pageClass, $method)) {
5850:             $this->assign('template', $page);
5851:             $classPage = new $this->pageClass;
5852:             $classPage->init($this->var);
5853:             ob_start();
5854:             $classPage->$method();
5855:             ob_end_flush();
5856:         } else {
5857:             die("renderPage does not exist: ".$page);
5858:         }
5859:     }
5860: }
5861: 
5862: class Session
5863: {
5864:     private static $_instance;
5865: 
5866:     public static $inactivityTimeout = 3600;
5867: 
5868:     public static $disableSessionProtection = false;
5869: 
5870:     public static $banFile = 'ipbans.php';
5871:     public static $banAfter = 4;
5872:     public static $banDuration = 1800;
5873: 
5874:     private function __construct($banFile)
5875:     {
5876:         // Check ban configuration
5877:         self::$banFile = $banFile;
5878: 
5879:         if (!is_file(self::$banFile)) {
5880:             file_put_contents(self::$banFile, "<?php\n\$GLOBALS['IPBANS']=".var_export(array('FAILURES'=>array(),'BANS'=>array()),true).";\n?>");
5881:         }
5882:         include self::$banFile;
5883: 
5884:         // Force cookie path (but do not change lifetime)
5885:         $cookie=session_get_cookie_params();
5886:         // Default cookie expiration and path.
5887:         $cookiedir = '';
5888:         if(dirname($_SERVER['SCRIPT_NAME'])!='/') {
5889:             $cookiedir = dirname($_SERVER["SCRIPT_NAME"]).'/';
5890:         }
5891:         session_set_cookie_params($cookie['lifetime'], $cookiedir);
5892:         // Use cookies to store session.
5893:         ini_set('session.use_cookies', 1);
5894:         // Force cookies for session  (phpsessionID forbidden in URL)
5895:         ini_set('session.use_only_cookies', 1);
5896:         if (!session_id()) {
5897:             // Prevent php to use sessionID in URL if cookies are disabled.
5898:             ini_set('session.use_trans_sid', false);
5899:             session_name('kriss');
5900:             session_start();
5901:         }
5902:     }
5903: 
5904:     public static function init($banFile)
5905:     {
5906:         if (!isset(self::$_instance)) {
5907:             self::$_instance = new Session($banFile);
5908:         }
5909:     }
5910: 
5911:     public static function banLoginFailed()
5912:     {
5913:         $ip = $_SERVER["REMOTE_ADDR"];
5914:         $gb = $GLOBALS['IPBANS'];
5915: 
5916:         if (!isset($gb['FAILURES'][$ip])) {
5917:             $gb['FAILURES'][$ip] = 0;
5918:         }
5919:         $gb['FAILURES'][$ip]++;
5920:         if ($gb['FAILURES'][$ip] > (self::$banAfter-1)) {
5921:             $gb['BANS'][$ip]= time() + self::$banDuration;
5922:         }
5923: 
5924:         $GLOBALS['IPBANS'] = $gb;
5925:         file_put_contents(self::$banFile, "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>");
5926:     }
5927: 
5928:     function banLoginOk()
5929:     {
5930:         $ip = $_SERVER["REMOTE_ADDR"];
5931:         $gb = $GLOBALS['IPBANS'];
5932:         unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
5933:         $GLOBALS['IPBANS'] = $gb;
5934:         file_put_contents(self::$banFile, "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>");
5935:     }
5936: 
5937:     function banCanLogin()
5938:     {
5939:         $ip = $_SERVER["REMOTE_ADDR"];
5940:         $gb = $GLOBALS['IPBANS'];
5941:         if (isset($gb['BANS'][$ip])) {
5942:             // User is banned. Check if the ban has expired:
5943:             if ($gb['BANS'][$ip] <= time()) {
5944:                 // Ban expired, user can try to login again.
5945:                 unset($gb['FAILURES'][$ip]);
5946:                 unset($gb['BANS'][$ip]);
5947:                 file_put_contents(self::$banFile, "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>");
5948:                 return true; // Ban has expired, user can login.
5949:             }
5950:             return false; // User is banned.
5951:         }
5952:         return true; // User is not banned.
5953:     }
5954: 
5955:     private static function _allIPs()
5956:     {
5957:         $ip = $_SERVER["REMOTE_ADDR"];
5958:         $ip.= isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? '_'.$_SERVER['HTTP_X_FORWARDED_FOR'] : '';
5959:         $ip.= isset($_SERVER['HTTP_CLIENT_IP']) ? '_'.$_SERVER['HTTP_CLIENT_IP'] : '';
5960: 
5961:         return $ip;
5962:     }
5963: 
5964:     public static function login (
5965:         $login,
5966:         $password,
5967:         $loginTest,
5968:         $passwordTest,
5969:         $pValues = array())
5970:     {
5971:         if (!self::banCanLogin()) {
5972:             die('I said: NO. You are banned for the moment. Go away.');
5973:         }
5974:         if ($login == $loginTest && $password==$passwordTest) {
5975:             self::banLoginOk();
5976:             // Generate unique random number to sign forms (HMAC)
5977:             $_SESSION['uid'] = sha1(uniqid('', true).'_'.mt_rand());
5978:             $_SESSION['ip'] = Session::_allIPs();
5979:             $_SESSION['username'] = $login;
5980:             // Set session expiration.
5981:             $_SESSION['expires_on'] = time() + Session::$inactivityTimeout;
5982: 
5983:             foreach ($pValues as $key => $value) {
5984:                 $_SESSION[$key] = $value;
5985:             }
5986: 
5987:             return true;
5988:         }
5989:         self::banLoginFailed();
5990:         Session::logout();
5991: 
5992:         return false;
5993:     }
5994: 
5995:     public static function logout()
5996:     {
5997:         unset($_SESSION['uid'], $_SESSION['ip'], $_SESSION['expires_on']);
5998:     }
5999: 
6000:     public static function isLogged()
6001:     {
6002:         if (!isset ($_SESSION['uid'])
6003:             || (Session::$disableSessionProtection == false
6004:                 && $_SESSION['ip']!=Session::_allIPs())
6005:             || time()>=$_SESSION['expires_on']) {
6006:             Session::logout();
6007: 
6008:             return false;
6009:         }
6010:         // User accessed a page : Update his/her session expiration date.
6011:         if (time()+Session::$inactivityTimeout > $_SESSION['expires_on']) {
6012:             $_SESSION['expires_on'] = time()+Session::$inactivityTimeout;
6013:         }
6014: 
6015:         return true;
6016:     }
6017: 
6018:     public static function getToken($salt = '')
6019:     {
6020:         if (!isset($_SESSION['tokens'])) {
6021:             $_SESSION['tokens']=array();
6022:         }
6023:         // We generate a random string and store it on the server side.
6024:         $rnd = sha1(uniqid('', true).'_'.mt_rand().$salt);
6025:         $_SESSION['tokens'][$rnd]=1;
6026: 
6027:         return $rnd;
6028:     }
6029: 
6030:     public static function isToken($token)
6031:     {
6032:         if (isset($_SESSION['tokens'][$token])) {
6033:             unset($_SESSION['tokens'][$token]); // Token is used: destroy it.
6034: 
6035:             return true; // Token is ok.
6036:         }
6037: 
6038:         return false; // Wrong token, or already used.
6039:     }
6040: }//end class
6041: 
6042: // Check if php version is correct
6043: MyTool::initPHP();
6044: // Initialize Session
6045: Session::init(BAN_FILE);
6046: // XSRF protection with token
6047: if (!empty($_POST)) {
6048:     if (!Session::isToken($_POST['token'])) {
6049:         die('Wrong token.');
6050:     }
6051: }
6052: unset($_SESSION['tokens']);
6053: 
6054: $pb = new PageBuilder('FeedPage');
6055: $kfp = new FeedPage(STYLE_FILE);
6056: $kfc = new FeedConf(CONFIG_FILE, FEED_VERSION);
6057: $kf = new Feed(DATA_FILE, CACHE_DIR, $kfc);
6058: 
6059: // List or Expanded ?
6060: $view = $kfc->view;
6061: // show or hide list of feeds ?
6062: $listFeeds =  $kfc->listFeeds;
6063: // All or Unread ?
6064: $filter =  $kfc->filter;
6065: // newerFirst or olderFirst
6066: $order =  $kfc->order;
6067: // number of item by page
6068: $byPage = $kfc->getByPage();
6069: // Hash : 'all', feed hash or folder hash
6070: $currentHash = $kfc->getCurrentHash();
6071: // Query
6072: $query = '?';
6073: if (!empty($currentHash) and $currentHash !== 'all') {
6074:     $query = '?currentHash='.$currentHash.'&amp;';
6075: }
6076: 
6077: $pb->assign('view', $view);
6078: $pb->assign('listFeeds', $listFeeds);
6079: $pb->assign('filter', $filter);
6080: $pb->assign('order', $order);
6081: $pb->assign('byPage', $byPage);
6082: $pb->assign('currentHash', $currentHash);
6083: $pb->assign('query', $query);
6084: $pb->assign('redirector', $kfc->redirector);
6085: $pb->assign('shaarli', htmlspecialchars($kfc->shaarli));
6086: $pb->assign('autoreadItem', $kfc->autoreadItem);
6087: $pb->assign('autoreadPage', $kfc->autoreadPage);
6088: $pb->assign('autohide', $kfc->autohide);
6089: $pb->assign('autofocus', $kfc->autofocus);
6090: $pb->assign('autoupdate', $kfc->autoUpdate);
6091: $pb->assign('addFavicon', $kfc->addFavicon);
6092: $pb->assign('version', FEED_VERSION);
6093: $pb->assign('kfurl', MyTool::getUrl());
6094: 
6095: if (isset($_GET['login'])) {
6096:     // Login
6097:     if (!empty($_POST['login'])
6098:         && !empty($_POST['password'])
6099:     ) {
6100:         if (Session::login(
6101:             $kfc->login,
6102:             $kfc->hash,
6103:             $_POST['login'],
6104:             sha1($_POST['password'].$_POST['login'].$kfc->salt)
6105:         )) {
6106:             if (!empty($_POST['longlastingsession'])) {
6107:                 // (31536000 seconds = 1 year)
6108:                 $_SESSION['longlastingsession'] = 31536000;
6109:                 $_SESSION['expires_on'] =
6110:                     time() + $_SESSION['longlastingsession'];
6111:                 session_set_cookie_params($_SESSION['longlastingsession']);
6112:             } else {
6113:                 session_set_cookie_params(0); // when browser closes
6114:             }
6115:             session_regenerate_id(true);
6116: 
6117:             MyTool::redirect();
6118:         }
6119:         die("Login failed !");
6120:     } else {
6121:         $pb->assign('pagetitle', 'Login - '.strip_tags($kfc->title));
6122:         $pb->renderPage('login');
6123:     }
6124: } elseif (isset($_GET['logout'])) {
6125:     //Logout
6126:     Session::logout();
6127:     MyTool::redirect();
6128: } elseif (isset($_GET['ajax'])) {
6129:     $kf->loadData();
6130:     $needSave = false;
6131:     $result = array();
6132:     if (isset($_GET['current'])) {
6133:         $result['item'] = $kf->getItem($_GET['current'], false);
6134:         $result['item']['itemHash'] = $_GET['current'];
6135:     }
6136:     if (isset($_GET['read'])) {
6137:         $needSave = $kf->mark($_GET['read'], 1);
6138:         if ($needSave) {
6139:             $result['read'] = $_GET['read'];
6140:         }
6141:     }
6142:     if (isset($_GET['unread'])) {
6143:         $needSave = $kf->mark($_GET['unread'], 0);
6144:         if ($needSave) {
6145:             $result['unread'] = $_GET['unread'];
6146:         }
6147:     }
6148:     if (isset($_GET['toggleFolder'])) {
6149:         $needSave = $kf->toggleFolder($_GET['toggleFolder']);
6150:     }
6151:     if (isset($_GET['page'])) {
6152:         $listItems = $kf->getItems($currentHash, $filter);
6153:         $currentPage = $_GET['page'];
6154:         $index = ($currentPage - 1) * $byPage;
6155:         $results = array_slice($listItems, $index, $byPage + 1, true);
6156:         $result['page'] = array();
6157:         $firstIndex = -1;
6158:         if (isset($_GET['last'])) {
6159:             $firstIndex = array_search($_GET['last'], array_keys($results));
6160:             if ($firstIndex === false) {
6161:                 $firstIndex = -1;
6162:             }
6163:         }
6164:         $i = 0;
6165:         foreach(array_slice($results, $firstIndex + 1, count($results) - $firstIndex - 1, true) as $itemHash => $item) {
6166:             $result['page'][$i] = $kf->getItem($itemHash, false);
6167:             $result['page'][$i]['read'] = $item[1];
6168:             $i++;
6169:         }
6170:     }
6171:     if (isset($_GET['update'])) {
6172:         if (Session::isLogged()) {
6173:             if (empty($_GET['update'])) {
6174:                 $result['update']['feeds'] = array();
6175:                 $feedsHash = $kf->orderFeedsForUpdate(array_keys($kf->getFeeds()));
6176:                 foreach ($feedsHash as $feedHash) {
6177:                     $feed = $kf->getFeed($feedHash);
6178:                     $result['update']['feeds'][] = array($feedHash, $feed['title'], (int) ((time() - $feed['lastUpdate']) / 60), $kf->getTimeUpdate($feed));
6179:                 }
6180:             } else {
6181:                 $feed = $kf->getFeed($_GET['update']);
6182:                 $info = $kf->updateChannel($_GET['update']);
6183:                 if (empty($info['error'])) {
6184:                     $info['error'] = $feed['description'];
6185:                 } else {
6186:                     $info['error'] = $kf->getError($info['error']);
6187:                 }
6188:                 $info['newItems'] = array_keys($info['newItems']);
6189:                 $result['update'] = $info;
6190:             }
6191:         } else {
6192:             $result['update'] = false;
6193:         }
6194:     }
6195:     if ($needSave) {
6196:         $kf->writeData();
6197:     }
6198:     MyTool::renderJson($result);
6199: } elseif (isset($_GET['help'])) {
6200:     $pb->assign('pagetitle', 'Help for KrISS feed');
6201:     $pb->renderPage('help');
6202: } elseif ((isset($_GET['update'])
6203:           && (Session::isLogged()
6204:               || (isset($_GET['cron'])
6205:                   && $_GET['cron'] === sha1($kfc->salt.$kfc->hash))))
6206:           || (isset($argv)
6207:               && count($argv) >= 3
6208:               && $argv[1] == 'update'
6209:               && $argv[2] == sha1($kfc->salt.$kfc->hash))) {
6210:     // Update
6211:     $kf->loadData();
6212:     $forceUpdate = false;
6213:     if (isset($_GET['force'])) {
6214:         $forceUpdate = true;
6215:     }
6216:     $feedsHash = array();
6217:     $hash = 'all';
6218:     if (isset($_GET['update'])) {
6219:         $hash = $_GET['update'];
6220:     }
6221:     // type : 'feed', 'folder', 'all', 'item'
6222:     $type = $kf->hashType($hash);
6223:     switch($type) {
6224:     case 'feed':
6225:         $feedsHash[] = $hash;
6226:         break;
6227:     case 'folder':
6228:         $feedsHash = $kf->getFeedsHashFromFolderHash($hash);
6229:         break;
6230:     case 'all':
6231:     case '':
6232:         $feedsHash = array_keys($kf->getFeeds());
6233:         break;
6234:     case 'item':
6235:     default:
6236:         break;
6237:     }
6238:     if (isset($_GET['cron']) || isset($argv) && count($argv) >= 3) {
6239:         $kf->updateFeedsHash($feedsHash, $forceUpdate);
6240:     } else {
6241:         $pb->assign('kf', $kf);
6242:         $pb->assign('feedsHash', $feedsHash);
6243:         $pb->assign('forceUpdate', $forceUpdate);
6244:         $pb->assign('pagetitle', 'Update');
6245:         $pb->renderPage('update');
6246:     }
6247: } elseif (isset($_GET['config']) && Session::isLogged()) {
6248:     // Config
6249:     if (isset($_POST['save'])) {
6250:         if (isset($_POST['disableSessionProtection'])) {
6251:             $_POST['disableSessionProtection'] = '1';
6252:         } else {
6253:             $_POST['disableSessionProtection'] = '0';
6254:         }
6255:         $kfc->hydrate($_POST);
6256:         MyTool::redirect();
6257:     } elseif (isset($_POST['cancel'])) {
6258:         MyTool::redirect();
6259:     } else {
6260:         $menu = $kfc->getMenu();
6261:         $paging = $kfc->getPaging();
6262: 
6263:         $pb->assign('page', 'config');
6264:         $pb->assign('pagetitle', 'Config - '.strip_tags($kfc->title));
6265:         $pb->assign('kfctitle', htmlspecialchars($kfc->title));
6266:         $pb->assign('kfcredirector', htmlspecialchars($kfc->redirector));
6267:         $pb->assign('kfcshaarli', htmlspecialchars($kfc->shaarli));
6268:         $pb->assign('kfclocale', htmlspecialchars($kfc->locale));
6269:         $pb->assign('kfcmaxitems', htmlspecialchars($kfc->maxItems));
6270:         $pb->assign('kfcmaxupdate', htmlspecialchars($kfc->maxUpdate));
6271:         $pb->assign('kfcpublic', (int) $kfc->public);
6272:         $pb->assign('kfccron', sha1($kfc->salt.$kfc->hash));
6273:         $pb->assign('kfcautoreaditem', (int) $kfc->autoreadItem);
6274:         $pb->assign('kfcautoreadpage', (int) $kfc->autoreadPage);
6275:         $pb->assign('kfcautoupdate', (int) $kfc->autoUpdate);
6276:         $pb->assign('kfcautohide', (int) $kfc->autohide);
6277:         $pb->assign('kfcautofocus', (int) $kfc->autofocus);
6278:         $pb->assign('kfcaddfavicon', (int) $kfc->addFavicon);
6279:         $pb->assign('kfcdisablesessionprotection', (int) $kfc->disableSessionProtection);
6280:         $pb->assign('kfcmenu', $menu);
6281:         $pb->assign('kfcpaging', $paging);
6282: 
6283:         $pb->renderPage('config');
6284:     }
6285: } elseif (isset($_GET['import']) && Session::isLogged()) {
6286:     // Import
6287:     if (isset($_POST['import'])) {
6288:         // If file is too big, some form field may be missing.
6289:         if ((!isset($_FILES))
6290:             || (isset($_FILES['filetoupload']['size'])
6291:             && $_FILES['filetoupload']['size']==0)
6292:         ) {
6293:             $rurl = empty($_SERVER['HTTP_REFERER'])
6294:                 ? '?'
6295:                 : $_SERVER['HTTP_REFERER'];
6296:             echo '<script>alert("The file you are trying to upload'
6297:                 . ' is probably bigger than what this webserver can accept '
6298:                 . '(' . MyTool::humanBytes(MyTool::getMaxFileSize())
6299:                 . ' bytes). Please upload in smaller chunks.");'
6300:                 . 'document.location=\'' . htmlspecialchars($rurl)
6301:                 . '\';</script>';
6302:             exit;
6303:         }
6304:        
6305:         $kf->loadData();
6306:         $kf->setData(Opml::importOpml($kf->getData()));
6307:         $kf->sortFeeds();
6308:         $kf->writeData();
6309:         exit;
6310:     } else if (isset($_POST['cancel'])) {
6311:         MyTool::redirect();
6312:     } else {
6313:         $pb->assign('pagetitle', 'Import');
6314:         $pb->renderPage('import');
6315:     }
6316: } elseif (isset($_GET['export']) && Session::isLogged()) {
6317:     // Export
6318:     $kf->loadData();
6319:     Opml::exportOpml($kf->getFeeds(), $kf->getFolders());
6320: } elseif (isset($_GET['add']) && Session::isLogged()) {
6321:     // Add feed
6322:     $kf->loadData();
6323: 
6324:     if (isset($_POST['newfeed']) && !empty($_POST['newfeed'])) {
6325:         if ($kf->addChannel($_POST['newfeed'])) {
6326:             // Add success
6327:             $folders = array();
6328:             if (!empty($_POST['folders'])) {
6329:                 foreach ($_POST['folders'] as $hashFolder) {
6330:                     $folders[] = $hashFolder;
6331:                 }
6332:             }
6333:             if (!empty($_POST['newfolder'])) {
6334:                 $newFolderHash = MyTool::smallHash($_POST['newfolder']);
6335:                 $kf->addFolder($_POST['newfolder'], $newFolderHash);
6336:                 $folders[] = $newFolderHash;
6337:             }
6338:             $hash = MyTool::smallHash($_POST['newfeed']);
6339:             $kf->editFeed($hash, '', '', $folders, '');
6340:             $kf->sortFeeds();
6341:             $kf->writeData();
6342:             MyTool::redirect('?currentHash='.$hash);
6343:         } else {
6344:             // Add fail
6345:             $returnurl = empty($_SERVER['HTTP_REFERER'])
6346:                 ? MyTool::getUrl()
6347:                 : $_SERVER['HTTP_REFERER'];
6348:             echo '<script>alert("The feed you are trying to add already exists'
6349:                 . ' or is wrong. Check your feed or try again later.");'
6350:                 . 'document.location=\'' . htmlspecialchars($returnurl)
6351:                 . '\';</script>';
6352:             exit;
6353:         }
6354:     }
6355: 
6356:     $newfeed = '';
6357:     if (isset($_GET['newfeed'])) {
6358:         $newfeed = htmlspecialchars($_GET['newfeed']);
6359:     }
6360:     $pb->assign('page', 'add');
6361:     $pb->assign('pagetitle', 'Add a new feed');
6362:     $pb->assign('newfeed', $newfeed);
6363:     $pb->assign('folders', $kf->getFolders());
6364:    
6365:     $pb->renderPage('addFeed');
6366: } elseif (isset($_GET['toggleFolder']) && Session::isLogged()) {
6367:     $kf->loadData();
6368:     if (isset($_GET['toggleFolder'])) {
6369:         $kf->toggleFolder($_GET['toggleFolder']);
6370:     }
6371:     $kf->writeData();
6372:     MyTool::redirect();
6373: } elseif ((isset($_GET['read'])
6374:            || isset($_GET['unread']))
6375:           && Session::isLogged()) {
6376:     // mark all as read : item, feed, folder, all
6377:     $kf->loadData();
6378: 
6379:     $read = 1;
6380:     if (isset($_GET['read'])) {
6381:         $hash = $_GET['read'];
6382:         $read = 1;
6383:     } else {
6384:         $hash = $_GET['unread'];
6385:         $read = 0;
6386:     }
6387: 
6388:     $needSave = $kf->mark($hash, $read);
6389:     if ($needSave) {
6390:         $kf->writeData();
6391:     }
6392: 
6393:     // type : 'feed', 'folder', 'all', 'item'
6394:     $type = $kf->hashType($hash);
6395:     if ($type === 'item') {
6396:         MyTool::redirect($query.'current='.$hash);
6397:     } else {
6398:         if ($filter === 'unread' && $read === 1) {
6399:             MyTool::redirect('?');
6400:         } else {
6401:             MyTool::redirect($query);
6402:         }
6403:     }
6404: } elseif (isset($_GET['edit']) && Session::isLogged()) {
6405:     // Edit feed, folder, all
6406:     $kf->loadData();
6407:     $pb->assign('page', 'edit');
6408:     $pb->assign('pagetitle', 'edit');
6409:    
6410:     $hash = substr(trim($_GET['edit'], '/'), 0, 6);
6411: // type : 'feed', 'folder', 'all', 'item'
6412: $type = $kf->hashType($currentHash);
6413:     $type = $kf->hashType($hash);
6414:     switch($type) {
6415:     case 'feed':
6416:         if (isset($_POST['save'])) {
6417:             $title = $_POST['title'];
6418:             $description = $_POST['description'];
6419:             $folders = array();
6420:             if (!empty($_POST['folders'])) {
6421:                 foreach ($_POST['folders'] as $hashFolder) {
6422:                     $folders[] = $hashFolder;
6423:                 }
6424:             }
6425:             if (!empty($_POST['newfolder'])) {
6426:                 $newFolderHash = MyTool::smallHash($_POST['newfolder']);
6427:                 $kf->addFolder($_POST['newfolder'], $newFolderHash);
6428:                 $folders[] = $newFolderHash;
6429:             }
6430:             $timeUpdate = $_POST['timeUpdate'];
6431: 
6432:             $kf->editFeed($hash, $title, $description, $folders, $timeUpdate);
6433:             $kf->writeData();
6434: 
6435:             MyTool::redirect();
6436:         } elseif (isset($_POST['delete'])) {
6437:             $kf->removeFeed($hash);
6438:             $kf->writeData();
6439: 
6440:             MyTool::redirect('?');
6441:         } elseif (isset($_POST['cancel'])) {
6442:             MyTool::redirect();
6443:         } else {
6444:             $feed = $kf->getFeed($hash);
6445:             if (!empty($feed)) {
6446:                 $lastUpdate = 'need update';
6447:                 if (!$kf->needUpdate($feed)) {
6448:                     $diff = (int) (time() - $feed['lastUpdate']);
6449:                     $lastUpdate =
6450:                         (int) ($diff / 60) . ' m ' . (int) ($diff % 60) . ' s';
6451:                 }
6452: 
6453:                 $pb->assign('feed', $feed);
6454:                 $pb->assign('folders', $kf->getFolders());
6455:                 $pb->assign('lastUpdate', $lastUpdate);
6456:                 $pb->renderPage('editFeed');
6457:             } else {
6458:                 MyTool::redirect();
6459:             }
6460:         }
6461:         break;
6462:     case 'folder':
6463:         if (isset($_POST['save'])) {
6464:             $oldFolderTitle = $kf->getFolderTitle($hash);
6465:             $newFolderTitle = $_POST['foldertitle'];
6466:             if ($oldFolderTitle !== $newFolderTitle) {
6467:                 $kf->renameFolder($hash, $newFolderTitle);
6468:                 $kf->writeData();
6469:             }
6470: 
6471:             if (empty($newFolderTitle)) {
6472:                 MyTool::redirect('?');
6473:             } else {
6474:                 MyTool::redirect('?currentHash='.MyTool::smallHash($newFolderTitle));
6475:             }
6476:         } elseif (isset($_POST['cancel'])) {
6477:             MyTool::redirect();
6478:         } else {
6479:             $folderTitle = $kf->getFolderTitle($hash);
6480:             $pb->assign('foldertitle', htmlspecialchars($folderTitle));
6481:             $pb->renderPage('editFolder');
6482:         }
6483:         break;
6484:     case 'all':
6485:         if (isset($_POST['save'])) {
6486: 
6487:             $feedsHash = array();
6488:             foreach ($_POST['feeds'] as $feedHash) {
6489:                 $feedsHash[] = $feedHash;
6490:             }
6491: 
6492:             foreach ($feedsHash as $feedHash) {
6493:                 $feed = $kf->getFeed($feedHash);
6494:                 $addFoldersHash = $feed['foldersHash'];
6495:                 if (!empty($_POST['addfolders'])) {
6496:                     foreach ($_POST['addfolders'] as $folderHash) {
6497:                         if (!in_array($folderHash, $addFoldersHash)) {
6498:                             $addFoldersHash[] = $folderHash;
6499:                         }
6500:                     }
6501:                 }
6502:                 if (!empty($_POST['addnewfolder'])) {
6503:                     $newFolderHash = MyTool::smallHash($_POST['addnewfolder']);
6504:                     $kf->addFolder($_POST['addnewfolder'], $newFolderHash);
6505:                     $addFoldersHash[] = $newFolderHash;
6506:                 }
6507:                 $removeFoldersHash = array();
6508:                 if (!empty($_POST['removefolders'])) {
6509:                     foreach ($_POST['removefolders'] as $folderHash) {
6510:                         $removeFoldersHash[] = $folderHash;
6511:                     }
6512:                 }
6513:                 $addFoldersHash = array_diff($addFoldersHash, $removeFoldersHash);
6514: 
6515:                 $kf->editFeed(
6516:                     $feedHash,
6517:                     '',
6518:                     '',
6519:                     $addFoldersHash,
6520:                     ''
6521:                 );
6522:             }
6523:             $kf->writeData();
6524: 
6525:             MyTool::redirect();
6526:         } elseif (isset($_POST['delete'])) {
6527:             foreach ($_POST['feeds'] as $feedHash) {
6528:                 $kf->removeFeed($feedHash);
6529:             }
6530:             $kf->writeData();
6531: 
6532:             MyTool::redirect();
6533:         } elseif (isset($_POST['cancel'])) {
6534:             MyTool::redirect();
6535:         } else {
6536:             $folders = $kf->getFolders();
6537:             $listFeeds = $kf->getFeeds();
6538:             $pb->assign('folders', $folders);
6539:             $pb->assign('listFeeds', $listFeeds);
6540:             $pb->renderPage('editAll');
6541:         }
6542:         break;
6543:     case 'item':
6544:     default:
6545:         MyTool::redirect();
6546:         break;
6547:     }
6548: } elseif (isset($_GET['shaarli'])) {
6549:     $kf->loadData();
6550:     $item = $kf->getItem($_GET['shaarli'], false);
6551:     $shaarli = $kfc->shaarli;
6552:     // remove sel used with javascript
6553:     $shaarli = str_replace('${sel}', '', $shaarli);
6554: 
6555:     $url = htmlspecialchars_decode($item['link']);
6556:     $via = htmlspecialchars_decode($item['via']);
6557:     $title = htmlspecialchars_decode($item['title']);
6558: 
6559:     if (parse_url($url, PHP_URL_HOST) !== parse_url($via, PHP_URL_HOST)) {
6560:         $via = 'via '.$via;
6561:     } else {
6562:         $via = '';
6563:     }
6564: 
6565:     $shaarli = str_replace('${url}', urlencode($url), $shaarli);
6566:     $shaarli = str_replace('${title}', urlencode($title), $shaarli);
6567:     $shaarli = str_replace('${via}', urlencode($via), $shaarli);
6568: 
6569:     header('Location: '.$shaarli);
6570: } else {
6571:     if (Session::isLogged() || $kfc->public) {
6572:         $kf->loadData();
6573:         if ($kf->updateItems()) {
6574:             $kf->writeData();
6575:         }
6576: 
6577:         $listItems = $kf->getItems($currentHash, $filter);
6578:         $listHash = array_keys($listItems);
6579: 
6580:         $currentItemHash = '';
6581:         if (isset($_GET['current']) && !empty($_GET['current'])) {
6582:             $currentItemHash = $_GET['current'];
6583:         }
6584:         if (isset($_GET['next']) && !empty($_GET['next'])) {
6585:             $currentItemHash = $_GET['next'];
6586:             if ($kfc->autoreadItem) {
6587:                 if ($kf->mark($currentItemHash, 1)) {
6588:                     if ($filter == 'unread') {
6589:                         unset($listItems[$currentItemHash]);
6590:                     }
6591:                     $kf->writeData();
6592:                 }
6593:             }
6594:         }
6595:         if (isset($_GET['previous']) && !empty($_GET['previous'])) {
6596:             $currentItemHash = $_GET['previous'];
6597:         }
6598:         if (empty($currentItemHash)) {
6599:             $currentPage = $kfc->getCurrentPage();
6600:             $index = ($currentPage - 1) * $byPage;
6601:         } else {
6602:             $index = array_search($currentItemHash, $listHash);
6603:             if (isset($_GET['next'])) {
6604:                 if ($index < count($listHash)-1) {
6605:                     $index++;
6606:                 }
6607:             }
6608: 
6609:             if (isset($_GET['previous'])) {
6610:                 if ($index > 0) {
6611:                     $index--;
6612:                 }
6613:             }
6614:         }
6615:         if ($index < count($listHash)) {
6616:             $currentItemHash = $listHash[$index];
6617:         } else {
6618:             $index = count($listHash) - 1;
6619:         }
6620: 
6621:         $unread = 0;
6622:         foreach ($listItems as $itemHash => $item) {
6623:             if ($item[1] === 0) {
6624:                 $unread++;
6625:             }
6626:         }
6627: 
6628:         // pagination
6629:         $currentPage = (int) ($index/$byPage)+1;
6630:         if ($currentPage <= 0) {
6631:             $currentPage = 1;
6632:         }
6633:         $begin = ($currentPage - 1) * $byPage;
6634:         $maxPage = (count($listItems) <= $byPage) ? '1' : ceil(count($listItems) / $byPage);
6635:         $nbItems = count($listItems);
6636: 
6637:         // list items
6638:         $listItems = array_slice($listItems, $begin, $byPage, true);
6639: 
6640:         // type : 'feed', 'folder', 'all', 'item'
6641:         $currentHashType = $kf->hashType($currentHash);
6642:         $hashView = '';
6643:         switch($currentHashType){
6644:         case 'all':
6645:             $hashView = '<span id="nb-unread">'.$unread.'</span><span class="hidden-phone"> unread items</span>';
6646:             break;
6647:         case 'feed':
6648:             $hashView = 'Feed (<a href="'.$kf->getFeedHtmlUrl($currentHash).'" title="">'.$kf->getFeedTitle($currentHash).'</a>): '.'<span id="nb-unread">'.$unread.'</span><span class="hidden-phone"> unread items</span>';
6649:             break;
6650:         case 'folder':
6651:             $hashView = 'Folder ('.$kf->getFolderTitle($currentHash).'): <span id="nb-unread">'.$unread.'</span><span class="hidden-phone"> unread items</span>';
6652:             break;
6653:         default:
6654:             $hashView = '<span id="nb-unread">'.$unread.'</span><span class="hidden-phone"> unread items</span>';
6655:             break;
6656:         }
6657: 
6658:         $menu = $kfc->getMenu();
6659:         $paging = $kfc->getPaging();
6660:         $pb->assign('menu',  $menu);
6661:         $pb->assign('paging',  $paging);
6662:         $pb->assign('currentHashType', $currentHashType);
6663:         $pb->assign('currentHashView', $hashView);
6664:         $pb->assign('currentPage',  (int) $currentPage);
6665:         $pb->assign('maxPage', (int) $maxPage);
6666:         $pb->assign('currentItemHash', $currentItemHash);
6667:         $pb->assign('nbItems', $nbItems);
6668:         $pb->assign('items', $listItems);
6669:         if ($listFeeds == 'show') {
6670:             $pb->assign('feedsView', $kf->getFeedsView());
6671:         }
6672:         $pb->assign('kf',  $kf);
6673:         $pb->assign('pagetitle', strip_tags($kfc->title));
6674: 
6675:         $pb->renderPage('index');
6676:     } else {
6677:         $pb->assign('pagetitle', 'Login - '.strip_tags($kfc->title));
6678:         if (!empty($_SERVER['QUERY_STRING'])) {
6679:             $pb->assign('referer', MyTool::getUrl().'?'.$_SERVER['QUERY_STRING']);
6680:         }
6681:         $pb->renderPage('login');
6682:     }
6683: }
6684: //print(number_format(microtime(true)-START_TIME,3).' secondes');