commit 4599c79723212d233dacd6267b50ff42057fa489 Author: alazhar Date: Thu Jan 2 23:02:57 2020 +0700 first commit diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..a03b0e6 --- /dev/null +++ b/.htaccess @@ -0,0 +1,15 @@ +RewriteEngine On + +# Put your installation directory here: +# If your URL is www.example.com/, use / +# If your URL is www.example.com/site_folder/, use /site_folder/ + +RewriteBase /everseiko + +# Do not enable rewriting for files or directories that exist +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d + +# For reuests that are not actual files or directories, +# Rewrite to index.php/URL +RewriteRule ^(.*)$ index.php/$1 [PT,L] diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/application/.htaccess b/application/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/application/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/application/cache/.htaccess b/application/cache/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/application/cache/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/application/cache/index.html b/application/cache/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/cache/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/config/autoload.php b/application/config/autoload.php new file mode 100644 index 0000000..736a869 --- /dev/null +++ b/application/config/autoload.php @@ -0,0 +1,116 @@ + '', + 'xhtml1-strict' => '', + 'xhtml1-trans' => '', + 'xhtml1-frame' => '', + 'html5' => '', + 'html4-strict' => '', + 'html4-trans' => '', + 'html4-frame' => '' + ); + +/* End of file doctypes.php */ +/* Location: ./application/config/doctypes.php */ \ No newline at end of file diff --git a/application/config/foreign_chars.php b/application/config/foreign_chars.php new file mode 100644 index 0000000..14b0d73 --- /dev/null +++ b/application/config/foreign_chars.php @@ -0,0 +1,64 @@ + 'ae', + '/ö|œ/' => 'oe', + '/ü/' => 'ue', + '/Ä/' => 'Ae', + '/Ü/' => 'Ue', + '/Ö/' => 'Oe', + '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ/' => 'A', + '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a', + '/Ç|Ć|Ĉ|Ċ|Č/' => 'C', + '/ç|ć|ĉ|ċ|č/' => 'c', + '/Ð|Ď|Đ/' => 'D', + '/ð|ď|đ/' => 'd', + '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E', + '/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e', + '/Ĝ|Ğ|Ġ|Ģ/' => 'G', + '/ĝ|ğ|ġ|ģ/' => 'g', + '/Ĥ|Ħ/' => 'H', + '/ĥ|ħ/' => 'h', + '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ/' => 'I', + '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı/' => 'i', + '/Ĵ/' => 'J', + '/ĵ/' => 'j', + '/Ķ/' => 'K', + '/ķ/' => 'k', + '/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L', + '/ĺ|ļ|ľ|ŀ|ł/' => 'l', + '/Ñ|Ń|Ņ|Ň/' => 'N', + '/ñ|ń|ņ|ň|ʼn/' => 'n', + '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O', + '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o', + '/Ŕ|Ŗ|Ř/' => 'R', + '/ŕ|ŗ|ř/' => 'r', + '/Ś|Ŝ|Ş|Š/' => 'S', + '/ś|ŝ|ş|š|ſ/' => 's', + '/Ţ|Ť|Ŧ/' => 'T', + '/ţ|ť|ŧ/' => 't', + '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U', + '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u', + '/Ý|Ÿ|Ŷ/' => 'Y', + '/ý|ÿ|ŷ/' => 'y', + '/Ŵ/' => 'W', + '/ŵ/' => 'w', + '/Ź|Ż|Ž/' => 'Z', + '/ź|ż|ž/' => 'z', + '/Æ|Ǽ/' => 'AE', + '/ß/'=> 'ss', + '/IJ/' => 'IJ', + '/ij/' => 'ij', + '/Œ/' => 'OE', + '/ƒ/' => 'f' +); + +/* End of file foreign_chars.php */ +/* Location: ./application/config/foreign_chars.php */ \ No newline at end of file diff --git a/application/config/hooks.php b/application/config/hooks.php new file mode 100644 index 0000000..a4ad2be --- /dev/null +++ b/application/config/hooks.php @@ -0,0 +1,16 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/config/migration.php b/application/config/migration.php new file mode 100644 index 0000000..df42a3c --- /dev/null +++ b/application/config/migration.php @@ -0,0 +1,41 @@ +migration->latest() this is the version that schema will +| be upgraded / downgraded to. +| +*/ +$config['migration_version'] = 0; + + +/* +|-------------------------------------------------------------------------- +| Migrations Path +|-------------------------------------------------------------------------- +| +| Path to your migrations folder. +| Typically, it will be within your application path. +| Also, writing permission is required within the migrations path. +| +*/ +$config['migration_path'] = APPPATH . 'migrations/'; + + +/* End of file migration.php */ +/* Location: ./application/config/migration.php */ \ No newline at end of file diff --git a/application/config/mimes.php b/application/config/mimes.php new file mode 100644 index 0000000..100f7d4 --- /dev/null +++ b/application/config/mimes.php @@ -0,0 +1,106 @@ + 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'), + 'bin' => 'application/macbinary', + 'dms' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'exe' => array('application/octet-stream', 'application/x-msdownload'), + 'class' => 'application/octet-stream', + 'psd' => 'application/x-photoshop', + 'so' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => array('application/pdf', 'application/x-download'), + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'), + 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'), + 'wbxml' => 'application/wbxml', + 'wmlc' => 'application/wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'gz' => 'application/x-gzip', + 'php' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'js' => 'application/x-javascript', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => array('application/x-tar', 'application/x-gzip-compressed'), + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'), + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'), + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'rv' => 'video/vnd.rn-realvideo', + 'wav' => array('audio/x-wav', 'audio/wave', 'audio/wav'), + 'bmp' => array('image/bmp', 'image/x-windows-bmp'), + 'gif' => 'image/gif', + 'jpeg' => array('image/jpeg', 'image/pjpeg'), + 'jpg' => array('image/jpeg', 'image/pjpeg'), + 'jpe' => array('image/jpeg', 'image/pjpeg'), + 'png' => array('image/png', 'image/x-png'), + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'log' => array('text/plain', 'text/x-log'), + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'doc' => 'application/msword', + 'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip'), + 'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'), + 'word' => array('application/msword', 'application/octet-stream'), + 'xl' => 'application/excel', + 'eml' => 'message/rfc822', + 'json' => array('application/json', 'text/json') + ); + + +/* End of file mimes.php */ +/* Location: ./application/config/mimes.php */ diff --git a/application/config/profiler.php b/application/config/profiler.php new file mode 100644 index 0000000..f8a5b1a --- /dev/null +++ b/application/config/profiler.php @@ -0,0 +1,17 @@ + array('grin.gif', '19', '19', 'grin'), + ':lol:' => array('lol.gif', '19', '19', 'LOL'), + ':cheese:' => array('cheese.gif', '19', '19', 'cheese'), + ':)' => array('smile.gif', '19', '19', 'smile'), + ';-)' => array('wink.gif', '19', '19', 'wink'), + ';)' => array('wink.gif', '19', '19', 'wink'), + ':smirk:' => array('smirk.gif', '19', '19', 'smirk'), + ':roll:' => array('rolleyes.gif', '19', '19', 'rolleyes'), + ':-S' => array('confused.gif', '19', '19', 'confused'), + ':wow:' => array('surprise.gif', '19', '19', 'surprised'), + ':bug:' => array('bigsurprise.gif', '19', '19', 'big surprise'), + ':-P' => array('tongue_laugh.gif', '19', '19', 'tongue laugh'), + '%-P' => array('tongue_rolleye.gif', '19', '19', 'tongue rolleye'), + ';-P' => array('tongue_wink.gif', '19', '19', 'tongue wink'), + ':P' => array('raspberry.gif', '19', '19', 'raspberry'), + ':blank:' => array('blank.gif', '19', '19', 'blank stare'), + ':long:' => array('longface.gif', '19', '19', 'long face'), + ':ohh:' => array('ohh.gif', '19', '19', 'ohh'), + ':grrr:' => array('grrr.gif', '19', '19', 'grrr'), + ':gulp:' => array('gulp.gif', '19', '19', 'gulp'), + '8-/' => array('ohoh.gif', '19', '19', 'oh oh'), + ':down:' => array('downer.gif', '19', '19', 'downer'), + ':red:' => array('embarrassed.gif', '19', '19', 'red face'), + ':sick:' => array('sick.gif', '19', '19', 'sick'), + ':shut:' => array('shuteye.gif', '19', '19', 'shut eye'), + ':-/' => array('hmm.gif', '19', '19', 'hmmm'), + '>:(' => array('mad.gif', '19', '19', 'mad'), + ':mad:' => array('mad.gif', '19', '19', 'mad'), + '>:-(' => array('angry.gif', '19', '19', 'angry'), + ':angry:' => array('angry.gif', '19', '19', 'angry'), + ':zip:' => array('zip.gif', '19', '19', 'zipper'), + ':kiss:' => array('kiss.gif', '19', '19', 'kiss'), + ':ahhh:' => array('shock.gif', '19', '19', 'shock'), + ':coolsmile:' => array('shade_smile.gif', '19', '19', 'cool smile'), + ':coolsmirk:' => array('shade_smirk.gif', '19', '19', 'cool smirk'), + ':coolgrin:' => array('shade_grin.gif', '19', '19', 'cool grin'), + ':coolhmm:' => array('shade_hmm.gif', '19', '19', 'cool hmm'), + ':coolmad:' => array('shade_mad.gif', '19', '19', 'cool mad'), + ':coolcheese:' => array('shade_cheese.gif', '19', '19', 'cool cheese'), + ':vampire:' => array('vampire.gif', '19', '19', 'vampire'), + ':snake:' => array('snake.gif', '19', '19', 'snake'), + ':exclaim:' => array('exclaim.gif', '19', '19', 'excaim'), + ':question:' => array('question.gif', '19', '19', 'question') // no comma after last item + + ); + +/* End of file smileys.php */ +/* Location: ./application/config/smileys.php */ \ No newline at end of file diff --git a/application/config/user_agents.php b/application/config/user_agents.php new file mode 100644 index 0000000..e2d3c3a --- /dev/null +++ b/application/config/user_agents.php @@ -0,0 +1,178 @@ + 'Windows Longhorn', + 'windows nt 5.2' => 'Windows 2003', + 'windows nt 5.0' => 'Windows 2000', + 'windows nt 5.1' => 'Windows XP', + 'windows nt 4.0' => 'Windows NT 4.0', + 'winnt4.0' => 'Windows NT 4.0', + 'winnt 4.0' => 'Windows NT', + 'winnt' => 'Windows NT', + 'windows 98' => 'Windows 98', + 'win98' => 'Windows 98', + 'windows 95' => 'Windows 95', + 'win95' => 'Windows 95', + 'windows' => 'Unknown Windows OS', + 'os x' => 'Mac OS X', + 'ppc mac' => 'Power PC Mac', + 'freebsd' => 'FreeBSD', + 'ppc' => 'Macintosh', + 'linux' => 'Linux', + 'debian' => 'Debian', + 'sunos' => 'Sun Solaris', + 'beos' => 'BeOS', + 'apachebench' => 'ApacheBench', + 'aix' => 'AIX', + 'irix' => 'Irix', + 'osf' => 'DEC OSF', + 'hp-ux' => 'HP-UX', + 'netbsd' => 'NetBSD', + 'bsdi' => 'BSDi', + 'openbsd' => 'OpenBSD', + 'gnu' => 'GNU/Linux', + 'unix' => 'Unknown Unix OS' + ); + + +// The order of this array should NOT be changed. Many browsers return +// multiple browser types so we want to identify the sub-type first. +$browsers = array( + 'Flock' => 'Flock', + 'Chrome' => 'Chrome', + 'Opera' => 'Opera', + 'MSIE' => 'Internet Explorer', + 'Internet Explorer' => 'Internet Explorer', + 'Shiira' => 'Shiira', + 'Firefox' => 'Firefox', + 'Chimera' => 'Chimera', + 'Phoenix' => 'Phoenix', + 'Firebird' => 'Firebird', + 'Camino' => 'Camino', + 'Netscape' => 'Netscape', + 'OmniWeb' => 'OmniWeb', + 'Safari' => 'Safari', + 'Mozilla' => 'Mozilla', + 'Konqueror' => 'Konqueror', + 'icab' => 'iCab', + 'Lynx' => 'Lynx', + 'Links' => 'Links', + 'hotjava' => 'HotJava', + 'amaya' => 'Amaya', + 'IBrowse' => 'IBrowse' + ); + +$mobiles = array( + // legacy array, old values commented out + 'mobileexplorer' => 'Mobile Explorer', +// 'openwave' => 'Open Wave', +// 'opera mini' => 'Opera Mini', +// 'operamini' => 'Opera Mini', +// 'elaine' => 'Palm', + 'palmsource' => 'Palm', +// 'digital paths' => 'Palm', +// 'avantgo' => 'Avantgo', +// 'xiino' => 'Xiino', + 'palmscape' => 'Palmscape', +// 'nokia' => 'Nokia', +// 'ericsson' => 'Ericsson', +// 'blackberry' => 'BlackBerry', +// 'motorola' => 'Motorola' + + // Phones and Manufacturers + 'motorola' => "Motorola", + 'nokia' => "Nokia", + 'palm' => "Palm", + 'iphone' => "Apple iPhone", + 'ipad' => "iPad", + 'ipod' => "Apple iPod Touch", + 'sony' => "Sony Ericsson", + 'ericsson' => "Sony Ericsson", + 'blackberry' => "BlackBerry", + 'cocoon' => "O2 Cocoon", + 'blazer' => "Treo", + 'lg' => "LG", + 'amoi' => "Amoi", + 'xda' => "XDA", + 'mda' => "MDA", + 'vario' => "Vario", + 'htc' => "HTC", + 'samsung' => "Samsung", + 'sharp' => "Sharp", + 'sie-' => "Siemens", + 'alcatel' => "Alcatel", + 'benq' => "BenQ", + 'ipaq' => "HP iPaq", + 'mot-' => "Motorola", + 'playstation portable' => "PlayStation Portable", + 'hiptop' => "Danger Hiptop", + 'nec-' => "NEC", + 'panasonic' => "Panasonic", + 'philips' => "Philips", + 'sagem' => "Sagem", + 'sanyo' => "Sanyo", + 'spv' => "SPV", + 'zte' => "ZTE", + 'sendo' => "Sendo", + + // Operating Systems + 'symbian' => "Symbian", + 'SymbianOS' => "SymbianOS", + 'elaine' => "Palm", + 'palm' => "Palm", + 'series60' => "Symbian S60", + 'windows ce' => "Windows CE", + + // Browsers + 'obigo' => "Obigo", + 'netfront' => "Netfront Browser", + 'openwave' => "Openwave Browser", + 'mobilexplorer' => "Mobile Explorer", + 'operamini' => "Opera Mini", + 'opera mini' => "Opera Mini", + + // Other + 'digital paths' => "Digital Paths", + 'avantgo' => "AvantGo", + 'xiino' => "Xiino", + 'novarra' => "Novarra Transcoder", + 'vodafone' => "Vodafone", + 'docomo' => "NTT DoCoMo", + 'o2' => "O2", + + // Fallback + 'mobile' => "Generic Mobile", + 'wireless' => "Generic Mobile", + 'j2me' => "Generic Mobile", + 'midp' => "Generic Mobile", + 'cldc' => "Generic Mobile", + 'up.link' => "Generic Mobile", + 'up.browser' => "Generic Mobile", + 'smartphone' => "Generic Mobile", + 'cellphone' => "Generic Mobile" + ); + +// There are hundreds of bots but these are the most common. +$robots = array( + 'googlebot' => 'Googlebot', + 'msnbot' => 'MSNBot', + 'slurp' => 'Inktomi Slurp', + 'yahoo' => 'Yahoo', + 'askjeeves' => 'AskJeeves', + 'fastcrawler' => 'FastCrawler', + 'infoseek' => 'InfoSeek Robot 1.0', + 'lycos' => 'Lycos' + ); + +/* End of file user_agents.php */ +/* Location: ./application/config/user_agents.php */ \ No newline at end of file diff --git a/application/controllers/contoh hasil.txt b/application/controllers/contoh hasil.txt new file mode 100644 index 0000000..1e2dd35 --- /dev/null +++ b/application/controllers/contoh hasil.txt @@ -0,0 +1,106 @@ +//print_r($data) +Array ( +[province] => Jawa Barat +[city] => Bandung +[method] => Disuruh +[staffofscene] => GM +[customername] => Tarjo +[ind/comp] => Individual +[head_address] => PGA +[head_phone] => 123 +[branch_address] => Sukapura +[branch_phone] => 456 +[cp_name] => Azhar +[cp_phone] => 789 +[nature_bisnis] => Transportation,Minning,Expedition/Courier,Angkot +[loads] => Materials,Passenger,Soil,Orang +[destinations] => Dayeuh Kolot +[road_condition_good] => 60 +[road_condition_toll] => 10 +[road_condition_bad] => 70 +[road_condition_other] => 20 +[tire_brands] => Goodyear,Dunlop,Maxxis,Swallow +[tire_purchases] => Retreads +[tire_types] => Radial +[mileage_method] => Estimates +[mileage_front] => 300 +[mileage_rear] => 100 +[mileage_detail] => Mati +[purchase_method] => Estimates +[psi_front] => 230 +[condition_front] => +[psi_rear] => 330 +[otr] => Mampus +[problem] => Gak bisa jalan +) +//post() + Array ( + [cdProvince] => Jawa Barat + [cdKota] => Bandung + [rbCd] => Disuruh + [cdSos] => GM + [cdCusName] => Tarjo + [rbCd2] => Individual + [cdOffice] => PGA + [cdTelp] => 123 + [cdBranch] => Sukapura + [cdTelp2] => 456 + [cdcpname] => Azhar + [cdcpphone] => 789 + [cdCb_1] => Transportation + [cdCb_3] => Minning + [cdCb_4] => Expedition/Courier + [cdCb_5] => Angkot + [vdTr4] => + [vdTr6] => + [vdTr10] => + [vdLt6] => + [vdLt8] => + [vdLt10] => + [vdLt12] => + [vdLt14] => + [vdLt18] => + [vdLtot] => + [vdQtrType] => + [vdQtrQty] => + [vdQtrTyre] => + [vdQtrType2] => + [vdQtrQty2] => + [vdQtrTyre2] => + [vdCb_1] => Materials + [vdCb_2] => Passenger + [vdCb_4] => Soil + [vdCb_6] => Orang + [vdTr4wt] => + [vdTr6wt] => + [vdTr10wt] => + [vdLt6wt] => + [vdLt8wt] => + [vdLt10wt] => + [vdLt12wt] => + [vdLt14wt] => + [vdLt18wt] => + [vdLtotwt] => + [vdDest] => Dayeuh Kolot + [vdgoro] => 60 + [vdtoro] => 10 + [vdbaro] => 70 + [vdothers] => 20 + [tpCb_2] => Goodyear + [tpCb_5] => Dunlop + [tpCb_11] => Maxxis + [tpCb_14] => Swallow + [tpCb2_2] => Retreads + [tpCb3_4] => Radial + [trRb] => Estimates + [trmfront] => 300 + [trmrear] => 100 + [trmdetails] => Mati + [trfpsi] => 230 + [cb31] => Estimates + [trrpsi] => 330 + [cb3] => Actual + [trotr] => Mampus + [trproblem] => Gak bisa jalan + [send] => Submit + ) \ No newline at end of file diff --git a/application/controllers/form.php b/application/controllers/form.php new file mode 100644 index 0000000..cc23cea --- /dev/null +++ b/application/controllers/form.php @@ -0,0 +1,558 @@ +load->model('M_form'); + } + + function index() + { + if($this->auth->CI->session->userdata('is_log_in')){ + $this->load->view('vForm2'); + } + else{ + $this->load->view('vlogin'); + } + $array_items = array('status' => '', 'tipe' => '', 'message' => ''); + $this->session->unset_userdata($array_items); + } + + //view form untuk admin + function view_form($action,$id) + { + $data['action']=$action; + //$data['form']=$this->M_form->getVisit($id); + $data['id']= $id; + $this->load->view('vReview', $data); + } + + //get + function getDataAjax($id) + { + //$id = 7; + $data['customer'] = $this->M_form->getCust($id); + $data['visit'] = $this->M_form->getVisit($id); + $data['vehicle'] = $this->M_form->getVehicle($id); + $data['purchase'] = $this->M_form->getPurchase($id); + $data['recommendation'] = $this->M_form->getRecommendation($id); + $data['pictures'] = $this->M_form->getPictures($id); + + echo JSON_ENCODE($data); + } + + //load customer name + function searchcustomer($clu) + { + $data = $this->M_form->searchcustomer($clu); + echo JSON_ENCODE($data); + } + + //update status isApprove form + function isApprove($id) + { + $cds = array ( + '1' => $this->input->POST('modalcb1'), + '2' => $this->input->POST('modalcb2'), + '3' => $this->input->POST('modalcb3') + ); + $cds = array_filter($cds, 'strlen'); + $cds = implode(',' ,$cds); + $data = array ( + 'id_customer' => $this->input->POST('ID'), + 'tier' => $this->input->POST('tier'), + 'customer_data_status' => $cds, + 'isApprove' => 1 + ); + $this->M_form->isApprove($data, $id); + $notif = array( + 'status' => '1', + 'tipe' => 'alert-success', + 'message' => 'Well Done | Form is approved' + ); + $this->session->set_userdata($notif); + redirect('user','refresh'); + } + + //updateform + function updateform($id) + { + $notif = array( + 'status' => '1', + 'tipe' => 'alert-success', + 'message' => 'Well Done | Form Updated' + ); + $this->session->set_userdata($notif); + redirect('user','refresh'); + } + + //submit form + function form_submit() + { + //customer + $datacustomer = array ( + 'id' => '', + 'id_user' => '', + 'nama' => $this->input->POST('cdCusName'), + 'tipe' => $this->input->POST('rbCd2') + ); + + //visit + $nature_bisnis = array ( + '1' => $this->input->POST('cdCb_1'), + '2' => $this->input->POST('cdCb_2'), + '3' => $this->input->POST('cdCb_3'), + '4' => $this->input->POST('cdCb_4'), + '5' => $this->input->POST('cdCb_5'), + '6' => $this->input->POST('cdCb_6'), + '7' => $this->input->POST('cdCb_7') + ); + $nature_bisnis = array_filter($nature_bisnis, 'strlen'); + $nature_bisnis = implode(',' ,$nature_bisnis); + + $type_of_loads =""; + $type_of_loads = array ( + '1' => $this->input->POST('vdCb_1'), + '2' => $this->input->POST('vdCb_2'), + '3' => $this->input->POST('vdCb_3'), + '4' => $this->input->POST('vdCb_4'), + '5' => $this->input->POST('vdCb_5'), + '6' => $this->input->POST('vdCb_6') + ); + $type_of_loads = array_filter($type_of_loads, 'strlen'); + $type_of_loads = implode(',' ,$type_of_loads); + + $tyre_brands = array ( + '1' => $this->input->POST('tpCb_1'), + '2' => $this->input->POST('tpCb_2'), + '3' => $this->input->POST('tpCb_3'), + '4' => $this->input->POST('tpCb_4'), + '5' => $this->input->POST('tpCb_5'), + '6' => $this->input->POST('tpCb_6'), + '7' => $this->input->POST('tpCb_7'), + '8' => $this->input->POST('tpCb_8'), + '9' => $this->input->POST('tpCb_9'), + '10' => $this->input->POST('tpCb_10'), + '11' => $this->input->POST('tpCb_11'), + '12' => $this->input->POST('tpCb_12'), + '13' => $this->input->POST('tpCb_13'), + '14' => $this->input->POST('tpCb_14'), + '15' => $this->input->POST('tpCb_15') + ); + $tyre_brands = array_filter($tyre_brands, 'strlen'); + $tyre_brands = implode(',' ,$tyre_brands); + + $tyre_purchase = array ( + '1' => $this->input->POST('tpCb2_1'), + '2' => $this->input->POST('tpCb2_2') + ); + $tyre_purchase = array_filter($tyre_purchase, 'strlen'); + $tyre_purchase = implode(',' ,$tyre_purchase); + + $tire_types = array ( + '1' => $this->input->POST('tpCb3_1'), + '2' => $this->input->POST('tpCb3_2'), + '3' => $this->input->POST('tpCb3_3'), + '4' => $this->input->POST('tpCb3_4') + ); + $tire_types = array_filter($tire_types, 'strlen'); + $tire_types = implode(',' ,$tire_types); + + $cond_front = array ( + '1' => $this->input->POST('cb31'), + '2' => $this->input->POST('cb32') + ); + $cond_front = array_filter($cond_front, 'strlen'); + $cond_front = implode(',' ,$cond_front); + + $cond_rear = array ( + '1' => $this->input->POST('cb41'), + '2' => $this->input->POST('cb42') + ); + $cond_rear = array_filter($cond_rear, 'strlen'); + $cond_rear = implode(',' ,$cond_rear); + + if ($this->input->POST('rbCd')=="Other")$method = $this->input->POST('rbCdO'); + else $method = $this->input->POST('rbCd'); + + $datavisit = array ( + 'id' => '', + 'longitude' => '', + 'latitude' => '', + 'province' => $this->input->POST('cdProvince'), + 'kota' => $this->input->POST('cdKota'), + 'date_visit' => date('Y-m-d H:j:s'), + 'id_staff' => '', + 'id_customer' => '', + 'visit_status' => $method, + 'head_address' => $this->input->POST('cdOffice'), + 'head_phone' => $this->input->POST('cdTelp'), + 'branch_address' => $this->input->POST('cdBranch'), + 'branch_phone' => $this->input->POST('cdTelp2'), + 'cp_name' => $this->input->POST('cdcpname'), + 'cp_phone' => $this->input->POST('cdcpphone'), + 'nature_bisnis' => $nature_bisnis, + 'loads' => $type_of_loads, + 'destination' => $this->input->POST('vdDest'), + 'road_condition_good' => $this->input->POST('vdgoro'), + 'road_condition_toll' => $this->input->POST('vdtoro'), + 'road_condition_bad' => $this->input->POST('vdbaro'), + 'road_condition_other' => $this->input->POST('vdothers'), + 'tire_brands' => $tyre_brands, + 'tire_purchases' => $tyre_purchase, + 'tire_types' => $tire_types, + 'tire_other' => '', + 'mileage_method' => $this->input->POST('trRb'), + 'mileage_front' => $this->input->POST('trmfront'), + 'mileage_rear' => $this->input->POST('trmrear'), + 'mileage_detail' => $this->input->POST('trmdetails'), + 'purchase_method' => $this->input->POST('trRb2'), + 'purchase_number' => $this->input->POST(''), + 'psi_front' => $this->input->POST('trfpsi'), + 'condition_front' => $cond_rear, + 'psi_rear' => $this->input->POST('trrpsi'), + 'condition_rear' => $cond_front, + 'otr' => $this->input->POST('trotr'), + 'problem' => $this->input->POST('trproblem'), + 'notes' => '', + 'pictures' => '', + 'sender' => $this->input->POST('cdSos'), + 'customer' => $this->input->POST('cdCusName'), + 'tier' => '', + 'customer_data_status' => '', + 'qty' => '', + 'category' => '' + ); + + //customer vehicle + $datavehicle = ''; + $i = 0; + if ($this->input->POST('vdTr4')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Light', + 'qty' => $this->input->POST('vdTr4'), + 'total_tire' => '4', + 'load_weight' => $this->input->POST('vdTr4wt') + ); + $i++; + } + if ($this->input->POST('vdTr6')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Light', + 'qty' => $this->input->POST('vdTr6'), + 'total_tire' => '6', + 'load_weight' => $this->input->POST('vdTr6wt') + ); + $i++; + } + if ($this->input->POST('vdTr10')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Light', + 'qty' => $this->input->POST('vdTr10'), + 'total_tire' => '10', + 'load_weight' => $this->input->POST('vdTr10wt') + ); + $i++; + } + if ($this->input->POST('vdLt6')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Normal', + 'qty' => $this->input->POST('vdLt6'), + 'total_tire' => '6', + 'load_weight' => $this->input->POST('vdLt6wt') + ); + $i++; + } + if ($this->input->POST('vdLt8')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Normal', + 'qty' => $this->input->POST('vdLt8'), + 'total_tire' => '8', + 'load_weight' => $this->input->POST('vdLt8wt') + ); + $i++; + } + if ($this->input->POST('vdLt10')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Normal', + 'qty' => $this->input->POST('vdLt10'), + 'total_tire' => '10', + 'load_weight' => $this->input->POST('vdLt10wt') + ); + $i++; + } + if ($this->input->POST('vdLt12')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Normal', + 'qty' => $this->input->POST('vdLt12'), + 'total_tire' => '12', + 'load_weight' => $this->input->POST('vdLt12wt') + ); + $i++; + } + if ($this->input->POST('vdLt14')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Normal', + 'qty' => $this->input->POST('vdLt14'), + 'total_tire' => '14', + 'load_weight' => $this->input->POST('vdLt14wt') + ); + $i++; + } + if ($this->input->POST('vdLt18')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Normal', + 'qty' => $this->input->POST('vdLt18'), + 'total_tire' => '18', + 'load_weight' => $this->input->POST('vdLt18wt') + ); + $i++; + } + if ($this->input->POST('vdLtot')!='') + { + $datavehicle[$i] = array ( + 'id' => '', + 'id_visit' => '', + 'category' => 'Truck', + 'type' => 'Normal', + 'qty' => $this->input->POST('vdLtot'), + 'total_tire' => '-1', + 'load_weight' => $this->input->POST('vdLtotwt') + ); + $i++; + } + + /* + 'otr1Type' => $this->input->POST('vdQtrType'), + 'otr1Qty' => $this->input->POST('vdQtrQty'), + 'otr1Tyre' => $this->input->POST('vdQtrTyre') + */ + + //purchase + $countpurchase = 0; + $purchase = array ( + 'MRFp' => $this->input->POST('pattern'), + 'MRFs' => $this->input->POST('size'), + 'MRFq' => $this->input->POST('qty'), + 'OTHb' => $this->input->POST('obrand'), + 'OTHp' => $this->input->POST('opattern'), + 'OTHs' => $this->input->POST('osize'), + 'OTHq' => $this->input->POST('oqty') + ); + //$mrfc = $this->input->POST('MRFcount'); + $count = count($purchase['MRFp']); + for ($k = 0 ; $k < $count ; $k++) + { + $datapurchase[$countpurchase] = array ( + 'id' => '', + 'id_visit' => '', + 'brand' => 'MRF', + 'pattern' => $purchase['MRFp'][$k], + 'size' => $purchase['MRFs'][$k], + 'qty' => $purchase['MRFq'][$k] + ); + $countpurchase++; + } + + $count2 = count($purchase['OTHp']); + $v = 0; + for ($n = 0 ; $n < $count2 ; $n++) + { + $datapurchase[$countpurchase] = array ( + 'id' => '', + 'id_visit' => '', + 'brand' => $purchase['OTHb'][$v], + 'pattern' => $purchase['OTHp'][$n], + 'size' => $purchase['OTHs'][$n], + 'qty' => $purchase['OTHq'][$n] + ); + $countpurchase++; + $v++; + } + + //recommendation + + $countrcm = 0; + $recommend = array ( + 'pattern' => $this->input->POST('rpattern'), + 'size' => $this->input->POST('rsize'), + 'remark' => $this->input->POST('rremark') + ); + $count3 = count($recommend['pattern']);; + for ($n = 0 ; $n < $count3 ; $n++) + { + $datarecommended[$countrcm] = array ( + 'id' => '', + 'id_visit' => '', + 'pattern' => $recommend['pattern'][$n], + 'size' => $recommend['size'][$n], + 'remark' => $recommend['remark'][$n], + ); + $countrcm++; + } + + + $data = array( + 'customer' => $datacustomer, + 'visit' => $datavisit, + 'vehicle' => $datavehicle, + 'purchase' => $datapurchase, + 'recommendation' => $datarecommended + ); + //$this->submit_form($data); + echo JSON_ENCODE($data); + } + + //insert + function submit_form($data) + { + //customer + $idc = 4; + $idc = $this->M_form->insertcustomer($data['customer']); + + //visit + $data['visit']['id_customer'] = $idc; + $idv = 3; + $idv = $this->M_form->insertvisit($data['visit']); + + + //vehicle + for ($i=0;$iM_form->insertvehicle($data['vehicle'][$j]); + } + + //purchase + for ($i=0;$iM_form->insertpurchase($data['purchase'][$j]); + } + + //recommendation + for ($i=0;$iM_form->insertrecommended($data['recommendation'][$j]); + } + + $notif = array( + 'status' => '1', + 'tipe' => 'alert-success', + 'message' => 'Well Done | Form is Submitted' + ); + $this->session->set_userdata($notif); + redirect('user','refresh'); + //echo JSON_ENCODE($data); + } + + + function addSellout() + { + $data = array ( + 'id_customer' => $this->input->POST('ID'), + 'customer' => $this->input->POST('customer'), + 'bulan' => $this->input->POST('bulan'), + 'tahun' => $this->input->POST('tahun'), + 'qty' => $this->input->POST('qty') + ); + $this->M_form->newSellout($data); + $notif = array( + 'status' => '1', + 'tipe' => 'alert-success', + 'message' => 'Well Done | Selling out added' + ); + $this->session->set_userdata($notif); + redirect('user','refresh'); + } + + function addVolume() + { + $data = array ( + 'id' => '', + 'dealer' => $this->input->POST('dealer'), + 'area' => $this->input->POST('area'), + 'region' => $this->input->POST('region'), + 'province' => $this->input->POST('province'), + 'date' => $this->input->POST('date'), + 'target' => $this->input->POST('target'), + 'previous_stock'=> $this->input->POST('prevstock'), + 'actual' => $this->input->POST('actual'), + 'sellout' => $this->input->POST('sellout'), + 'order' => $this->input->POST('order'), + 'pattern' => $this->input->POST('pattern') + ); + $data['current_stock'] = $data['previous_stock']+$data['actual']-$data['sellout']; + $pattern = $this->input->POST('pattern'); + if(($pattern== ("7.50-16 M77")) or ($pattern==("7.50-16 SLUG")) or ($pattern==("7.50-16 SM95"))) + { + $data['category'] = 'Light Truck'; + } + else $data['category'] = 'Truck'; + $data['service_level'] = $data['actual'] / $data['order']; + + //echo JSON_ENCODE($data); + $this->M_form->newVolume($data); + + $notif = array( + 'status' => '1', + 'tipe' => 'alert-success', + 'message' => 'Well Done | Volume added' + ); + $this->session->set_userdata($notif); + redirect('user','refresh'); + } + + function loadwilayah() + { + $data = $this->M_form->getwilayah(); + echo JSON_ENCODE($data); + } +} \ No newline at end of file diff --git a/application/controllers/index.html b/application/controllers/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/controllers/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/controllers/user.php b/application/controllers/user.php new file mode 100644 index 0000000..c68761d --- /dev/null +++ b/application/controllers/user.php @@ -0,0 +1,149 @@ +load->model('M_form'); + } + + function index() + { + if($this->auth->CI->session->userdata('is_log_in')) + { + if($this->auth->CI->session->userdata('role')=='Admin') + { + $this->load->view('vAdmin'); + } + else + { + redirect('form'); + } + }else + { + //load halaman login + $this->load->view('vLogin'); + } + $array_items = array('status' => '', 'tipe' => '', 'message' => ''); + $this->session->unset_userdata($array_items); + } + + function loadform() + { + if ($this->cekLogin()) + { + $data['form_saved'] = $this->M_form->getFormSaved(); + $data['form_pending'] = $this->M_form->getFormPending(); + $this->load->view('vAdminForm',$data); + } + else + { + //$this->load->view('vLogin'); + } + } + + function loadstaff() + { + $data['user'] = $this->M_form->getUser(); + $this->load->view('vAdminStaff',$data); + } + + function loadsellingout() + { + $data['sellout'] = $this->M_form->getSellout(); + $this->load->view('vAdminSellingout',$data); + } + + function loadvolume() + { + $data['volume'] = $this->M_form->getVolume(); + $this->load->view('vAdminVolume',$data); + } + + function login_auth() + { + $username = $this->input->post('username'); + $password = $this->input->post('password'); + $success = $this->auth->do_login($username,$password); + if($success) + { + $notif = array( + 'status' => '1', + 'tipe' => 'alert-info', + 'message' => 'Welcome back '.$this->auth->CI->session->userdata('nama') + ); + $this->session->set_userdata($notif); + redirect('user'); + } + else + { + //wrong log in + $data['login_info'] = "Maaf, username dan password salah!"; + $this->load->view('vLogin',$data); + } + } + + function logout() + { + //$this->auth->CI->session->unset_userdata(); + $this->auth->CI->session->sess_destroy(); + redirect('user'); + } + + function insert_user() + { + $datauser = array ( + 'nama' => $this->input->post('nama'), + 'username' => $this->input->post('username'), + 'password' => md5($this->input->post('password')), + 'role' => $this->input->post('role') + ); + $cek = $this->M_form->newuser($datauser); + if ($cek) + { + $notif = array( + 'status' => '1', + 'tipe' => 'alert-success', + 'message' => 'Well Done | Sales baru berhasil diinput' + ); + $this->session->set_userdata($notif); + redirect('user'); + } + else + { + $notif = array( + 'status' => '1', + 'tipe' => 'alert-error', + 'message' => 'Well Done | Sales baru berhasil diinput' + ); + $this->session->set_userdata($notif); + redirect('user'); + } + } + + function delete_user($id) + { + $id = $this->M_form->delete_user($id); + + redirect('user'); + } + + function cekLogin() + { + if($this->auth->CI->session->userdata('is_log_in')) + { + if($this->auth->CI->session->userdata('role')=='Admin') + { + return true; + } + else + { + redirect('Form'); + } + }else + { + //load halaman login + return false; + } + } +} \ No newline at end of file diff --git a/application/core/index.html b/application/core/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/core/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/errors/error_404.php b/application/errors/error_404.php new file mode 100644 index 0000000..792726a --- /dev/null +++ b/application/errors/error_404.php @@ -0,0 +1,62 @@ + + + +404 Page Not Found + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/errors/error_db.php b/application/errors/error_db.php new file mode 100644 index 0000000..b396cda --- /dev/null +++ b/application/errors/error_db.php @@ -0,0 +1,62 @@ + + + +Database Error + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/errors/error_general.php b/application/errors/error_general.php new file mode 100644 index 0000000..fd63ce2 --- /dev/null +++ b/application/errors/error_general.php @@ -0,0 +1,62 @@ + + + +Error + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/errors/error_php.php b/application/errors/error_php.php new file mode 100644 index 0000000..f085c20 --- /dev/null +++ b/application/errors/error_php.php @@ -0,0 +1,10 @@ +
+ +

A PHP Error was encountered

+ +

Severity:

+

Message:

+

Filename:

+

Line Number:

+ +
\ No newline at end of file diff --git a/application/errors/index.html b/application/errors/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/errors/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/helpers/index.html b/application/helpers/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/helpers/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/hooks/index.html b/application/hooks/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/hooks/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/index.html b/application/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/language/english/index.html b/application/language/english/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/language/english/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/libraries/auth.php b/application/libraries/auth.php new file mode 100644 index 0000000..6a9ce24 --- /dev/null +++ b/application/libraries/auth.php @@ -0,0 +1,62 @@ +CI =& get_instance(); + } + // untuk validasi login + function do_login($username,$password) + { + // cek di database, ada ga? + $this->CI->db->from('user'); + $this->CI->db->where('username',$username); + $this->CI->db->where('password=("'.md5($password).'")','',false); + $result = $this->CI->db->get(); + if($result->num_rows() == 0) + { + // username dan password tsb tidak ada + return false; + } + else + { + // ada, maka ambil informasi dari database + $userdata = $result->row(); + if($userdata->role == "admin") $rule = 'Admin'; + else $rule = 'Sales'; + $session_data = array( + 'username' => $userdata->username, + 'nama' => $userdata->nama, + 'role' => $rule, + 'is_log_in' => TRUE + ); + // buat session + $this->CI->session->set_userdata($session_data); + return true; + } + } + // untuk mengecek apakah user sudah login/belum + function is_logged_in() + { + if($this->CI->session->userdata('user_id') == '') + { + return false; + } + return true; + } + // untuk validasi di setiap halaman yang mengharuskan authentikasi + function restrict() + { + if($this->is_logged_in() == false) + { + redirect('home/login'); + } + } +} \ No newline at end of file diff --git a/application/libraries/index.html b/application/libraries/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/libraries/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/logs/index.html b/application/logs/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/logs/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/models/M_form.php b/application/models/M_form.php new file mode 100644 index 0000000..6f46699 --- /dev/null +++ b/application/models/M_form.php @@ -0,0 +1,211 @@ +db->insert('customer',$data); + return $this->db->insert_id(); + } + + function insertvisit($data) + { + $this->db->insert('visit',$data); + return $this->db->insert_id(); + } + + function insertvehicle($data) + { + $this->db->insert('customer_vehicle',$data); + return $this->db->affected_rows(); + } + + function insertrecommended($data) + { + $this->db->insert('recommendation',$data); + return $this->db->affected_rows(); + } + + function insertpurchase($data) + { + $this->db->insert('purchase',$data); + return $this->db->affected_rows(); + } + + function getFormSaved() + { + $query=$this->db->query("SELECT * FROM `visit` WHERE `isApprove` = '1' ORDER BY id DESC"); + return $query->result(); + } + + function getFormPending() + { + $query=$this->db->query("SELECT * FROM `visit` WHERE `isApprove` = '0' ORDER BY id DESC"); + return $query->result(); + } + + function getVisit($id) + { + $q="SELECT * FROM visit WHERE id='$id'"; + $query=$this->db->query($q); + return $query->row(); + } + + function getCust($id) + { + $sql="SELECT * FROM customer WHERE id = (SELECT id_customer FROM visit WHERE id='$id')"; + $query=$this->db->query($sql); + return $query->row(); + } + + function getVehicle($id) + { + $sql="SELECT * FROM customer_vehicle WHERE id_visit='$id'"; + //$query=$this->db->query($q); + $sql = mysql_query($sql); + while ($array = mysql_fetch_assoc($sql)) { + $rs[] = $array; + } + if (empty($rs)) + { + $rs = ''; + } + return $rs; + //return $query->row(); + } + + function getPurchase($id) + { + $sql="SELECT * FROM purchase WHERE id_visit='$id'"; + //$query=$this->db->query($q); + $sql = mysql_query($sql); + while ($array = mysql_fetch_assoc($sql)) { + $rs[] = $array; + } + if (empty($rs)) + { + $rs = ''; + } + return $rs; + //return $query->row(); + } + + function getRecommendation($id) + { + $sql="SELECT * FROM recommendation WHERE id_visit='$id'"; + //$query=$this->db->query($q); + $sql = mysql_query($sql); + while ($array = mysql_fetch_assoc($sql)) { + $rs[] = $array; + } + if (empty($rs)) + { + $rs = ''; + } + return $rs; + //return $query->row(); + } + + function getPictures($id) + { + $sql="SELECT * FROM pictures WHERE id_visit='$id'"; + //$query=$this->db->query($q); + $sql = mysql_query($sql); + while ($array = mysql_fetch_assoc($sql)) { + $rs[] = $array; + } + if (empty($rs)) + { + $rs = ''; + } + return $rs; + } + + function isApprove($data, $id) + { + + $idc = $this->getCustomer($id); + $this->updateCustomer($idc['id_customer'],$data['id_customer']); + $this->db->where('id', $id); + $this->db->update('visit', $data); + } + + function getCustomer($id) + { + $sql="SELECT id_customer FROM visit WHERE id='$id'"; + $sql = mysql_query($sql); + //echo $sql; + $rs = mysql_fetch_assoc($sql); + return $rs; + } + + function updateCustomer($idc,$id) + { + $data = array ( + 'id_customer' => $id + ); + $this->db->where('id', $idc); + $this->db->update('customer', $data); + } + + function searchcustomer($clue) + { + $sql="SELECT id,nama FROM customer WHERE nama like '%$clue%'"; + //$query=$this->db->query($q); + $sql = mysql_query($sql); + while ($array = mysql_fetch_assoc($sql)) { + $rs[] = $array; + } + if (empty($rs)) + { + $rs = ''; + } + return $rs; + } + + function newUser($data) + { + $this->db->insert('user',$data); + return $this->db->affected_rows(); + } + + function getUser() + { + $query=$this->db->query("SELECT * FROM `user`"); + return $query->result(); + } + + function delete_user($id) + { + $query=$this->db->query("DELETE FROM user WHERE username='$id'"); + } + + function getSellout() + { + $query=$this->db->query("SELECT * FROM `sellingout`"); + return $query->result(); + } + + function newSellout($data) + { + $this->db->insert('sellingout',$data); + return $this->db->affected_rows(); + } + + function getVolume() + { + $query=$this->db->query("SELECT * FROM `volume`"); + return $query->result(); + } + + function newVolume($data) + { + $this->db->insert('volume',$data); + return $this->db->affected_rows(); + } + + function getWilayah() + { + $query=$this->db->query("SELECT * FROM `wilayah`"); + return $query->result(); + } +} \ No newline at end of file diff --git a/application/models/index.html b/application/models/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/models/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/third_party/index.html b/application/third_party/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/third_party/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/views/admin/bAdmin.php b/application/views/admin/bAdmin.php new file mode 100644 index 0000000..0999b97 --- /dev/null +++ b/application/views/admin/bAdmin.php @@ -0,0 +1,185 @@ + + +Admin Page + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+ + session->userdata('status')=='1' ) + { + $tipe = $this->session->userdata('tipe'); + echo " +
+ + ".$this->session->userdata('message')." +
"; + } + ?> + +
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/application/views/bForm.php b/application/views/bForm.php new file mode 100644 index 0000000..2e50538 --- /dev/null +++ b/application/views/bForm.php @@ -0,0 +1,823 @@ + + + + + Form Customer + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + +
+
+
+ Contact Details +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ General Location +
+ + + +
+ Company Details +
+ + + + + +
+ + + +
+ + + +
+ +
+
+
+ Address / Phone no +
+ + + +
+ + + +
+ Contact Person +
+ + + +
+ Nature Business +
+ + + + + +
+ + + +
+
+

+
+
+ Vehicles Details +
+ + + + + + + + + + + + + + + + + + + +
Number of vehicles owned
+ + + + + + + + + + + + + + + + + +
Light TruckQTY
4 wheels + +
6 wheels + +
10 wheels + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TruckQTY
6 wheels + +
8 wheels + +
10 wheels + +
12 wheels + +
14 wheels + +
18 wheels + +
Other + +
+
QTR
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Load and Speed Details
Type of Load
+ + + + + +
+ + + + + +
Average Weight of Loads
+ + + + + + + + + + + + + + + + + +
TruckWt
4 wheels + +
6 wheels + +
10 wheels + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Light TrWt
6 wheels + +
8 wheels + +
10 wheels + +
12 wheels + +
14 wheels + +
18 wheels + +
Other + +
+
Points of Origin Destination
Driving Condition
+
+ + % +
+
+ + % +
+
+
+ + % +
+
+ + % +
+
+
+

+
+
+ Types +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Tyre Brands and Type +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + +
Type of Purchase
+ + + +
Type
+ + + + + + + +
+
+

+
+
+ Tyre Usages +
+
+
+
+ Milleage

+ + + +

+
+ + Km +


+
+ + Km +


+ + +
+
+ New Tyre Purchase per Month

+ + + +

+
+

+
+
+ Front Tyre

+

+ +    + + +
+
+ Rear Tyre

+

+ +    + + +
+


+
+

+ +
+
+
+

+
+
+ Recommendation +
+
+ + + + +
+
+

+
+
+ Upload Picture +
+
+ +

+
+

+ +
+
+
+ + +
+
+
+
+ +
+ +
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application/views/bHalamanAdmin.php b/application/views/bHalamanAdmin.php new file mode 100644 index 0000000..c7f5096 --- /dev/null +++ b/application/views/bHalamanAdmin.php @@ -0,0 +1,336 @@ + + +Admin Page + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+
+ session->userdata('status')=='1' ) + { + $tipe = $this->session->userdata('tipe'); + echo " +
+ + ".$this->session->userdata('message')." +
"; + } + ?> +
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Date/Time Sender Area Customer/Client Action
2013-05-27 16:25:39MarkJawa TengahOmdo +
date; ?>sender; ?>area; ?>customer; ?> + +
+
+
+ Tambah +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Date/Time Sender Area Customer/Client Action
1MarkJawa TengahOmdo + +
date; ?>sender; ?>area; ?>customer; ?> + +
+
+
+
+
+
+ +
+
+ Tambah + +

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Name Username Role Action
MarkMarkJawa Tengah + +
nama; ?>username; ?>role; ?> + +
+
+
+
+
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/application/views/bReview.php b/application/views/bReview.php new file mode 100644 index 0000000..a76bc7a --- /dev/null +++ b/application/views/bReview.php @@ -0,0 +1,828 @@ + + + + + Form Customer + + + + + + + + + + nature_bisnis); + $onature = end($nature_bisnis); // move the internal pointer to the end of the array + //$onature = key($nature_bisnis); + ?> + + + + + + + + + + + + + + + +
+
+ + + +
+ +
+
+
+ Contact Details +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ General Location +
+
+ + +
+
+
+ + +
+
+ Company Details +
+ + + + + +
+
+ + +
+
+
+ + +
+
+ + + +
+ +
+
+
+ Address / Phone no +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ Contact Person +
+
+ + +
+
+
+ + +
+
+ Nature Business +
+ + + + + +
+ + + +
+
+

+
+
+ Vehicles Details +
+ + + + + + + + + + + + + + + + + + + +
Number of vehicles owned
+ + + + + + + + + + + + + + + + + +
Light TruckQTY
4 wheels + +
6 wheels + +
10 wheels + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TruckQTY
6 wheels + +
8 wheels + +
10 wheels + +
12 wheels + +
14 wheels + +
18 wheels + +
Other + +
+
QTR
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Load and Speed Details
Type of Load
+ + + + + +
+ + + + + +
Average Weight of Loads
+ + + + + + + + + + + + + + + + + +
TruckWt
4 wheels + +
6 wheels + +
10 wheels + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Light TrWt
6 wheels + +
8 wheels + +
10 wheels + +
12 wheels + +
14 wheels + +
18 wheels + +
Other + +
+
Points of Origin Destination
Driving Condition
+
+ + + % +
+
+ + + % +
+
+
+ + + % +
+
+ + + % +
+
+
+

+
+
+ Types +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Tyre Brands and Type +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + +
Type of Purchase
+ + + +
Type
+ + + + + + + +
+
+

+
+
+ Tyre Usages +
+
+
+
+ Milleage

+ + + +

+
+ + Km +


+
+ + Km +


+ + +
+
+ New Tyre Purchase per Month

+ + + +

+
+

+
+
+ Front Tyre

+ +

+ +    + + +
+
+ Rear Tyre

+ +

+ +    + + +
+


+
+ +

+ +
+
+
+

+
+
+ Recommendation +
+
+

+
+
+ Picture +
+ +
+ + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/application/views/index.html b/application/views/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/application/views/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/views/vAdmin.php b/application/views/vAdmin.php new file mode 100644 index 0000000..09fa3f5 --- /dev/null +++ b/application/views/vAdmin.php @@ -0,0 +1,163 @@ + + +Admin Page + + + + + + + + + + + + + + + + + + +
+ + + +
+
+ + session->userdata('status')=='1' ) + { + $tipe = $this->session->userdata('tipe'); + echo " +
+ + ".$this->session->userdata('message')." +
"; + } + ?> + +
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/application/views/vAdminForm.php b/application/views/vAdminForm.php new file mode 100644 index 0000000..db0099c --- /dev/null +++ b/application/views/vAdminForm.php @@ -0,0 +1,94 @@ + +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Date/Time Sender Area Customer/Client Action
2013-05-27 16:25:39MarkJawa TengahSuprapto +
date_visit; ?>sender; ?>province; ?>customer; ?> + +
+
+
+ Tambah +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Date/Time Sender Area Customer/Client Action
2013-07-25 15:28:56MarkJawa TengahSumartoyo + +
date_visit; ?>sender; ?>province; ?>customer; ?> + +
+
+
\ No newline at end of file diff --git a/application/views/vAdminSellingout.php b/application/views/vAdminSellingout.php new file mode 100644 index 0000000..3740759 --- /dev/null +++ b/application/views/vAdminSellingout.php @@ -0,0 +1,178 @@ + +
+ +
+
+ Tambah +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Customer Date Quantity Action
everseikoJanuary 20135 + + +
customer; ?>bulan." ".$so->tahun; ?>qty; ?> + + +
+
+ + + \ No newline at end of file diff --git a/application/views/vAdminStaff.php b/application/views/vAdminStaff.php new file mode 100644 index 0000000..2a0b112 --- /dev/null +++ b/application/views/vAdminStaff.php @@ -0,0 +1,94 @@ + +
+ +
+
+ Tambah +

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Name Username Role Action
MarkMarkJawa Tengah + +
nama; ?>username; ?>role; ?> + +
+
+ + + + \ No newline at end of file diff --git a/application/views/vAdminVolume.php b/application/views/vAdminVolume.php new file mode 100644 index 0000000..cb32882 --- /dev/null +++ b/application/views/vAdminVolume.php @@ -0,0 +1,226 @@ + +
+ +
+
+ Tambah +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Dealaer Region Province Area Month Target Sellout Order Previous Stock Actual Current Stock Category Pattern Service Level
everseikoJawaJawa BaratBandungApril462775
dealer; ?>region; ?>province; ?>area; ?>date; ?>target; ?>sellout; ?>order; ?>previous_stock; ?>actual; ?>current_stock; ?>category; ?>pattern; ?>service_level; ?>
+
+ + + + \ No newline at end of file diff --git a/application/views/vForm2.php b/application/views/vForm2.php new file mode 100644 index 0000000..42bd8e5 --- /dev/null +++ b/application/views/vForm2.php @@ -0,0 +1,924 @@ + + + + + Form Customer + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ session->userdata('status')=='1' ) + { + $tipe = $this->session->userdata('tipe'); + echo " +
+ + ".$this->session->userdata('message')." +
"; + } + ?> + +
+
+
+
+
+ +
+ Contact Details + +
General Location
+ + + +
Company Details
+ + + +

+ + + +

+ + +

+ + +
Address / Phone no
+ + +

+ + +

+
Contact Person
+ + +

+
Nature Business
+ + + + + + + +
+ +
+
+ Vehicles Details + + + + + + + + + + + + + + + +
Number of vehicles owned
+ + + + + + + + + + + + + + + + + +
Light TruckQTY
4 wheels + +
6 wheels + +
10 wheels + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TruckQTY
6 wheels + +
8 wheels + +
10 wheels + +
12 wheels + +
14 wheels + +
18 wheels + +
Other + +
+
QTR
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Load and Speed Details
Type of Load
+ + + + + +
+ + + + + +
Average Weight of Loads
+ + + + + + + + + + + + + + + + + +
Light TruckWt
4 wheels + +
6 wheels + +
10 wheels + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TruckWt
6 wheels + +
8 wheels + +
10 wheels + +
12 wheels + +
14 wheels + +
18 wheels + +
Other + +
+
Points of Origin Destination
Driving Condition
+
+ + % +
+
+ + % +
+
+
+ + % +
+
+ + % +
+
+
+
+ +
+ Types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Tyre Brands and Type +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + +
Type of Purchase
+ + + +
Type
+ + + + + + + +
+
+ +
+ Tyre Usages +
+
+
+ Milleage

+ + +

+
+ + Km +


+
+ + Km +


+ + +
+
+ New Tyre Purchase per Month

+ + +

+ + +
+
+ + + + +
+
+ +
+
+
+ + + + + +
+
+ +

+
+

+
+
+ Front Tyre

+

+    + +
+
+ Rear Tyre

+

+    + +
+


+
+

+ +
+
+
+ +
+ Recommendation +
+
+ + + + +
+ +
+ +
+ + + +
+
+ + + +
+
+
+ +
+ Upload Picture +
+ +

+
+
+

+ +
+
+ +
+ Confirm +
+

+ +

+
+
+
+
+
+
+
+ + +
+
+ +
+ +
+

© Everseiko 2013

+
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/application/views/vLogin.php b/application/views/vLogin.php new file mode 100644 index 0000000..d83b22d --- /dev/null +++ b/application/views/vLogin.php @@ -0,0 +1,81 @@ + + + +Login + + + + + + + + + + + +
+ +
'; + } + ?> +
Login
+ + + + + + + + + + + \ No newline at end of file diff --git a/application/views/vReview.php b/application/views/vReview.php new file mode 100644 index 0000000..b5beed2 --- /dev/null +++ b/application/views/vReview.php @@ -0,0 +1,920 @@ + + + + + + Form Customer + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ +
+
+
+ Contact Details +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
General Location
+
+ + +
+
+
+ + +
+
Company Details
+ + + + + +
+
+ + +
+
+
+ + +
+
+ + + +
+
+
Address / Phone no
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
Contact Person
+
+ + +
+
+
+ + +
+
Nature Business
+ + + + + +
+ + + + + +
+ +
+
+

+
+
+ Vehicles Details +
+ + + + + + + + + + + +
Number of vehicles owned
+ + + + + + + + + + + + + + + + + +
Lt TruckQTY
4 wheels + +
6 wheels + +
10 wheels + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TruckQTY
6 wheels + +
8 wheels + +
10 wheels + +
12 wheels + +
14 wheels + +
18 wheels + +
Other + +
+
OTR
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Load and Speed Details
Type of Load
+ + + + + +
+ + + + + +
Average Weight of Loads
+ + + + + + + + + + + + + + + + + +
Lt TruckWt
4 wheels + +
6 wheels + +
10 wheels + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TruckWt
6 wheels + +
8 wheels + +
10 wheels + +
12 wheels + +
14 wheels + +
18 wheels + +
Other + +
+
Points of Origin Destination
Driving Condition
+
+ + + % +
+
+ + + % +
+
+
+ + + % +
+
+ + + % +
+
+
+

+
+
+ Types +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tyre Brands and Type
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + +
Type of Purchase
+ + + +
Type
+ + + + + + + +
+ +
+
+

+
+
+ Tyre Usages +
+
+
+
+ Milleage

+ + +

+
+ + Km +
+

+
+ + Km +


+ + + +
+
+ New Tyre Purchase per Month

+ + + + + + + + + + + + + + + + + +
Brand + +
MRF +
+ +
+
+ + +
Other +
+ +
+
+ + +
+

+
+
+
+
+
+ Front Tyre

+ +

+ +    + + +
+
+ Rear Tyre

+ +

+ +    + + +
+


+
+ +

+ +
+
+
+

+
+
+ Recommendation +
+
+ Pattern                           +     Size                 +                   Remark +
+
+
No Recommendation Available
+
+








+
+

+
+
+ Picture +
+
+ +
+ + + +
+ +
+
+ + + + + +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/asset/bootstrap/css/bootstrap-responsive.css b/asset/bootstrap/css/bootstrap-responsive.css new file mode 100644 index 0000000..09e88ce --- /dev/null +++ b/asset/bootstrap/css/bootstrap-responsive.css @@ -0,0 +1,1109 @@ +/*! + * Bootstrap Responsive v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.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: #777777; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: #777777; + -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: #999999; + } + .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: #111111; + } + .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: none; + -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: #111111; + border-bottom-color: #111111; + } + .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; + } +} diff --git a/asset/bootstrap/css/bootstrap-responsive.min.css b/asset/bootstrap/css/bootstrap-responsive.min.css new file mode 100644 index 0000000..f4ede63 --- /dev/null +++ b/asset/bootstrap/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.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}} diff --git a/asset/bootstrap/css/bootstrap.css b/asset/bootstrap/css/bootstrap.css new file mode 100644 index 0000000..43dc567 --- /dev/null +++ b/asset/bootstrap/css/bootstrap.css @@ -0,0 +1,6194 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.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: 0.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: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover, +a:focus { + color: #005580; + text-decoration: underline; +} + +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.img-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); +} + +.img-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: #999999; +} + +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: #999999; +} + +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 #eeeeee; +} + +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 #eeeeee; + border-bottom: 1px solid #ffffff; +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} + +blockquote small { + display: block; + line-height: 20px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + 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: #333333; + -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: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 15px; + color: #999999; +} + +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: #555555; + 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: #ffffff; + border: 1px solid #cccccc; + -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 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.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; + /* IE6-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; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 30px; +} + +select { + width: 220px; + background-color: #ffffff; + border: 1px solid #cccccc; +} + +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: #999999; + cursor: not-allowed; + background-color: #fcfcfc; + border-color: #cccccc; + -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: #999999; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} + +.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: #eeeeee; +} + +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 #ffffff; + background-color: #eeeeee; + 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; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/* Allow for input prepend/append in search forms */ + +.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 #dddddd; +} + +.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 #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + 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 #dddddd; +} + +.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; +} + +/* White icons with optional class, or on hover/focus/active states of certain elements */ + +.icon-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"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + width: 16px; + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + width: 16px; + background-position: -384px -120px; +} + +.icon-folder-open { + width: 16px; + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-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 #000000; + 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: #ffffff; + 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 #ffffff; +} + +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #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: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #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: #999999; +} + +.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; +} + +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + 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: #cccccc; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.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 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.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: #333333; + 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, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + *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: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.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: 0.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: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + *background-color: #0044cc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + border-color: #0044cc #0044cc #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: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} + +.btn-warning { + color: #ffffff; + 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: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + color: #ffffff; + 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: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + color: #ffffff; + 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: #ffffff; + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + color: #ffffff; + 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: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + *background-color: #222222; + background-image: -moz-linear-gradient(top, #444444, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + 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: #ffffff; + background-color: #222222; + *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: #0088cc; + 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: #333333; + 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: #0044cc; +} + +.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: #222222; +} + +.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: #ffffff; + border-bottom-color: #ffffff; +} + +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *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: #eeeeee; +} + +.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: #999999; + 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: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.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 #ffffff; +} + +.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: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: #555555; + cursor: default; + background-color: #ffffff; + 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: #ffffff; + background-color: #0088cc; +} + +.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: #0088cc; + border-bottom-color: #0088cc; +} + +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +/* move down carets for tabs */ + +.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: #555555; + border-bottom-color: #555555; +} + +.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: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.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: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: #999999; +} + +.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: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.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: #ffffff; +} + +.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: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.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: #ffffff; +} + +.nav > .disabled > a { + color: #999999; +} + +.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, #ffffff, #f2f2f2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); + background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); + background-image: linear-gradient(to bottom, #ffffff, #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: #777777; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .brand:hover, +.navbar .brand:focus { + text-decoration: none; +} + +.navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #777777; +} + +.navbar-link { + color: #777777; +} + +.navbar-link:hover, +.navbar-link:focus { + color: #333333; +} + +.navbar .divider-vertical { + height: 40px; + margin: 0 9px; + border-right: 1px solid #ffffff; + 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: #777777; + text-decoration: none; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + color: #333333; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #555555; + 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: #ffffff; + 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: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} + +.navbar .btn-navbar .icon-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 .icon-bar + .icon-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 #ffffff; + 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 #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: #555555; + background-color: #e5e5e5; +} + +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} + +.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: #555555; + border-bottom-color: #555555; +} + +.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, #222222, #111111); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); + background-image: -webkit-linear-gradient(top, #222222, #111111); + background-image: -o-linear-gradient(top, #222222, #111111); + background-image: linear-gradient(to bottom, #222222, #111111); + 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: #999999; + 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: #ffffff; +} + +.navbar-inverse .brand { + color: #999999; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover, +.navbar-inverse .navbar-link:focus { + color: #ffffff; +} + +.navbar-inverse .divider-vertical { + border-right-color: #222222; + border-left-color: #111111; +} + +.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: #ffffff; + background-color: #111111; +} + +.navbar-inverse .nav li.dropdown > a:hover .caret, +.navbar-inverse .nav li.dropdown > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} + +.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: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #515151; + border-color: #111111; + -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: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + 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: #ffffff; + 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 #000000; + 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: #ffffff; + background-color: #040404; + *background-color: #000000; +} + +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \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 #ffffff; + *zoom: 1; +} + +.breadcrumb > li > .divider { + padding: 0 5px; + color: #ccc; +} + +.breadcrumb > .active { + color: #999999; +} + +.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: #ffffff; + border: 1px solid #dddddd; + 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: #999999; + cursor: default; +} + +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: #999999; + 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: #999999; + cursor: default; + background-color: #fff; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: 1050; + width: 560px; + margin-left: -280px; + background-color: #ffffff; + 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: none; + -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 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.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 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.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: 0.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: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -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: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + 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: #ffffff; + 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: #ffffff; + 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: #ffffff; + 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: #ffffff; + 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: #ffffff; + 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 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +a.thumbnail:hover, +a.thumbnail:focus { + border-color: #0088cc; + -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: #555555; +} + +.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: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.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: #ffffff; + 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: #333333; +} + +.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: #ffffff; + 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 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.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: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.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: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.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: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + line-height: 20px; + color: #ffffff; +} + +.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: #eeeeee; + -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; +} + +/* Let's get this party started */ + ::-webkit-scrollbar { + width: 8px; + -webkit-appearance: none; + } + ::-webkit-scrollbar:horizontal { + height: 8px; + } + + /* Track */ + ::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 6px #888888 ; + -webkit-border-radius: 10px; + border-radius: 10px; + } + + /* Handle */ + ::-webkit-scrollbar-thumb { + -webkit-border-radius: 10px; + border-radius: 10px; + background: #888888 ; + -webkit-box-shadow: inset 0 0 6px #C0C0C0; + } + ::-webkit-scrollbar-thumb:window-inactive { + background: #C0C0C0; + } diff --git a/asset/bootstrap/css/bootstrap.min.css b/asset/bootstrap/css/bootstrap.min.css new file mode 100644 index 0000000..b6428e6 --- /dev/null +++ b/asset/bootstrap/css/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.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}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-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)}.img-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}.icon-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")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-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}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.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 .icon-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 .icon-bar+.icon-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} diff --git a/asset/bootstrap/css/docs.css b/asset/bootstrap/css/docs.css new file mode 100644 index 0000000..af65540 --- /dev/null +++ b/asset/bootstrap/css/docs.css @@ -0,0 +1,1067 @@ +/* Add additional stylesheets below +-------------------------------------------------- */ +/* + Bootstrap's documentation styles + Special styles for presenting Bootstrap's documentation and examples +*/ + + + +/* Body and structure +-------------------------------------------------- */ + +body { + position: relative; + padding-top: 40px; +} + +/* Code in headings */ +h3 code { + font-size: 14px; + font-weight: normal; +} + + + +/* Tweak navbar brand link to be super sleek +-------------------------------------------------- */ + +body > .navbar { + font-size: 13px; +} + +/* Change the docs' brand */ +body > .navbar .brand { + padding-right: 0; + padding-left: 0; + margin-left: 20px; + float: right; + font-weight: bold; + color: #000; + text-shadow: 0 1px 0 rgba(255,255,255,.1), 0 0 30px rgba(255,255,255,.125); + -webkit-transition: all .2s linear; + -moz-transition: all .2s linear; + transition: all .2s linear; +} +body > .navbar .brand:hover { + text-decoration: none; + text-shadow: 0 1px 0 rgba(255,255,255,.1), 0 0 30px rgba(255,255,255,.4); +} + + +/* Sections +-------------------------------------------------- */ + +/* padding for in-page bookmarks and fixed navbar */ +section { + padding-top: 30px; +} +section > .page-header, +section > .lead { + color: #5a5a5a; +} +section > ul li { + margin-bottom: 5px; +} + +/* Separators (hr) */ +.bs-docs-separator { + margin: 40px 0 39px; +} + +/* Faded out hr */ +hr.soften { + height: 1px; + margin: 70px 0; + background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); + background-image: -moz-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); + background-image: -ms-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); + background-image: -o-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); + border: 0; +} + + + +/* Jumbotrons +-------------------------------------------------- */ + +/* Base class +------------------------- */ +.jumbotron { + position: relative; + padding: 40px 0; + color: #fff; + text-align: center; + text-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 30px rgba(0,0,0,.075); + background: #020031; /* Old browsers */ + background: -moz-linear-gradient(45deg, #020031 0%, #6d3353 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left bottom, right top, color-stop(0%,#020031), color-stop(100%,#6d3353)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* IE10+ */ + background: linear-gradient(45deg, #020031 0%,#6d3353 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#020031', endColorstr='#6d3353',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ + -webkit-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); + -moz-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); + box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); +} +.jumbotron h1 { + font-size: 80px; + font-weight: bold; + letter-spacing: -1px; + line-height: 1; +} +.jumbotron p { + font-size: 24px; + font-weight: 300; + line-height: 1.25; + margin-bottom: 30px; +} + +/* Link styles (used on .masthead-links as well) */ +.jumbotron a { + color: #fff; + color: rgba(255,255,255,.5); + -webkit-transition: all .2s ease-in-out; + -moz-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; +} +.jumbotron a:hover { + color: #fff; + text-shadow: 0 0 10px rgba(255,255,255,.25); +} + +/* Download button */ +.masthead .btn { + padding: 19px 24px; + font-size: 24px; + font-weight: 200; + color: #fff; /* redeclare to override the `.jumbotron a` */ + border: 0; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); + -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); + box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); + -webkit-transition: none; + -moz-transition: none; + transition: none; +} +.masthead .btn:hover { + -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); + -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); + box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); +} +.masthead .btn:active { + -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); + -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); + box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); +} + + +/* Pattern overlay +------------------------- */ +.jumbotron .container { + position: relative; + z-index: 2; +} +.jumbotron:after { + content: ''; + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: url(../img/bs-docs-masthead-pattern.png) repeat center center; + opacity: .4; +} +@media +only screen and (-webkit-min-device-pixel-ratio: 2), +only screen and ( min--moz-device-pixel-ratio: 2), +only screen and ( -o-min-device-pixel-ratio: 2/1) { + + .jumbotron:after { + background-size: 150px 150px; + } + +} + +/* Masthead (docs home) +------------------------- */ +.masthead { + padding: 70px 0 80px; + margin-bottom: 0; + color: #fff; +} +.masthead h1 { + font-size: 120px; + line-height: 1; + letter-spacing: -2px; +} +.masthead p { + font-size: 40px; + font-weight: 200; + line-height: 1.25; +} + +/* Textual links in masthead */ +.masthead-links { + margin: 0; + list-style: none; +} +.masthead-links li { + display: inline; + padding: 0 10px; + color: rgba(255,255,255,.25); +} + +/* Social proof buttons from GitHub & Twitter */ +.bs-docs-social { + padding: 15px 0; + text-align: center; + background-color: #f5f5f5; + border-top: 1px solid #fff; + border-bottom: 1px solid #ddd; +} + +/* Quick links on Home */ +.bs-docs-social-buttons { + margin-left: 0; + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.bs-docs-social-buttons li { + display: inline-block; + padding: 5px 8px; + line-height: 1; + *display: inline; + *zoom: 1; +} + +/* Subhead (other pages) +------------------------- */ +.subhead { + text-align: left; + border-bottom: 1px solid #ddd; +} +.subhead h1 { + font-size: 60px; +} +.subhead p { + margin-bottom: 20px; +} +.subhead .navbar { + display: none; +} + + + +/* Marketing section of Overview +-------------------------------------------------- */ + +.marketing { + text-align: center; + color: #5a5a5a; +} +.marketing h1 { + margin: 60px 0 10px; + font-size: 60px; + font-weight: 200; + line-height: 1; + letter-spacing: -1px; +} +.marketing h2 { + font-weight: 200; + margin-bottom: 5px; +} +.marketing p { + font-size: 16px; + line-height: 1.5; +} +.marketing .marketing-byline { + margin-bottom: 40px; + font-size: 20px; + font-weight: 300; + line-height: 1.25; + color: #999; +} +.marketing-img { + display: block; + margin: 0 auto 30px; + max-height: 145px; +} + + + +/* Footer +-------------------------------------------------- */ + +.footer { + text-align: center; + padding: 30px 0; + margin-top: 70px; + border-top: 1px solid #e5e5e5; + background-color: #f5f5f5; +} +.footer p { + margin-bottom: 0; + color: #777; +} +.footer-links { + margin: 10px 0; +} +.footer-links li { + display: inline; + padding: 0 2px; +} +.footer-links li:first-child { + padding-left: 0; +} + + + +/* Special grid styles +-------------------------------------------------- */ + +.show-grid { + margin-top: 10px; + margin-bottom: 20px; +} +.show-grid [class*="span"] { + background-color: #eee; + text-align: center; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + min-height: 40px; + line-height: 40px; +} +.show-grid [class*="span"]:hover { + background-color: #ddd; +} +.show-grid .show-grid { + margin-top: 0; + margin-bottom: 0; +} +.show-grid .show-grid [class*="span"] { + margin-top: 5px; +} +.show-grid [class*="span"] [class*="span"] { + background-color: #ccc; +} +.show-grid [class*="span"] [class*="span"] [class*="span"] { + background-color: #999; +} + + + +/* Mini layout previews +-------------------------------------------------- */ +.mini-layout { + border: 1px solid #ddd; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.075); + -moz-box-shadow: 0 1px 2px rgba(0,0,0,.075); + box-shadow: 0 1px 2px rgba(0,0,0,.075); +} +.mini-layout, +.mini-layout .mini-layout-body, +.mini-layout.fluid .mini-layout-sidebar { + height: 300px; +} +.mini-layout { + margin-bottom: 20px; + padding: 9px; +} +.mini-layout div { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.mini-layout .mini-layout-body { + background-color: #dceaf4; + margin: 0 auto; + width: 70%; +} +.mini-layout.fluid .mini-layout-sidebar, +.mini-layout.fluid .mini-layout-header, +.mini-layout.fluid .mini-layout-body { + float: left; +} +.mini-layout.fluid .mini-layout-sidebar { + background-color: #bbd8e9; + width: 20%; +} +.mini-layout.fluid .mini-layout-body { + width: 77.5%; + margin-left: 2.5%; +} + + + +/* Download page +-------------------------------------------------- */ + +.download .page-header { + margin-top: 36px; +} +.page-header .toggle-all { + margin-top: 5px; +} + +/* Space out h3s when following a section */ +.download h3 { + margin-bottom: 5px; +} +.download-builder input + h3, +.download-builder .checkbox + h3 { + margin-top: 9px; +} + +/* Fields for variables */ +.download-builder input[type=text] { + margin-bottom: 9px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #d14; +} +.download-builder input[type=text]:focus { + background-color: #fff; +} + +/* Custom, larger checkbox labels */ +.download .checkbox { + padding: 6px 10px 6px 25px; + font-size: 13px; + line-height: 18px; + color: #555; + background-color: #f9f9f9; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} +.download .checkbox:hover { + color: #333; + background-color: #f5f5f5; +} +.download .checkbox small { + font-size: 12px; + color: #777; +} + +/* Variables section */ +#variables label { + margin-bottom: 0; +} + +/* Giant download button */ +.download-btn { + margin: 36px 0 108px; +} +#download p, +#download h4 { + max-width: 50%; + margin: 0 auto; + color: #999; + text-align: center; +} +#download h4 { + margin-bottom: 0; +} +#download p { + margin-bottom: 18px; +} +.download-btn .btn { + display: block; + width: auto; + padding: 19px 24px; + margin-bottom: 27px; + font-size: 30px; + line-height: 1; + text-align: center; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + + + +/* Misc +-------------------------------------------------- */ + +/* Make tables spaced out a bit more */ +h2 + table, +h3 + table, +h4 + table, +h2 + .row { + margin-top: 5px; +} + +/* Example sites showcase */ +.example-sites { + xmargin-left: 20px; +} +.example-sites img { + max-width: 100%; + margin: 0 auto; +} + +.scrollspy-example { + height: 200px; + overflow: auto; + position: relative; +} + + +/* Fake the :focus state to demo it */ +.focused { + border-color: rgba(82,168,236,.8); + -webkit-box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); + -moz-box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); + box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); + outline: 0; +} + +/* For input sizes, make them display block */ +.docs-input-sizes select, +.docs-input-sizes input[type=text] { + display: block; + margin-bottom: 9px; +} + +/* Icons +------------------------- */ +.the-icons { + margin-left: 0; + list-style: none; +} +.the-icons li { + float: left; + width: 25%; + line-height: 25px; +} +.the-icons i:hover { + background-color: rgba(255,0,0,.25); +} + +/* Example page +------------------------- */ +.bootstrap-examples h4 { + margin: 10px 0 5px; +} +.bootstrap-examples p { + font-size: 13px; + line-height: 18px; +} +.bootstrap-examples .thumbnail { + margin-bottom: 9px; + background-color: #fff; +} + + + +/* Bootstrap code examples +-------------------------------------------------- */ + +/* Base class */ +.bs-docs-example { + position: relative; + margin: 15px 0; + padding: 39px 19px 14px; + *padding-top: 19px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +/* Echo out a label for the example */ +.bs-docs-example:after { + content: "Example"; + position: absolute; + top: -1px; + left: -1px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + background-color: #f5f5f5; + border: 1px solid #ddd; + color: #9da0a4; + -webkit-border-radius: 4px 0 4px 0; + -moz-border-radius: 4px 0 4px 0; + border-radius: 4px 0 4px 0; +} + +/* Remove spacing between an example and it's code */ +.bs-docs-example + .prettyprint { + margin-top: -20px; + padding-top: 15px; +} + +/* Tweak examples +------------------------- */ +.bs-docs-example > p:last-child { + margin-bottom: 0; +} +.bs-docs-example .table, +.bs-docs-example .progress, +.bs-docs-example .well, +.bs-docs-example .alert, +.bs-docs-example .hero-unit, +.bs-docs-example .pagination, +.bs-docs-example .navbar, +.bs-docs-example > .nav, +.bs-docs-example blockquote { + margin-bottom: 5px; +} +.bs-docs-example .pagination { + margin-top: 0; +} +.bs-navbar-top-example, +.bs-navbar-bottom-example { + z-index: 1; + padding: 0; + height: 90px; + overflow: hidden; /* cut the drop shadows off */ +} +.bs-navbar-top-example .navbar-fixed-top, +.bs-navbar-bottom-example .navbar-fixed-bottom { + margin-left: 0; + margin-right: 0; +} +.bs-navbar-top-example { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.bs-navbar-top-example:after { + top: auto; + bottom: -1px; + -webkit-border-radius: 0 4px 0 4px; + -moz-border-radius: 0 4px 0 4px; + border-radius: 0 4px 0 4px; +} +.bs-navbar-bottom-example { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.bs-navbar-bottom-example .navbar { + margin-bottom: 0; +} +form.bs-docs-example { + padding-bottom: 19px; +} + +/* Images */ +.bs-docs-example-images img { + margin: 10px; + display: inline-block; +} + +/* Tooltips */ +.bs-docs-tooltip-examples { + text-align: center; + margin: 0 0 10px; + list-style: none; +} +.bs-docs-tooltip-examples li { + display: inline; + padding: 0 10px; +} + +/* Popovers */ +.bs-docs-example-popover { + padding-bottom: 24px; + background-color: #f9f9f9; +} +.bs-docs-example-popover .popover { + position: relative; + display: block; + float: left; + width: 260px; + margin: 20px; +} + +/* Dropdowns */ +.bs-docs-example-submenus { + min-height: 180px; +} +.bs-docs-example-submenus > .pull-left + .pull-left { + margin-left: 20px; +} +.bs-docs-example-submenus .dropup > .dropdown-menu, +.bs-docs-example-submenus .dropdown > .dropdown-menu { + display: block; + position: static; + margin-bottom: 5px; + *width: 180px; +} + + + +/* Responsive docs +-------------------------------------------------- */ + +/* Utility classes table +------------------------- */ +.responsive-utilities th small { + display: block; + font-weight: normal; + color: #999; +} +.responsive-utilities tbody th { + font-weight: normal; +} +.responsive-utilities td { + text-align: center; +} +.responsive-utilities td.is-visible { + color: #468847; + background-color: #dff0d8 !important; +} +.responsive-utilities td.is-hidden { + color: #ccc; + background-color: #f9f9f9 !important; +} + +/* Responsive tests +------------------------- */ +.responsive-utilities-test { + margin-top: 5px; + margin-left: 0; + list-style: none; + overflow: hidden; /* clear floats */ +} +.responsive-utilities-test li { + position: relative; + float: left; + width: 25%; + height: 43px; + font-size: 14px; + font-weight: bold; + line-height: 43px; + color: #999; + text-align: center; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.responsive-utilities-test li + li { + margin-left: 10px; +} +.responsive-utilities-test span { + position: absolute; + top: -1px; + left: -1px; + right: -1px; + bottom: -1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.responsive-utilities-test span { + color: #468847; + background-color: #dff0d8; + border: 1px solid #d6e9c6; +} + + + +/* Sidenav for Docs +-------------------------------------------------- */ + +.bs-docs-sidenav { + width: 228px; + margin: 30px 0 0; + padding: 0; + background-color: #fff; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 1px 4px rgba(0,0,0,.065); + -moz-box-shadow: 0 1px 4px rgba(0,0,0,.065); + box-shadow: 0 1px 4px rgba(0,0,0,.065); +} +.bs-docs-sidenav > li > a { + display: block; + width: 190px \9; + margin: 0 0 -1px; + padding: 8px 14px; + border: 1px solid #e5e5e5; +} +.bs-docs-sidenav > li:first-child > a { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} +.bs-docs-sidenav > li:last-child > a { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} +.bs-docs-sidenav > .active > a { + position: relative; + z-index: 2; + padding: 9px 15px; + border: 0; + text-shadow: 0 1px 0 rgba(0,0,0,.15); + -webkit-box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); + -moz-box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); + box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); +} +/* Chevrons */ +.bs-docs-sidenav .icon-chevron-right { + float: right; + margin-top: 2px; + margin-right: -6px; + opacity: .25; +} +.bs-docs-sidenav > li > a:hover { + background-color: #f5f5f5; +} +.bs-docs-sidenav a:hover .icon-chevron-right { + opacity: .5; +} +.bs-docs-sidenav .active .icon-chevron-right, +.bs-docs-sidenav .active a:hover .icon-chevron-right { + background-image: url(../img/glyphicons-halflings-white.png); + opacity: 1; +} +.bs-docs-sidenav.affix { + top: 40px; +} +.bs-docs-sidenav.affix-bottom { + position: absolute; + top: auto; + bottom: 270px; +} + + + + +/* Responsive +-------------------------------------------------- */ + +/* Desktop large +------------------------- */ +@media (min-width: 1200px) { + .bs-docs-container { + max-width: 970px; + } + .bs-docs-sidenav { + width: 258px; + } + .bs-docs-sidenav > li > a { + width: 230px \9; /* Override the previous IE8-9 hack */ + } +} + +/* Desktop +------------------------- */ +@media (max-width: 980px) { + /* Unfloat brand */ + body > .navbar-fixed-top .brand { + float: left; + margin-left: 0; + padding-left: 10px; + padding-right: 10px; + } + + /* Inline-block quick links for more spacing */ + .quick-links li { + display: inline-block; + margin: 5px; + } + + /* When affixed, space properly */ + .bs-docs-sidenav { + top: 0; + width: 218px; + margin-top: 30px; + margin-right: 0; + } +} + +/* Tablet to desktop +------------------------- */ +@media (min-width: 768px) and (max-width: 979px) { + /* Remove any padding from the body */ + body { + padding-top: 0; + } + /* Widen masthead and social buttons to fill body padding */ + .jumbotron { + margin-top: -20px; /* Offset bottom margin on .navbar */ + } + /* Adjust sidenav width */ + .bs-docs-sidenav { + width: 166px; + margin-top: 20px; + } + .bs-docs-sidenav.affix { + top: 0; + } +} + +/* Tablet +------------------------- */ +@media (max-width: 767px) { + /* Remove any padding from the body */ + body { + padding-top: 0; + } + + /* Widen masthead and social buttons to fill body padding */ + .jumbotron { + padding: 40px 20px; + margin-top: -20px; /* Offset bottom margin on .navbar */ + margin-right: -20px; + margin-left: -20px; + } + .masthead h1 { + font-size: 90px; + } + .masthead p, + .masthead .btn { + font-size: 24px; + } + .marketing .span4 { + margin-bottom: 40px; + } + .bs-docs-social { + margin: 0 -20px; + } + + /* Space out the show-grid examples */ + .show-grid [class*="span"] { + margin-bottom: 5px; + } + + /* Sidenav */ + .bs-docs-sidenav { + width: auto; + margin-bottom: 20px; + } + .bs-docs-sidenav.affix { + position: static; + width: auto; + top: 0; + } + + /* Unfloat the back to top link in footer */ + .footer { + margin-left: -20px; + margin-right: -20px; + padding-left: 20px; + padding-right: 20px; + } + .footer p { + margin-bottom: 9px; + } +} + +/* Landscape phones +------------------------- */ +@media (max-width: 480px) { + /* Remove padding above jumbotron */ + body { + padding-top: 0; + } + + /* Change up some type stuff */ + h2 small { + display: block; + } + + /* Downsize the jumbotrons */ + .jumbotron h1 { + font-size: 45px; + } + .jumbotron p, + .jumbotron .btn { + font-size: 18px; + } + .jumbotron .btn { + display: block; + margin: 0 auto; + } + + /* center align subhead text like the masthead */ + .subhead h1, + .subhead p { + text-align: center; + } + + /* Marketing on home */ + .marketing h1 { + font-size: 30px; + } + .marketing-byline { + font-size: 18px; + } + + /* center example sites */ + .example-sites { + margin-left: 0; + } + .example-sites > li { + float: none; + display: block; + max-width: 280px; + margin: 0 auto 18px; + text-align: center; + } + .example-sites .thumbnail > img { + max-width: 270px; + } + + /* Do our best to make tables work in narrow viewports */ + table code { + white-space: normal; + word-wrap: break-word; + word-break: break-all; + } + + /* Examples: dropdowns */ + .bs-docs-example-submenus > .pull-left { + float: none; + clear: both; + } + .bs-docs-example-submenus > .pull-left, + .bs-docs-example-submenus > .pull-left + .pull-left { + margin-left: 0; + } + .bs-docs-example-submenus p { + margin-bottom: 0; + } + .bs-docs-example-submenus .dropup > .dropdown-menu, + .bs-docs-example-submenus .dropdown > .dropdown-menu { + margin-bottom: 10px; + float: none; + max-width: 180px; + } + + /* Examples: modal */ + .modal-example .modal { + position: relative; + top: auto; + right: auto; + bottom: auto; + left: auto; + } + + /* Tighten up footer */ + .footer { + padding-top: 20px; + padding-bottom: 20px; + } +} diff --git a/asset/bootstrap/img/glyphicons-halflings-white.png b/asset/bootstrap/img/glyphicons-halflings-white.png new file mode 100644 index 0000000..3bf6484 Binary files /dev/null and b/asset/bootstrap/img/glyphicons-halflings-white.png differ diff --git a/asset/bootstrap/img/glyphicons-halflings.png b/asset/bootstrap/img/glyphicons-halflings.png new file mode 100644 index 0000000..a996999 Binary files /dev/null and b/asset/bootstrap/img/glyphicons-halflings.png differ diff --git a/asset/bootstrap/js/README.md b/asset/bootstrap/js/README.md new file mode 100644 index 0000000..66903c7 --- /dev/null +++ b/asset/bootstrap/js/README.md @@ -0,0 +1,106 @@ +## 2.0 BOOTSTRAP JS PHILOSOPHY +These are the high-level design rules which guide the development of Bootstrap's plugin apis. + +--- + +### DATA-ATTRIBUTE API + +We believe you should be able to use all plugins provided by Bootstrap purely through the markup API without writing a single line of javascript. + +We acknowledge that this isn't always the most performant and sometimes it may be desirable to turn this functionality off altogether. Therefore, as of 2.0 we provide the ability to disable the data attribute API by unbinding all events on the body namespaced with `'data-api'`. This looks like this: + + $('body').off('.data-api') + +To target a specific plugin, just include the plugins name as a namespace along with the data-api namespace like this: + + $('body').off('.alert.data-api') + +--- + +### PROGRAMMATIC API + +We also believe you should be able to use all plugins provided by Bootstrap purely through the JS API. + +All public APIs should be single, chainable methods, and return the collection acted upon. + + $(".btn.danger").button("toggle").addClass("fat") + +All methods should accept an optional options object, a string which targets a particular method, or null which initiates the default behavior: + + $("#myModal").modal() // initialized with defaults + $("#myModal").modal({ keyboard: false }) // initialized with now keyboard + $("#myModal").modal('show') // initializes and invokes show immediately afterqwe2 + +--- + +### OPTIONS + +Options should be sparse and add universal value. We should pick the right defaults. + +All plugins should have a default object which can be modified to effect all instance's default options. The defaults object should be available via `$.fn.plugin.defaults`. + + $.fn.modal.defaults = { … } + +An options definition should take the following form: + + *noun*: *adjective* - describes or modifies a quality of an instance + +examples: + + backdrop: true + keyboard: false + placement: 'top' + +--- + +### EVENTS + +All events should have an infinitive and past participle form. The infinitive is fired just before an action takes place, the past participle on completion of the action. + + show | shown + hide | hidden + +--- + +### CONSTRUCTORS + +Each plugin should expose it's raw constructor on a `Constructor` property -- accessed in the following way: + + + $.fn.popover.Constructor + +--- + +### DATA ACCESSOR + +Each plugin stores a copy of the invoked class on an object. This class instance can be accessed directly through jQuery's data API like this: + + $('[rel=popover]').data('popover') instanceof $.fn.popover.Constructor + +--- + +### DATA ATTRIBUTES + +Data attributes should take the following form: + +- data-{{verb}}={{plugin}} - defines main interaction +- data-target || href^=# - defined on "control" element (if element controls an element other than self) +- data-{{noun}} - defines class instance options + +examples: + + // control other targets + data-toggle="modal" data-target="#foo" + data-toggle="collapse" data-target="#foo" data-parent="#bar" + + // defined on element they control + data-spy="scroll" + + data-dismiss="modal" + data-dismiss="alert" + + data-toggle="dropdown" + + data-toggle="button" + data-toggle="buttons-checkbox" + data-toggle="buttons-radio" \ No newline at end of file diff --git a/asset/bootstrap/js/application.js b/asset/bootstrap/js/application.js new file mode 100644 index 0000000..f880bc0 --- /dev/null +++ b/asset/bootstrap/js/application.js @@ -0,0 +1,156 @@ +// NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT +// IT'S ALL JUST JUNK FOR OUR DOCS! +// ++++++++++++++++++++++++++++++++++++++++++ + +!function ($) { + + $(function(){ + + var $window = $(window) + + // Disable certain links in docs + $('section [href^=#]').click(function (e) { + e.preventDefault() + }) + + // side bar + setTimeout(function () { + $('.bs-docs-sidenav').affix({ + offset: { + top: function () { return $window.width() <= 980 ? 290 : 210 } + , bottom: 270 + } + }) + }, 100) + + // make code pretty + window.prettyPrint && prettyPrint() + + // add-ons + $('.add-on :checkbox').on('click', function () { + var $this = $(this) + , method = $this.attr('checked') ? 'addClass' : 'removeClass' + $(this).parents('.add-on')[method]('active') + }) + + // add tipsies to grid for scaffolding + if ($('#gridSystem').length) { + $('#gridSystem').tooltip({ + selector: '.show-grid > [class*="span"]' + , title: function () { return $(this).width() + 'px' } + }) + } + + // tooltip demo + $('.tooltip-demo').tooltip({ + selector: "a[data-toggle=tooltip]" + }) + + $('.tooltip-test').tooltip() + $('.popover-test').popover() + + // popover demo + $("a[data-toggle=popover]") + .popover() + .click(function(e) { + e.preventDefault() + }) + + // button state demo + $('#fat-btn') + .click(function () { + var btn = $(this) + btn.button('loading') + setTimeout(function () { + btn.button('reset') + }, 3000) + }) + + // carousel demo + $('#myCarousel').carousel() + + // javascript build logic + var inputsComponent = $("#components.download input") + , inputsPlugin = $("#plugins.download input") + , inputsVariables = $("#variables.download input") + + // toggle all plugin checkboxes + $('#components.download .toggle-all').on('click', function (e) { + e.preventDefault() + inputsComponent.attr('checked', !inputsComponent.is(':checked')) + }) + + $('#plugins.download .toggle-all').on('click', function (e) { + e.preventDefault() + inputsPlugin.attr('checked', !inputsPlugin.is(':checked')) + }) + + $('#variables.download .toggle-all').on('click', function (e) { + e.preventDefault() + inputsVariables.val('') + }) + + // request built javascript + $('.download-btn .btn').on('click', function () { + + var css = $("#components.download input:checked") + .map(function () { return this.value }) + .toArray() + , js = $("#plugins.download input:checked") + .map(function () { return this.value }) + .toArray() + , vars = {} + , img = ['glyphicons-halflings.png', 'glyphicons-halflings-white.png'] + + $("#variables.download input") + .each(function () { + $(this).val() && (vars[ $(this).prev().text() ] = $(this).val()) + }) + + $.ajax({ + type: 'POST' + , url: /\?dev/.test(window.location) ? 'http://localhost:3000' : 'http://bootstrap.herokuapp.com' + , dataType: 'jsonpi' + , params: { + js: js + , css: css + , vars: vars + , img: img + } + }) + }) + }) + +// Modified from the original jsonpi https://github.com/benvinegar/jquery-jsonpi +$.ajaxTransport('jsonpi', function(opts, originalOptions, jqXHR) { + var url = opts.url; + + return { + send: function(_, completeCallback) { + var name = 'jQuery_iframe_' + jQuery.now() + , iframe, form + + iframe = $('' : ''); + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + var changeMonth = this._get(inst, 'changeMonth'); + var changeYear = this._get(inst, 'changeYear'); + var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); + var html = '
'; + var monthHtml = ''; + // month selection + if (secondary || !changeMonth) + monthHtml += '' + monthNames[drawMonth] + ''; + else { + var inMinYear = (minDate && minDate.getFullYear() == drawYear); + var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); + monthHtml += ''; + } + if (!showMonthAfterYear) + html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); + // year selection + if ( !inst.yearshtml ) { + inst.yearshtml = ''; + if (secondary || !changeYear) + html += '' + drawYear + ''; + else { + // determine range of years to display + var years = this._get(inst, 'yearRange').split(':'); + var thisYear = new Date().getFullYear(); + var determineYear = function(value) { + var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + var year = determineYear(years[0]); + var endYear = Math.max(year, determineYear(years[1] || '')); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + inst.yearshtml += ''; + + html += inst.yearshtml; + inst.yearshtml = null; + } + } + html += this._get(inst, 'yearSuffix'); + if (showMonthAfterYear) + html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; + html += '
'; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period == 'Y' ? offset : 0); + var month = inst.drawMonth + (period == 'M' ? offset : 0); + var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + + (period == 'D' ? offset : 0); + var date = this._restrictMinMax(inst, + this._daylightSavingAdjust(new Date(year, month, day))); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period == 'M' || period == 'Y') + this._notifyChange(inst); + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + var newDate = (minDate && date < minDate ? minDate : date); + newDate = (maxDate && newDate > maxDate ? maxDate : newDate); + return newDate; + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, 'onChangeMonthYear'); + if (onChange) + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, 'numberOfMonths'); + return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst); + var date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + if (offset < 0) + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var minDate = this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime())); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, 'shortYearCutoff'); + shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), + monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day == 'object' ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); + } +}); + +/* + * Bind hover events for datepicker elements. + * Done via delegate so the binding only occurs once in the lifetime of the parent div. + * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. + */ +function bindHover(dpDiv) { + var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; + return dpDiv.bind('mouseout', function(event) { + var elem = $( event.target ).closest( selector ); + if ( !elem.length ) { + return; + } + elem.removeClass( "ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover" ); + }) + .bind('mouseover', function(event) { + var elem = $( event.target ).closest( selector ); + if ($.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0]) || + !elem.length ) { + return; + } + elem.parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); + elem.addClass('ui-state-hover'); + if (elem.hasClass('ui-datepicker-prev')) elem.addClass('ui-datepicker-prev-hover'); + if (elem.hasClass('ui-datepicker-next')) elem.addClass('ui-datepicker-next-hover'); + }); +} + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) + if (props[name] == null || props[name] == undefined) + target[name] = props[name]; + return target; +}; + +/* Determine whether an object is an array. */ +function isArray(a) { + return (a && (($.browser.safari && typeof a == 'object' && a.length) || + (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); +}; + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Verify an empty collection wasn't passed - Fixes #6976 */ + if ( !this.length ) { + return this; + } + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick). + find('body').append($.datepicker.dpDiv); + $.datepicker.initialized = true; + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + return this.each(function() { + typeof options == 'string' ? + $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.8.23"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window['DP_jQuery_' + dpuuid] = $; + +})(jQuery); + +(function( $, undefined ) { + +var uiDialogClasses = + 'ui-dialog ' + + 'ui-widget ' + + 'ui-widget-content ' + + 'ui-corner-all ', + sizeRelatedOptions = { + buttons: true, + height: true, + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true, + width: true + }, + resizableRelatedOptions = { + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true + }; + +$.widget("ui.dialog", { + options: { + autoOpen: true, + buttons: {}, + closeOnEscape: true, + closeText: 'close', + dialogClass: '', + draggable: true, + hide: null, + height: 'auto', + maxHeight: false, + maxWidth: false, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: 'center', + at: 'center', + collision: 'fit', + // ensure that the titlebar is never outside the document + using: function(pos) { + var topOffset = $(this).css(pos).offset().top; + if (topOffset < 0) { + $(this).css('top', pos.top - topOffset); + } + } + }, + resizable: true, + show: null, + stack: true, + title: '', + width: 300, + zIndex: 1000 + }, + + _create: function() { + this.originalTitle = this.element.attr('title'); + // #5742 - .attr() might return a DOMElement + if ( typeof this.originalTitle !== "string" ) { + this.originalTitle = ""; + } + + this.options.title = this.options.title || this.originalTitle; + var self = this, + options = self.options, + + title = options.title || ' ', + titleId = $.ui.dialog.getTitleId(self.element), + + uiDialog = (self.uiDialog = $('
')) + .appendTo(document.body) + .hide() + .addClass(uiDialogClasses + options.dialogClass) + .css({ + zIndex: options.zIndex + }) + // setting tabIndex makes the div focusable + // setting outline to 0 prevents a border on focus in Mozilla + .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { + if (options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE) { + + self.close(event); + event.preventDefault(); + } + }) + .attr({ + role: 'dialog', + 'aria-labelledby': titleId + }) + .mousedown(function(event) { + self.moveToTop(false, event); + }), + + uiDialogContent = self.element + .show() + .removeAttr('title') + .addClass( + 'ui-dialog-content ' + + 'ui-widget-content') + .appendTo(uiDialog), + + uiDialogTitlebar = (self.uiDialogTitlebar = $('
')) + .addClass( + 'ui-dialog-titlebar ' + + 'ui-widget-header ' + + 'ui-corner-all ' + + 'ui-helper-clearfix' + ) + .prependTo(uiDialog), + + uiDialogTitlebarClose = $('') + .addClass( + 'ui-dialog-titlebar-close ' + + 'ui-corner-all' + ) + .attr('role', 'button') + .hover( + function() { + uiDialogTitlebarClose.addClass('ui-state-hover'); + }, + function() { + uiDialogTitlebarClose.removeClass('ui-state-hover'); + } + ) + .focus(function() { + uiDialogTitlebarClose.addClass('ui-state-focus'); + }) + .blur(function() { + uiDialogTitlebarClose.removeClass('ui-state-focus'); + }) + .click(function(event) { + self.close(event); + return false; + }) + .appendTo(uiDialogTitlebar), + + uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('')) + .addClass( + 'ui-icon ' + + 'ui-icon-closethick' + ) + .text(options.closeText) + .appendTo(uiDialogTitlebarClose), + + uiDialogTitle = $('') + .addClass('ui-dialog-title') + .attr('id', titleId) + .html(title) + .prependTo(uiDialogTitlebar); + + //handling of deprecated beforeclose (vs beforeClose) option + //Ticket #4669 http://dev.jqueryui.com/ticket/4669 + //TODO: remove in 1.9pre + if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) { + options.beforeClose = options.beforeclose; + } + + uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); + + if (options.draggable && $.fn.draggable) { + self._makeDraggable(); + } + if (options.resizable && $.fn.resizable) { + self._makeResizable(); + } + + self._createButtons(options.buttons); + self._isOpen = false; + + if ($.fn.bgiframe) { + uiDialog.bgiframe(); + } + }, + + _init: function() { + if ( this.options.autoOpen ) { + this.open(); + } + }, + + destroy: function() { + var self = this; + + if (self.overlay) { + self.overlay.destroy(); + } + self.uiDialog.hide(); + self.element + .unbind('.dialog') + .removeData('dialog') + .removeClass('ui-dialog-content ui-widget-content') + .hide().appendTo('body'); + self.uiDialog.remove(); + + if (self.originalTitle) { + self.element.attr('title', self.originalTitle); + } + + return self; + }, + + widget: function() { + return this.uiDialog; + }, + + close: function(event) { + var self = this, + maxZ, thisZ; + + if (false === self._trigger('beforeClose', event)) { + return; + } + + if (self.overlay) { + self.overlay.destroy(); + } + self.uiDialog.unbind('keypress.ui-dialog'); + + self._isOpen = false; + + if (self.options.hide) { + self.uiDialog.hide(self.options.hide, function() { + self._trigger('close', event); + }); + } else { + self.uiDialog.hide(); + self._trigger('close', event); + } + + $.ui.dialog.overlay.resize(); + + // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) + if (self.options.modal) { + maxZ = 0; + $('.ui-dialog').each(function() { + if (this !== self.uiDialog[0]) { + thisZ = $(this).css('z-index'); + if(!isNaN(thisZ)) { + maxZ = Math.max(maxZ, thisZ); + } + } + }); + $.ui.dialog.maxZ = maxZ; + } + + return self; + }, + + isOpen: function() { + return this._isOpen; + }, + + // the force parameter allows us to move modal dialogs to their correct + // position on open + moveToTop: function(force, event) { + var self = this, + options = self.options, + saveScroll; + + if ((options.modal && !force) || + (!options.stack && !options.modal)) { + return self._trigger('focus', event); + } + + if (options.zIndex > $.ui.dialog.maxZ) { + $.ui.dialog.maxZ = options.zIndex; + } + if (self.overlay) { + $.ui.dialog.maxZ += 1; + self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ); + } + + //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. + // http://ui.jquery.com/bugs/ticket/3193 + saveScroll = { scrollTop: self.element.scrollTop(), scrollLeft: self.element.scrollLeft() }; + $.ui.dialog.maxZ += 1; + self.uiDialog.css('z-index', $.ui.dialog.maxZ); + self.element.attr(saveScroll); + self._trigger('focus', event); + + return self; + }, + + open: function() { + if (this._isOpen) { return; } + + var self = this, + options = self.options, + uiDialog = self.uiDialog; + + self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null; + self._size(); + self._position(options.position); + uiDialog.show(options.show); + self.moveToTop(true); + + // prevent tabbing out of modal dialogs + if ( options.modal ) { + uiDialog.bind( "keydown.ui-dialog", function( event ) { + if ( event.keyCode !== $.ui.keyCode.TAB ) { + return; + } + + var tabbables = $(':tabbable', this), + first = tabbables.filter(':first'), + last = tabbables.filter(':last'); + + if (event.target === last[0] && !event.shiftKey) { + first.focus(1); + return false; + } else if (event.target === first[0] && event.shiftKey) { + last.focus(1); + return false; + } + }); + } + + // set focus to the first tabbable element in the content area or the first button + // if there are no tabbable elements, set focus on the dialog itself + $(self.element.find(':tabbable').get().concat( + uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat( + uiDialog.get()))).eq(0).focus(); + + self._isOpen = true; + self._trigger('open'); + + return self; + }, + + _createButtons: function(buttons) { + var self = this, + hasButtons = false, + uiDialogButtonPane = $('
') + .addClass( + 'ui-dialog-buttonpane ' + + 'ui-widget-content ' + + 'ui-helper-clearfix' + ), + uiButtonSet = $( "
" ) + .addClass( "ui-dialog-buttonset" ) + .appendTo( uiDialogButtonPane ); + + // if we already have a button pane, remove it + self.uiDialog.find('.ui-dialog-buttonpane').remove(); + + if (typeof buttons === 'object' && buttons !== null) { + $.each(buttons, function() { + return !(hasButtons = true); + }); + } + if (hasButtons) { + $.each(buttons, function(name, props) { + props = $.isFunction( props ) ? + { click: props, text: name } : + props; + var button = $('') + .click(function() { + props.click.apply(self.element[0], arguments); + }) + .appendTo(uiButtonSet); + // can't use .attr( props, true ) with jQuery 1.3.2. + $.each( props, function( key, value ) { + if ( key === "click" ) { + return; + } + if ( key in button ) { + button[ key ]( value ); + } else { + button.attr( key, value ); + } + }); + if ($.fn.button) { + button.button(); + } + }); + uiDialogButtonPane.appendTo(self.uiDialog); + } + }, + + _makeDraggable: function() { + var self = this, + options = self.options, + doc = $(document), + heightBeforeDrag; + + function filteredUi(ui) { + return { + position: ui.position, + offset: ui.offset + }; + } + + self.uiDialog.draggable({ + cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', + handle: '.ui-dialog-titlebar', + containment: 'document', + start: function(event, ui) { + heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height(); + $(this).height($(this).height()).addClass("ui-dialog-dragging"); + self._trigger('dragStart', event, filteredUi(ui)); + }, + drag: function(event, ui) { + self._trigger('drag', event, filteredUi(ui)); + }, + stop: function(event, ui) { + options.position = [ui.position.left - doc.scrollLeft(), + ui.position.top - doc.scrollTop()]; + $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); + self._trigger('dragStop', event, filteredUi(ui)); + $.ui.dialog.overlay.resize(); + } + }); + }, + + _makeResizable: function(handles) { + handles = (handles === undefined ? this.options.resizable : handles); + var self = this, + options = self.options, + // .ui-resizable has position: relative defined in the stylesheet + // but dialogs have to use absolute or fixed positioning + position = self.uiDialog.css('position'), + resizeHandles = (typeof handles === 'string' ? + handles : + 'n,e,s,w,se,sw,ne,nw' + ); + + function filteredUi(ui) { + return { + originalPosition: ui.originalPosition, + originalSize: ui.originalSize, + position: ui.position, + size: ui.size + }; + } + + self.uiDialog.resizable({ + cancel: '.ui-dialog-content', + containment: 'document', + alsoResize: self.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: self._minHeight(), + handles: resizeHandles, + start: function(event, ui) { + $(this).addClass("ui-dialog-resizing"); + self._trigger('resizeStart', event, filteredUi(ui)); + }, + resize: function(event, ui) { + self._trigger('resize', event, filteredUi(ui)); + }, + stop: function(event, ui) { + $(this).removeClass("ui-dialog-resizing"); + options.height = $(this).height(); + options.width = $(this).width(); + self._trigger('resizeStop', event, filteredUi(ui)); + $.ui.dialog.overlay.resize(); + } + }) + .css('position', position) + .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); + }, + + _minHeight: function() { + var options = this.options; + + if (options.height === 'auto') { + return options.minHeight; + } else { + return Math.min(options.minHeight, options.height); + } + }, + + _position: function(position) { + var myAt = [], + offset = [0, 0], + isVisible; + + if (position) { + // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( + // if (typeof position == 'string' || $.isArray(position)) { + // myAt = $.isArray(position) ? position : position.split(' '); + + if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) { + myAt = position.split ? position.split(' ') : [position[0], position[1]]; + if (myAt.length === 1) { + myAt[1] = myAt[0]; + } + + $.each(['left', 'top'], function(i, offsetPosition) { + if (+myAt[i] === myAt[i]) { + offset[i] = myAt[i]; + myAt[i] = offsetPosition; + } + }); + + position = { + my: myAt.join(" "), + at: myAt.join(" "), + offset: offset.join(" ") + }; + } + + position = $.extend({}, $.ui.dialog.prototype.options.position, position); + } else { + position = $.ui.dialog.prototype.options.position; + } + + // need to show the dialog to get the actual offset in the position plugin + isVisible = this.uiDialog.is(':visible'); + if (!isVisible) { + this.uiDialog.show(); + } + this.uiDialog + // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 + .css({ top: 0, left: 0 }) + .position($.extend({ of: window }, position)); + if (!isVisible) { + this.uiDialog.hide(); + } + }, + + _setOptions: function( options ) { + var self = this, + resizableOptions = {}, + resize = false; + + $.each( options, function( key, value ) { + self._setOption( key, value ); + + if ( key in sizeRelatedOptions ) { + resize = true; + } + if ( key in resizableRelatedOptions ) { + resizableOptions[ key ] = value; + } + }); + + if ( resize ) { + this._size(); + } + if ( this.uiDialog.is( ":data(resizable)" ) ) { + this.uiDialog.resizable( "option", resizableOptions ); + } + }, + + _setOption: function(key, value){ + var self = this, + uiDialog = self.uiDialog; + + switch (key) { + //handling of deprecated beforeclose (vs beforeClose) option + //Ticket #4669 http://dev.jqueryui.com/ticket/4669 + //TODO: remove in 1.9pre + case "beforeclose": + key = "beforeClose"; + break; + case "buttons": + self._createButtons(value); + break; + case "closeText": + // ensure that we always pass a string + self.uiDialogTitlebarCloseText.text("" + value); + break; + case "dialogClass": + uiDialog + .removeClass(self.options.dialogClass) + .addClass(uiDialogClasses + value); + break; + case "disabled": + if (value) { + uiDialog.addClass('ui-dialog-disabled'); + } else { + uiDialog.removeClass('ui-dialog-disabled'); + } + break; + case "draggable": + var isDraggable = uiDialog.is( ":data(draggable)" ); + if ( isDraggable && !value ) { + uiDialog.draggable( "destroy" ); + } + + if ( !isDraggable && value ) { + self._makeDraggable(); + } + break; + case "position": + self._position(value); + break; + case "resizable": + // currently resizable, becoming non-resizable + var isResizable = uiDialog.is( ":data(resizable)" ); + if (isResizable && !value) { + uiDialog.resizable('destroy'); + } + + // currently resizable, changing handles + if (isResizable && typeof value === 'string') { + uiDialog.resizable('option', 'handles', value); + } + + // currently non-resizable, becoming resizable + if (!isResizable && value !== false) { + self._makeResizable(value); + } + break; + case "title": + // convert whatever was passed in o a string, for html() to not throw up + $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' ')); + break; + } + + $.Widget.prototype._setOption.apply(self, arguments); + }, + + _size: function() { + /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + * divs will both have width and height set, so we need to reset them + */ + var options = this.options, + nonContentHeight, + minContentHeight, + isVisible = this.uiDialog.is( ":visible" ); + + // reset content sizing + this.element.show().css({ + width: 'auto', + minHeight: 0, + height: 0 + }); + + if (options.minWidth > options.width) { + options.width = options.minWidth; + } + + // reset wrapper sizing + // determine the height of all the non-content elements + nonContentHeight = this.uiDialog.css({ + height: 'auto', + width: options.width + }) + .height(); + minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); + + if ( options.height === "auto" ) { + // only needed for IE6 support + if ( $.support.minHeight ) { + this.element.css({ + minHeight: minContentHeight, + height: "auto" + }); + } else { + this.uiDialog.show(); + var autoHeight = this.element.css( "height", "auto" ).height(); + if ( !isVisible ) { + this.uiDialog.hide(); + } + this.element.height( Math.max( autoHeight, minContentHeight ) ); + } + } else { + this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); + } + + if (this.uiDialog.is(':data(resizable)')) { + this.uiDialog.resizable('option', 'minHeight', this._minHeight()); + } + } +}); + +$.extend($.ui.dialog, { + version: "1.8.23", + + uuid: 0, + maxZ: 0, + + getTitleId: function($el) { + var id = $el.attr('id'); + if (!id) { + this.uuid += 1; + id = this.uuid; + } + return 'ui-dialog-title-' + id; + }, + + overlay: function(dialog) { + this.$el = $.ui.dialog.overlay.create(dialog); + } +}); + +$.extend($.ui.dialog.overlay, { + instances: [], + // reuse old instances due to IE memory leak with alpha transparency (see #5185) + oldInstances: [], + maxZ: 0, + events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), + function(event) { return event + '.dialog-overlay'; }).join(' '), + create: function(dialog) { + if (this.instances.length === 0) { + // prevent use of anchors and inputs + // we use a setTimeout in case the overlay is created from an + // event that we're going to be cancelling (see #2804) + setTimeout(function() { + // handle $(el).dialog().dialog('close') (see #4065) + if ($.ui.dialog.overlay.instances.length) { + $(document).bind($.ui.dialog.overlay.events, function(event) { + // stop events if the z-index of the target is < the z-index of the overlay + // we cannot return true when we don't want to cancel the event (#3523) + if ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) { + return false; + } + }); + } + }, 1); + + // allow closing by pressing the escape key + $(document).bind('keydown.dialog-overlay', function(event) { + if (dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE) { + + dialog.close(event); + event.preventDefault(); + } + }); + + // handle window resize + $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); + } + + var $el = (this.oldInstances.pop() || $('
').addClass('ui-widget-overlay')) + .appendTo(document.body) + .css({ + width: this.width(), + height: this.height() + }); + + if ($.fn.bgiframe) { + $el.bgiframe(); + } + + this.instances.push($el); + return $el; + }, + + destroy: function($el) { + var indexOf = $.inArray($el, this.instances); + if (indexOf != -1){ + this.oldInstances.push(this.instances.splice(indexOf, 1)[0]); + } + + if (this.instances.length === 0) { + $([document, window]).unbind('.dialog-overlay'); + } + + $el.remove(); + + // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) + var maxZ = 0; + $.each(this.instances, function() { + maxZ = Math.max(maxZ, this.css('z-index')); + }); + this.maxZ = maxZ; + }, + + height: function() { + var scrollHeight, + offsetHeight; + // handle IE 6 + if ($.browser.msie && $.browser.version < 7) { + scrollHeight = Math.max( + document.documentElement.scrollHeight, + document.body.scrollHeight + ); + offsetHeight = Math.max( + document.documentElement.offsetHeight, + document.body.offsetHeight + ); + + if (scrollHeight < offsetHeight) { + return $(window).height() + 'px'; + } else { + return scrollHeight + 'px'; + } + // handle "good" browsers + } else { + return $(document).height() + 'px'; + } + }, + + width: function() { + var scrollWidth, + offsetWidth; + // handle IE + if ( $.browser.msie ) { + scrollWidth = Math.max( + document.documentElement.scrollWidth, + document.body.scrollWidth + ); + offsetWidth = Math.max( + document.documentElement.offsetWidth, + document.body.offsetWidth + ); + + if (scrollWidth < offsetWidth) { + return $(window).width() + 'px'; + } else { + return scrollWidth + 'px'; + } + // handle "good" browsers + } else { + return $(document).width() + 'px'; + } + }, + + resize: function() { + /* If the dialog is draggable and the user drags it past the + * right edge of the window, the document becomes wider so we + * need to stretch the overlay. If the user then drags the + * dialog back to the left, the document will become narrower, + * so we need to shrink the overlay to the appropriate size. + * This is handled by shrinking the overlay before setting it + * to the full document size. + */ + var $overlays = $([]); + $.each($.ui.dialog.overlay.instances, function() { + $overlays = $overlays.add(this); + }); + + $overlays.css({ + width: 0, + height: 0 + }).css({ + width: $.ui.dialog.overlay.width(), + height: $.ui.dialog.overlay.height() + }); + } +}); + +$.extend($.ui.dialog.overlay.prototype, { + destroy: function() { + $.ui.dialog.overlay.destroy(this.$el); + } +}); + +}(jQuery)); + +(function( $, undefined ) { + +$.ui = $.ui || {}; + +var horizontalPositions = /left|center|right/, + verticalPositions = /top|center|bottom/, + center = "center", + support = {}, + _position = $.fn.position, + _offset = $.fn.offset; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var target = $( options.of ), + targetElem = target[0], + collision = ( options.collision || "flip" ).split( " " ), + offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ], + targetWidth, + targetHeight, + basePosition; + + if ( targetElem.nodeType === 9 ) { + targetWidth = target.width(); + targetHeight = target.height(); + basePosition = { top: 0, left: 0 }; + // TODO: use $.isWindow() in 1.9 + } else if ( targetElem.setTimeout ) { + targetWidth = target.width(); + targetHeight = target.height(); + basePosition = { top: target.scrollTop(), left: target.scrollLeft() }; + } else if ( targetElem.preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + targetWidth = targetHeight = 0; + basePosition = { top: options.of.pageY, left: options.of.pageX }; + } else { + targetWidth = target.outerWidth(); + targetHeight = target.outerHeight(); + basePosition = target.offset(); + } + + // force my and at to have valid horizontal and veritcal positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[this] || "" ).split( " " ); + if ( pos.length === 1) { + pos = horizontalPositions.test( pos[0] ) ? + pos.concat( [center] ) : + verticalPositions.test( pos[0] ) ? + [ center ].concat( pos ) : + [ center, center ]; + } + pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center; + pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center; + options[ this ] = pos; + }); + + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + // normalize offset option + offset[ 0 ] = parseInt( offset[0], 10 ) || 0; + if ( offset.length === 1 ) { + offset[ 1 ] = offset[ 0 ]; + } + offset[ 1 ] = parseInt( offset[1], 10 ) || 0; + + if ( options.at[0] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[0] === center ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[1] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[1] === center ) { + basePosition.top += targetHeight / 2; + } + + basePosition.left += offset[ 0 ]; + basePosition.top += offset[ 1 ]; + + return this.each(function() { + var elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0, + marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0, + collisionWidth = elemWidth + marginLeft + + ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ), + collisionHeight = elemHeight + marginTop + + ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ), + position = $.extend( {}, basePosition ), + collisionPosition; + + if ( options.my[0] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[0] === center ) { + position.left -= elemWidth / 2; + } + + if ( options.my[1] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[1] === center ) { + position.top -= elemHeight / 2; + } + + // prevent fractions if jQuery version doesn't support them (see #5280) + if ( !support.fractions ) { + position.left = Math.round( position.left ); + position.top = Math.round( position.top ); + } + + collisionPosition = { + left: position.left - marginLeft, + top: position.top - marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[i] ] ) { + $.ui.position[ collision[i] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: offset, + my: options.my, + at: options.at + }); + } + }); + + if ( $.fn.bgiframe ) { + elem.bgiframe(); + } + elem.offset( $.extend( position, { using: options.using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var win = $( window ), + over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(); + position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left ); + }, + top: function( position, data ) { + var win = $( window ), + over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(); + position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top ); + } + }, + + flip: { + left: function( position, data ) { + if ( data.at[0] === center ) { + return; + } + var win = $( window ), + over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(), + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + -data.targetWidth, + offset = -2 * data.offset[ 0 ]; + position.left += data.collisionPosition.left < 0 ? + myOffset + atOffset + offset : + over > 0 ? + myOffset + atOffset + offset : + 0; + }, + top: function( position, data ) { + if ( data.at[1] === center ) { + return; + } + var win = $( window ), + over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(), + myOffset = data.my[ 1 ] === "top" ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + -data.targetHeight, + offset = -2 * data.offset[ 1 ]; + position.top += data.collisionPosition.top < 0 ? + myOffset + atOffset + offset : + over > 0 ? + myOffset + atOffset + offset : + 0; + } + } +}; + +// offset setter from jQuery 1.4 +if ( !$.offset.setOffset ) { + $.offset.setOffset = function( elem, options ) { + // set position first, in-case top/left are set even on static elem + if ( /static/.test( $.curCSS( elem, "position" ) ) ) { + elem.style.position = "relative"; + } + var curElem = $( elem ), + curOffset = curElem.offset(), + curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0, + curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0, + props = { + top: (options.top - curOffset.top) + curTop, + left: (options.left - curOffset.left) + curLeft + }; + + if ( 'using' in options ) { + options.using.call( elem, props ); + } else { + curElem.css( props ); + } + }; + + $.fn.offset = function( options ) { + var elem = this[ 0 ]; + if ( !elem || !elem.ownerDocument ) { return null; } + if ( options ) { + if ( $.isFunction( options ) ) { + return this.each(function( i ) { + $( this ).offset( options.call( this, i, $( this ).offset() ) ); + }); + } + return this.each(function() { + $.offset.setOffset( this, options ); + }); + } + return _offset.call( this ); + }; +} + +// jQuery <1.4.3 uses curCSS, in 1.4.3 - 1.7.2 curCSS = css, 1.8+ only has css +if ( !$.curCSS ) { + $.curCSS = $.css; +} + +// fraction support test (older versions of jQuery don't support fractions) +(function () { + var body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ), + testElement, testElementParent, testElementStyle, offset, offsetTotal; + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( var i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;"; + + offset = $( div ).offset( function( _, offset ) { + return offset; + }).offset(); + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); + + offsetTotal = offset.top + offset.left + ( body ? 2000 : 0 ); + support.fractions = offsetTotal > 21 && offsetTotal < 22; +})(); + +}( jQuery )); + +(function( $, undefined ) { + +$.widget( "ui.progressbar", { + options: { + value: 0, + max: 100 + }, + + min: 0, + + _create: function() { + this.element + .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .attr({ + role: "progressbar", + "aria-valuemin": this.min, + "aria-valuemax": this.options.max, + "aria-valuenow": this._value() + }); + + this.valueDiv = $( "
" ) + .appendTo( this.element ); + + this.oldValue = this._value(); + this._refreshValue(); + }, + + destroy: function() { + this.element + .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + + this.valueDiv.remove(); + + $.Widget.prototype.destroy.apply( this, arguments ); + }, + + value: function( newValue ) { + if ( newValue === undefined ) { + return this._value(); + } + + this._setOption( "value", newValue ); + return this; + }, + + _setOption: function( key, value ) { + if ( key === "value" ) { + this.options.value = value; + this._refreshValue(); + if ( this._value() === this.options.max ) { + this._trigger( "complete" ); + } + } + + $.Widget.prototype._setOption.apply( this, arguments ); + }, + + _value: function() { + var val = this.options.value; + // normalize invalid value + if ( typeof val !== "number" ) { + val = 0; + } + return Math.min( this.options.max, Math.max( this.min, val ) ); + }, + + _percentage: function() { + return 100 * this._value() / this.options.max; + }, + + _refreshValue: function() { + var value = this.value(); + var percentage = this._percentage(); + + if ( this.oldValue !== value ) { + this.oldValue = value; + this._trigger( "change" ); + } + + this.valueDiv + .toggle( value > this.min ) + .toggleClass( "ui-corner-right", value === this.options.max ) + .width( percentage.toFixed(0) + "%" ); + this.element.attr( "aria-valuenow", value ); + } +}); + +$.extend( $.ui.progressbar, { + version: "1.8.23" +}); + +})( jQuery ); + +(function( $, undefined ) { + +// number of pages in a slider +// (how many times can you page up/down to go through the whole range) +var numPages = 5; + +$.widget( "ui.slider", $.ui.mouse, { + + widgetEventPrefix: "slide", + + options: { + animate: false, + distance: 0, + max: 100, + min: 0, + orientation: "horizontal", + range: false, + step: 1, + value: 0, + values: null + }, + + _create: function() { + var self = this, + o = this.options, + existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), + handle = "", + handleCount = ( o.values && o.values.length ) || 1, + handles = []; + + this._keySliding = false; + this._mouseSliding = false; + this._animateOff = true; + this._handleIndex = null; + this._detectOrientation(); + this._mouseInit(); + + this.element + .addClass( "ui-slider" + + " ui-slider-" + this.orientation + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all" + + ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) ); + + this.range = $([]); + + if ( o.range ) { + if ( o.range === true ) { + if ( !o.values ) { + o.values = [ this._valueMin(), this._valueMin() ]; + } + if ( o.values.length && o.values.length !== 2 ) { + o.values = [ o.values[0], o.values[0] ]; + } + } + + this.range = $( "
" ) + .appendTo( this.element ) + .addClass( "ui-slider-range" + + // note: this isn't the most fittingly semantic framework class for this element, + // but worked best visually with a variety of themes + " ui-widget-header" + + ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) ); + } + + for ( var i = existingHandles.length; i < handleCount; i += 1 ) { + handles.push( handle ); + } + + this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( self.element ) ); + + this.handle = this.handles.eq( 0 ); + + this.handles.add( this.range ).filter( "a" ) + .click(function( event ) { + event.preventDefault(); + }) + .hover(function() { + if ( !o.disabled ) { + $( this ).addClass( "ui-state-hover" ); + } + }, function() { + $( this ).removeClass( "ui-state-hover" ); + }) + .focus(function() { + if ( !o.disabled ) { + $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); + $( this ).addClass( "ui-state-focus" ); + } else { + $( this ).blur(); + } + }) + .blur(function() { + $( this ).removeClass( "ui-state-focus" ); + }); + + this.handles.each(function( i ) { + $( this ).data( "index.ui-slider-handle", i ); + }); + + this.handles + .keydown(function( event ) { + var index = $( this ).data( "index.ui-slider-handle" ), + allowed, + curVal, + newVal, + step; + + if ( self.options.disabled ) { + return; + } + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + case $.ui.keyCode.END: + case $.ui.keyCode.PAGE_UP: + case $.ui.keyCode.PAGE_DOWN: + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + event.preventDefault(); + if ( !self._keySliding ) { + self._keySliding = true; + $( this ).addClass( "ui-state-active" ); + allowed = self._start( event, index ); + if ( allowed === false ) { + return; + } + } + break; + } + + step = self.options.step; + if ( self.options.values && self.options.values.length ) { + curVal = newVal = self.values( index ); + } else { + curVal = newVal = self.value(); + } + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + newVal = self._valueMin(); + break; + case $.ui.keyCode.END: + newVal = self._valueMax(); + break; + case $.ui.keyCode.PAGE_UP: + newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.PAGE_DOWN: + newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + if ( curVal === self._valueMax() ) { + return; + } + newVal = self._trimAlignValue( curVal + step ); + break; + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + if ( curVal === self._valueMin() ) { + return; + } + newVal = self._trimAlignValue( curVal - step ); + break; + } + + self._slide( event, index, newVal ); + }) + .keyup(function( event ) { + var index = $( this ).data( "index.ui-slider-handle" ); + + if ( self._keySliding ) { + self._keySliding = false; + self._stop( event, index ); + self._change( event, index ); + $( this ).removeClass( "ui-state-active" ); + } + + }); + + this._refreshValue(); + + this._animateOff = false; + }, + + destroy: function() { + this.handles.remove(); + this.range.remove(); + + this.element + .removeClass( "ui-slider" + + " ui-slider-horizontal" + + " ui-slider-vertical" + + " ui-slider-disabled" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all" ) + .removeData( "slider" ) + .unbind( ".slider" ); + + this._mouseDestroy(); + + return this; + }, + + _mouseCapture: function( event ) { + var o = this.options, + position, + normValue, + distance, + closestHandle, + self, + index, + allowed, + offset, + mouseOverHandle; + + if ( o.disabled ) { + return false; + } + + this.elementSize = { + width: this.element.outerWidth(), + height: this.element.outerHeight() + }; + this.elementOffset = this.element.offset(); + + position = { x: event.pageX, y: event.pageY }; + normValue = this._normValueFromMouse( position ); + distance = this._valueMax() - this._valueMin() + 1; + self = this; + this.handles.each(function( i ) { + var thisDistance = Math.abs( normValue - self.values(i) ); + if ( distance > thisDistance ) { + distance = thisDistance; + closestHandle = $( this ); + index = i; + } + }); + + // workaround for bug #3736 (if both handles of a range are at 0, + // the first is always used as the one with least distance, + // and moving it is obviously prevented by preventing negative ranges) + if( o.range === true && this.values(1) === o.min ) { + index += 1; + closestHandle = $( this.handles[index] ); + } + + allowed = this._start( event, index ); + if ( allowed === false ) { + return false; + } + this._mouseSliding = true; + + self._handleIndex = index; + + closestHandle + .addClass( "ui-state-active" ) + .focus(); + + offset = closestHandle.offset(); + mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); + this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { + left: event.pageX - offset.left - ( closestHandle.width() / 2 ), + top: event.pageY - offset.top - + ( closestHandle.height() / 2 ) - + ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - + ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + + ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) + }; + + if ( !this.handles.hasClass( "ui-state-hover" ) ) { + this._slide( event, index, normValue ); + } + this._animateOff = true; + return true; + }, + + _mouseStart: function( event ) { + return true; + }, + + _mouseDrag: function( event ) { + var position = { x: event.pageX, y: event.pageY }, + normValue = this._normValueFromMouse( position ); + + this._slide( event, this._handleIndex, normValue ); + + return false; + }, + + _mouseStop: function( event ) { + this.handles.removeClass( "ui-state-active" ); + this._mouseSliding = false; + + this._stop( event, this._handleIndex ); + this._change( event, this._handleIndex ); + + this._handleIndex = null; + this._clickOffset = null; + this._animateOff = false; + + return false; + }, + + _detectOrientation: function() { + this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; + }, + + _normValueFromMouse: function( position ) { + var pixelTotal, + pixelMouse, + percentMouse, + valueTotal, + valueMouse; + + if ( this.orientation === "horizontal" ) { + pixelTotal = this.elementSize.width; + pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); + } else { + pixelTotal = this.elementSize.height; + pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); + } + + percentMouse = ( pixelMouse / pixelTotal ); + if ( percentMouse > 1 ) { + percentMouse = 1; + } + if ( percentMouse < 0 ) { + percentMouse = 0; + } + if ( this.orientation === "vertical" ) { + percentMouse = 1 - percentMouse; + } + + valueTotal = this._valueMax() - this._valueMin(); + valueMouse = this._valueMin() + percentMouse * valueTotal; + + return this._trimAlignValue( valueMouse ); + }, + + _start: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + return this._trigger( "start", event, uiHash ); + }, + + _slide: function( event, index, newVal ) { + var otherVal, + newValues, + allowed; + + if ( this.options.values && this.options.values.length ) { + otherVal = this.values( index ? 0 : 1 ); + + if ( ( this.options.values.length === 2 && this.options.range === true ) && + ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) + ) { + newVal = otherVal; + } + + if ( newVal !== this.values( index ) ) { + newValues = this.values(); + newValues[ index ] = newVal; + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal, + values: newValues + } ); + otherVal = this.values( index ? 0 : 1 ); + if ( allowed !== false ) { + this.values( index, newVal, true ); + } + } + } else { + if ( newVal !== this.value() ) { + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal + } ); + if ( allowed !== false ) { + this.value( newVal ); + } + } + } + }, + + _stop: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + + this._trigger( "stop", event, uiHash ); + }, + + _change: function( event, index ) { + if ( !this._keySliding && !this._mouseSliding ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + + this._trigger( "change", event, uiHash ); + } + }, + + value: function( newValue ) { + if ( arguments.length ) { + this.options.value = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, 0 ); + return; + } + + return this._value(); + }, + + values: function( index, newValue ) { + var vals, + newValues, + i; + + if ( arguments.length > 1 ) { + this.options.values[ index ] = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, index ); + return; + } + + if ( arguments.length ) { + if ( $.isArray( arguments[ 0 ] ) ) { + vals = this.options.values; + newValues = arguments[ 0 ]; + for ( i = 0; i < vals.length; i += 1 ) { + vals[ i ] = this._trimAlignValue( newValues[ i ] ); + this._change( null, i ); + } + this._refreshValue(); + } else { + if ( this.options.values && this.options.values.length ) { + return this._values( index ); + } else { + return this.value(); + } + } + } else { + return this._values(); + } + }, + + _setOption: function( key, value ) { + var i, + valsLength = 0; + + if ( $.isArray( this.options.values ) ) { + valsLength = this.options.values.length; + } + + $.Widget.prototype._setOption.apply( this, arguments ); + + switch ( key ) { + case "disabled": + if ( value ) { + this.handles.filter( ".ui-state-focus" ).blur(); + this.handles.removeClass( "ui-state-hover" ); + this.handles.propAttr( "disabled", true ); + this.element.addClass( "ui-disabled" ); + } else { + this.handles.propAttr( "disabled", false ); + this.element.removeClass( "ui-disabled" ); + } + break; + case "orientation": + this._detectOrientation(); + this.element + .removeClass( "ui-slider-horizontal ui-slider-vertical" ) + .addClass( "ui-slider-" + this.orientation ); + this._refreshValue(); + break; + case "value": + this._animateOff = true; + this._refreshValue(); + this._change( null, 0 ); + this._animateOff = false; + break; + case "values": + this._animateOff = true; + this._refreshValue(); + for ( i = 0; i < valsLength; i += 1 ) { + this._change( null, i ); + } + this._animateOff = false; + break; + } + }, + + //internal value getter + // _value() returns value trimmed by min and max, aligned by step + _value: function() { + var val = this.options.value; + val = this._trimAlignValue( val ); + + return val; + }, + + //internal values getter + // _values() returns array of values trimmed by min and max, aligned by step + // _values( index ) returns single value trimmed by min and max, aligned by step + _values: function( index ) { + var val, + vals, + i; + + if ( arguments.length ) { + val = this.options.values[ index ]; + val = this._trimAlignValue( val ); + + return val; + } else { + // .slice() creates a copy of the array + // this copy gets trimmed by min and max and then returned + vals = this.options.values.slice(); + for ( i = 0; i < vals.length; i+= 1) { + vals[ i ] = this._trimAlignValue( vals[ i ] ); + } + + return vals; + } + }, + + // returns the step-aligned value that val is closest to, between (inclusive) min and max + _trimAlignValue: function( val ) { + if ( val <= this._valueMin() ) { + return this._valueMin(); + } + if ( val >= this._valueMax() ) { + return this._valueMax(); + } + var step = ( this.options.step > 0 ) ? this.options.step : 1, + valModStep = (val - this._valueMin()) % step, + alignValue = val - valModStep; + + if ( Math.abs(valModStep) * 2 >= step ) { + alignValue += ( valModStep > 0 ) ? step : ( -step ); + } + + // Since JavaScript has problems with large floats, round + // the final value to 5 digits after the decimal point (see #4124) + return parseFloat( alignValue.toFixed(5) ); + }, + + _valueMin: function() { + return this.options.min; + }, + + _valueMax: function() { + return this.options.max; + }, + + _refreshValue: function() { + var oRange = this.options.range, + o = this.options, + self = this, + animate = ( !this._animateOff ) ? o.animate : false, + valPercent, + _set = {}, + lastValPercent, + value, + valueMin, + valueMax; + + if ( this.options.values && this.options.values.length ) { + this.handles.each(function( i, j ) { + valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100; + _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + if ( self.options.range === true ) { + if ( self.orientation === "horizontal" ) { + if ( i === 0 ) { + self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); + } + if ( i === 1 ) { + self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } else { + if ( i === 0 ) { + self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); + } + if ( i === 1 ) { + self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } + } + lastValPercent = valPercent; + }); + } else { + value = this.value(); + valueMin = this._valueMin(); + valueMax = this._valueMax(); + valPercent = ( valueMax !== valueMin ) ? + ( value - valueMin ) / ( valueMax - valueMin ) * 100 : + 0; + _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + + if ( oRange === "min" && this.orientation === "horizontal" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "horizontal" ) { + this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + if ( oRange === "min" && this.orientation === "vertical" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "vertical" ) { + this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } + } + +}); + +$.extend( $.ui.slider, { + version: "1.8.23" +}); + +}(jQuery)); + +(function( $, undefined ) { + +var tabId = 0, + listId = 0; + +function getNextTabId() { + return ++tabId; +} + +function getNextListId() { + return ++listId; +} + +$.widget( "ui.tabs", { + options: { + add: null, + ajaxOptions: null, + cache: false, + cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } + collapsible: false, + disable: null, + disabled: [], + enable: null, + event: "click", + fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } + idPrefix: "ui-tabs-", + load: null, + panelTemplate: "
", + remove: null, + select: null, + show: null, + spinner: "Loading…", + tabTemplate: "
  • #{label}
  • " + }, + + _create: function() { + this._tabify( true ); + }, + + _setOption: function( key, value ) { + if ( key == "selected" ) { + if (this.options.collapsible && value == this.options.selected ) { + return; + } + this.select( value ); + } else { + this.options[ key ] = value; + this._tabify(); + } + }, + + _tabId: function( a ) { + return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || + this.options.idPrefix + getNextTabId(); + }, + + _sanitizeSelector: function( hash ) { + // we need this because an id may contain a ":" + return hash.replace( /:/g, "\\:" ); + }, + + _cookie: function() { + var cookie = this.cookie || + ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() ); + return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) ); + }, + + _ui: function( tab, panel ) { + return { + tab: tab, + panel: panel, + index: this.anchors.index( tab ) + }; + }, + + _cleanup: function() { + // restore all former loading tabs labels + this.lis.filter( ".ui-state-processing" ) + .removeClass( "ui-state-processing" ) + .find( "span:data(label.tabs)" ) + .each(function() { + var el = $( this ); + el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" ); + }); + }, + + _tabify: function( init ) { + var self = this, + o = this.options, + fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash + + this.list = this.element.find( "ol,ul" ).eq( 0 ); + this.lis = $( " > li:has(a[href])", this.list ); + this.anchors = this.lis.map(function() { + return $( "a", this )[ 0 ]; + }); + this.panels = $( [] ); + + this.anchors.each(function( i, a ) { + var href = $( a ).attr( "href" ); + // For dynamically created HTML that contains a hash as href IE < 8 expands + // such href to the full page url with hash and then misinterprets tab as ajax. + // Same consideration applies for an added tab with a fragment identifier + // since a[href=#fragment-identifier] does unexpectedly not match. + // Thus normalize href attribute... + var hrefBase = href.split( "#" )[ 0 ], + baseEl; + if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] || + ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) { + href = a.hash; + a.href = href; + } + + // inline tab + if ( fragmentId.test( href ) ) { + self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) ); + // remote tab + // prevent loading the page itself if href is just "#" + } else if ( href && href !== "#" ) { + // required for restore on destroy + $.data( a, "href.tabs", href ); + + // TODO until #3808 is fixed strip fragment identifier from url + // (IE fails to load from such url) + $.data( a, "load.tabs", href.replace( /#.*$/, "" ) ); + + var id = self._tabId( a ); + a.href = "#" + id; + var $panel = self.element.find( "#" + id ); + if ( !$panel.length ) { + $panel = $( o.panelTemplate ) + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .insertAfter( self.panels[ i - 1 ] || self.list ); + $panel.data( "destroy.tabs", true ); + } + self.panels = self.panels.add( $panel ); + // invalid tab href + } else { + o.disabled.push( i ); + } + }); + + // initialization from scratch + if ( init ) { + // attach necessary classes for styling + this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); + this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); + this.lis.addClass( "ui-state-default ui-corner-top" ); + this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ); + + // Selected tab + // use "selected" option or try to retrieve: + // 1. from fragment identifier in url + // 2. from cookie + // 3. from selected class attribute on
  • + if ( o.selected === undefined ) { + if ( location.hash ) { + this.anchors.each(function( i, a ) { + if ( a.hash == location.hash ) { + o.selected = i; + return false; + } + }); + } + if ( typeof o.selected !== "number" && o.cookie ) { + o.selected = parseInt( self._cookie(), 10 ); + } + if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { + o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); + } + o.selected = o.selected || ( this.lis.length ? 0 : -1 ); + } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release + o.selected = -1; + } + + // sanity check - default to first tab... + o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) + ? o.selected + : 0; + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + // A selected tab cannot become disabled. + o.disabled = $.unique( o.disabled.concat( + $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) { + return self.lis.index( n ); + }) + ) ).sort(); + + if ( $.inArray( o.selected, o.disabled ) != -1 ) { + o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 ); + } + + // highlight selected tab + this.panels.addClass( "ui-tabs-hide" ); + this.lis.removeClass( "ui-tabs-selected ui-state-active" ); + // check for length avoids error when initializing empty list + if ( o.selected >= 0 && this.anchors.length ) { + self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" ); + this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); + + // seems to be expected behavior that the show callback is fired + self.element.queue( "tabs", function() { + self._trigger( "show", null, + self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); + }); + + this.load( o.selected ); + } + + // clean up to avoid memory leaks in certain versions of IE 6 + // TODO: namespace this event + $( window ).bind( "unload", function() { + self.lis.add( self.anchors ).unbind( ".tabs" ); + self.lis = self.anchors = self.panels = null; + }); + // update selected after add/remove + } else { + o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); + } + + // update collapsible + // TODO: use .toggleClass() + this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" ); + + // set or update cookie after init and add/remove respectively + if ( o.cookie ) { + this._cookie( o.selected, o.cookie ); + } + + // disable tabs + for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { + $( li )[ $.inArray( i, o.disabled ) != -1 && + // TODO: use .toggleClass() + !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" ); + } + + // reset cache if switching from cached to not cached + if ( o.cache === false ) { + this.anchors.removeData( "cache.tabs" ); + } + + // remove all handlers before, tabify may run on existing tabs after add or option change + this.lis.add( this.anchors ).unbind( ".tabs" ); + + if ( o.event !== "mouseover" ) { + var addState = function( state, el ) { + if ( el.is( ":not(.ui-state-disabled)" ) ) { + el.addClass( "ui-state-" + state ); + } + }; + var removeState = function( state, el ) { + el.removeClass( "ui-state-" + state ); + }; + this.lis.bind( "mouseover.tabs" , function() { + addState( "hover", $( this ) ); + }); + this.lis.bind( "mouseout.tabs", function() { + removeState( "hover", $( this ) ); + }); + this.anchors.bind( "focus.tabs", function() { + addState( "focus", $( this ).closest( "li" ) ); + }); + this.anchors.bind( "blur.tabs", function() { + removeState( "focus", $( this ).closest( "li" ) ); + }); + } + + // set up animations + var hideFx, showFx; + if ( o.fx ) { + if ( $.isArray( o.fx ) ) { + hideFx = o.fx[ 0 ]; + showFx = o.fx[ 1 ]; + } else { + hideFx = showFx = o.fx; + } + } + + // Reset certain styles left over from animation + // and prevent IE's ClearType bug... + function resetStyle( $el, fx ) { + $el.css( "display", "" ); + if ( !$.support.opacity && fx.opacity ) { + $el[ 0 ].style.removeAttribute( "filter" ); + } + } + + // Show a tab... + var showTab = showFx + ? function( clicked, $show ) { + $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); + $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way + .animate( showFx, showFx.duration || "normal", function() { + resetStyle( $show, showFx ); + self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); + }); + } + : function( clicked, $show ) { + $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); + $show.removeClass( "ui-tabs-hide" ); + self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); + }; + + // Hide a tab, $show is optional... + var hideTab = hideFx + ? function( clicked, $hide ) { + $hide.animate( hideFx, hideFx.duration || "normal", function() { + self.lis.removeClass( "ui-tabs-selected ui-state-active" ); + $hide.addClass( "ui-tabs-hide" ); + resetStyle( $hide, hideFx ); + self.element.dequeue( "tabs" ); + }); + } + : function( clicked, $hide, $show ) { + self.lis.removeClass( "ui-tabs-selected ui-state-active" ); + $hide.addClass( "ui-tabs-hide" ); + self.element.dequeue( "tabs" ); + }; + + // attach tab event handler, unbind to avoid duplicates from former tabifying... + this.anchors.bind( o.event + ".tabs", function() { + var el = this, + $li = $(el).closest( "li" ), + $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), + $show = self.element.find( self._sanitizeSelector( el.hash ) ); + + // If tab is already selected and not collapsible or tab disabled or + // or is already loading or click callback returns false stop here. + // Check if click handler returns false last so that it is not executed + // for a disabled or loading tab! + if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || + $li.hasClass( "ui-state-disabled" ) || + $li.hasClass( "ui-state-processing" ) || + self.panels.filter( ":animated" ).length || + self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) { + this.blur(); + return false; + } + + o.selected = self.anchors.index( this ); + + self.abort(); + + // if tab may be closed + if ( o.collapsible ) { + if ( $li.hasClass( "ui-tabs-selected" ) ) { + o.selected = -1; + + if ( o.cookie ) { + self._cookie( o.selected, o.cookie ); + } + + self.element.queue( "tabs", function() { + hideTab( el, $hide ); + }).dequeue( "tabs" ); + + this.blur(); + return false; + } else if ( !$hide.length ) { + if ( o.cookie ) { + self._cookie( o.selected, o.cookie ); + } + + self.element.queue( "tabs", function() { + showTab( el, $show ); + }); + + // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 + self.load( self.anchors.index( this ) ); + + this.blur(); + return false; + } + } + + if ( o.cookie ) { + self._cookie( o.selected, o.cookie ); + } + + // show new tab + if ( $show.length ) { + if ( $hide.length ) { + self.element.queue( "tabs", function() { + hideTab( el, $hide ); + }); + } + self.element.queue( "tabs", function() { + showTab( el, $show ); + }); + + self.load( self.anchors.index( this ) ); + } else { + throw "jQuery UI Tabs: Mismatching fragment identifier."; + } + + // Prevent IE from keeping other link focussed when using the back button + // and remove dotted border from clicked link. This is controlled via CSS + // in modern browsers; blur() removes focus from address bar in Firefox + // which can become a usability and annoying problem with tabs('rotate'). + if ( $.browser.msie ) { + this.blur(); + } + }); + + // disable click in any case + this.anchors.bind( "click.tabs", function(){ + return false; + }); + }, + + _getIndex: function( index ) { + // meta-function to give users option to provide a href string instead of a numerical index. + // also sanitizes numerical indexes to valid values. + if ( typeof index == "string" ) { + index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); + } + + return index; + }, + + destroy: function() { + var o = this.options; + + this.abort(); + + this.element + .unbind( ".tabs" ) + .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ) + .removeData( "tabs" ); + + this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); + + this.anchors.each(function() { + var href = $.data( this, "href.tabs" ); + if ( href ) { + this.href = href; + } + var $this = $( this ).unbind( ".tabs" ); + $.each( [ "href", "load", "cache" ], function( i, prefix ) { + $this.removeData( prefix + ".tabs" ); + }); + }); + + this.lis.unbind( ".tabs" ).add( this.panels ).each(function() { + if ( $.data( this, "destroy.tabs" ) ) { + $( this ).remove(); + } else { + $( this ).removeClass([ + "ui-state-default", + "ui-corner-top", + "ui-tabs-selected", + "ui-state-active", + "ui-state-hover", + "ui-state-focus", + "ui-state-disabled", + "ui-tabs-panel", + "ui-widget-content", + "ui-corner-bottom", + "ui-tabs-hide" + ].join( " " ) ); + } + }); + + if ( o.cookie ) { + this._cookie( null, o.cookie ); + } + + return this; + }, + + add: function( url, label, index ) { + if ( index === undefined ) { + index = this.anchors.length; + } + + var self = this, + o = this.options, + $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ), + id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] ); + + $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true ); + + // try to find an existing element before creating a new one + var $panel = self.element.find( "#" + id ); + if ( !$panel.length ) { + $panel = $( o.panelTemplate ) + .attr( "id", id ) + .data( "destroy.tabs", true ); + } + $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); + + if ( index >= this.lis.length ) { + $li.appendTo( this.list ); + $panel.appendTo( this.list[ 0 ].parentNode ); + } else { + $li.insertBefore( this.lis[ index ] ); + $panel.insertBefore( this.panels[ index ] ); + } + + o.disabled = $.map( o.disabled, function( n, i ) { + return n >= index ? ++n : n; + }); + + this._tabify(); + + if ( this.anchors.length == 1 ) { + o.selected = 0; + $li.addClass( "ui-tabs-selected ui-state-active" ); + $panel.removeClass( "ui-tabs-hide" ); + this.element.queue( "tabs", function() { + self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); + }); + + this.load( 0 ); + } + + this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + return this; + }, + + remove: function( index ) { + index = this._getIndex( index ); + var o = this.options, + $li = this.lis.eq( index ).remove(), + $panel = this.panels.eq( index ).remove(); + + // If selected tab was removed focus tab to the right or + // in case the last tab was removed the tab to the left. + if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { + this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); + } + + o.disabled = $.map( + $.grep( o.disabled, function(n, i) { + return n != index; + }), + function( n, i ) { + return n >= index ? --n : n; + }); + + this._tabify(); + + this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); + return this; + }, + + enable: function( index ) { + index = this._getIndex( index ); + var o = this.options; + if ( $.inArray( index, o.disabled ) == -1 ) { + return; + } + + this.lis.eq( index ).removeClass( "ui-state-disabled" ); + o.disabled = $.grep( o.disabled, function( n, i ) { + return n != index; + }); + + this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + return this; + }, + + disable: function( index ) { + index = this._getIndex( index ); + var self = this, o = this.options; + // cannot disable already selected tab + if ( index != o.selected ) { + this.lis.eq( index ).addClass( "ui-state-disabled" ); + + o.disabled.push( index ); + o.disabled.sort(); + + this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + } + + return this; + }, + + select: function( index ) { + index = this._getIndex( index ); + if ( index == -1 ) { + if ( this.options.collapsible && this.options.selected != -1 ) { + index = this.options.selected; + } else { + return this; + } + } + this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); + return this; + }, + + load: function( index ) { + index = this._getIndex( index ); + var self = this, + o = this.options, + a = this.anchors.eq( index )[ 0 ], + url = $.data( a, "load.tabs" ); + + this.abort(); + + // not remote or from cache + if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) { + this.element.dequeue( "tabs" ); + return; + } + + // load remote from here on + this.lis.eq( index ).addClass( "ui-state-processing" ); + + if ( o.spinner ) { + var span = $( "span", a ); + span.data( "label.tabs", span.html() ).html( o.spinner ); + } + + this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, { + url: url, + success: function( r, s ) { + self.element.find( self._sanitizeSelector( a.hash ) ).html( r ); + + // take care of tab labels + self._cleanup(); + + if ( o.cache ) { + $.data( a, "cache.tabs", true ); + } + + self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); + try { + o.ajaxOptions.success( r, s ); + } + catch ( e ) {} + }, + error: function( xhr, s, e ) { + // take care of tab labels + self._cleanup(); + + self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); + try { + // Passing index avoid a race condition when this method is + // called after the user has selected another tab. + // Pass the anchor that initiated this request allows + // loadError to manipulate the tab content panel via $(a.hash) + o.ajaxOptions.error( xhr, s, index, a ); + } + catch ( e ) {} + } + } ) ); + + // last, so that load event is fired before show... + self.element.dequeue( "tabs" ); + + return this; + }, + + abort: function() { + // stop possibly running animations + this.element.queue( [] ); + this.panels.stop( false, true ); + + // "tabs" queue must not contain more than two elements, + // which are the callbacks for the latest clicked tab... + this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) ); + + // terminate pending requests from other tabs + if ( this.xhr ) { + this.xhr.abort(); + delete this.xhr; + } + + // take care of tab labels + this._cleanup(); + return this; + }, + + url: function( index, url ) { + this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url ); + return this; + }, + + length: function() { + return this.anchors.length; + } +}); + +$.extend( $.ui.tabs, { + version: "1.8.23" +}); + +/* + * Tabs Extensions + */ + +/* + * Rotate + */ +$.extend( $.ui.tabs.prototype, { + rotation: null, + rotate: function( ms, continuing ) { + var self = this, + o = this.options; + + var rotate = self._rotate || ( self._rotate = function( e ) { + clearTimeout( self.rotation ); + self.rotation = setTimeout(function() { + var t = o.selected; + self.select( ++t < self.anchors.length ? t : 0 ); + }, ms ); + + if ( e ) { + e.stopPropagation(); + } + }); + + var stop = self._unrotate || ( self._unrotate = !continuing + ? function(e) { + if (e.clientX) { // in case of a true click + self.rotate(null); + } + } + : function( e ) { + rotate(); + }); + + // start rotation + if ( ms ) { + this.element.bind( "tabsshow", rotate ); + this.anchors.bind( o.event + ".tabs", stop ); + rotate(); + // stop rotation + } else { + clearTimeout( self.rotation ); + this.element.unbind( "tabsshow", rotate ); + this.anchors.unbind( o.event + ".tabs", stop ); + delete this._rotate; + delete this._unrotate; + } + + return this; + } +}); + +})( jQuery ); \ No newline at end of file diff --git a/asset/slimscroll/jquery.slimscroll.min.js b/asset/slimscroll/jquery.slimscroll.min.js new file mode 100644 index 0000000..4a65411 --- /dev/null +++ b/asset/slimscroll/jquery.slimscroll.min.js @@ -0,0 +1,15 @@ +/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * Version: 1.1.1 + * + */ +(function(f){jQuery.fn.extend({slimScroll:function(l){var a=f.extend({width:"auto",height:"250px",size:"7px",color:"#000",position:"right",distance:"1px",start:"top",opacity:0.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:0.2,railDraggable:!0,railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,wheelStep:20,touchScrollStep:200},l);this.each(function(){function r(d){if(n){d=d||window.event;var c=0;d.wheelDelta&&(c=-d.wheelDelta/ +120);d.detail&&(c=d.detail/3);f(d.target||d.srcTarget).closest("."+a.wrapperClass).is(b.parent())&&g(c,!0);d.preventDefault&&!p&&d.preventDefault();p||(d.returnValue=!1)}}function g(d,f,h){var e=d,g=b.outerHeight()-c.outerHeight();f&&(e=parseInt(c.css("top"))+d*parseInt(a.wheelStep)/100*c.outerHeight(),e=Math.min(Math.max(e,0),g),e=0=b.outerHeight()?p=!0:(c.stop(!0,!0).fadeIn("fast"),a.railVisible&&h.stop(!0,!0).fadeIn("fast"))}function m(){a.alwaysVisible||(w=setTimeout(function(){if((!a.disableFadeOut||!n)&&!u&&!v)c.fadeOut("slow"),h.fadeOut("slow")},1E3))}var n,u,v,w,y,q,j,x,B=30,p=!1,b=f(this);if(b.parent().hasClass(a.wrapperClass)){var k=b.scrollTop(),c=b.parent().find("."+a.barClass),h=b.parent().find("."+a.railClass);t();if(f.isPlainObject(l)){if("scrollTo"in l)k= +parseInt(a.scrollTo);else if("scrollBy"in l)k+=parseInt(a.scrollBy);else if("destroy"in l){c.remove();h.remove();b.unwrap();return}g(k,!1,!0)}}else{a.height="auto"==a.height?b.parent().innerHeight():a.height;k=f("
    ").addClass(a.wrapperClass).css({position:"relative",overflow:"hidden",width:a.width,height:a.height});b.css({overflow:"hidden",width:a.width,height:a.height});var h=f("
    ").addClass(a.railClass).css({width:a.size,height:"100%",position:"absolute",top:0,display:a.alwaysVisible&& +a.railVisible?"block":"none","border-radius":a.size,background:a.railColor,opacity:a.railOpacity,zIndex:90}),c=f("
    ").addClass(a.barClass).css({background:a.color,width:a.size,position:"absolute",top:0,opacity:a.opacity,display:a.alwaysVisible?"block":"none","border-radius":a.size,BorderRadius:a.size,MozBorderRadius:a.size,WebkitBorderRadius:a.size,zIndex:99}),z="right"==a.position?{right:a.distance}:{left:a.distance};h.css(z);c.css(z);b.wrap(k);b.parent().append(c);b.parent().append(h); +a.railDraggable&&c.draggable({axis:"y",containment:"parent",start:function(){v=!0},stop:function(){v=!1;m()},drag:function(){g(0,f(this).position().top,!1)}});h.hover(function(){s()},function(){m()});c.hover(function(){u=!0},function(){u=!1});b.hover(function(){n=!0;s();m()},function(){n=!1;m()});b.bind("touchstart",function(a){a.originalEvent.touches.length&&(y=a.originalEvent.touches[0].pageY)});b.bind("touchmove",function(b){b.originalEvent.preventDefault();b.originalEvent.touches.length&&g((y- +b.originalEvent.touches[0].pageY)/a.touchScrollStep,!0)});"bottom"===a.start?(c.css({top:b.outerHeight()-c.outerHeight()}),g(0,!0)):"top"!==a.start&&(g(f(a.start).position().top,null,!0),a.alwaysVisible||c.hide());A();t()}});return this}});jQuery.fn.extend({slimscroll:jQuery.fn.slimScroll})})(jQuery); \ No newline at end of file diff --git a/asset/tablesorter/demo_table.css b/asset/tablesorter/demo_table.css new file mode 100644 index 0000000..7839c7e --- /dev/null +++ b/asset/tablesorter/demo_table.css @@ -0,0 +1,577 @@ +/* + * File: demo_table.css + * CVS: $Id$ + * Description: CSS descriptions for DataTables demo pages + * Author: Allan Jardine + * Created: Tue May 12 06:47:22 BST 2009 + * Modified: $Date$ by $Author$ + * Language: CSS + * Project: DataTables + * + * Copyright 2009 Allan Jardine. All Rights Reserved. + * + * *************************************************************************** + * DESCRIPTION + * + * The styles given here are suitable for the demos that are used with the standard DataTables + * distribution (see www.datatables.net). You will most likely wish to modify these styles to + * meet the layout requirements of your site. + * + * Common issues: + * 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is + * no conflict between the two pagination types. If you want to use full_numbers pagination + * ensure that you either have "example_alt_pagination" as a body class name, or better yet, + * modify that selector. + * Note that the path used for Images is relative. All images are by default located in + * ../images/ - relative to this CSS file. + */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables features + */ + +.dataTables_wrapper { + position: relative; + clear: both; + zoom: 1; /* Feeling sorry for IE */ +} + +.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 250px; + height: 30px; + margin-left: -125px; + margin-top: -15px; + padding: 14px 0 2px 0; + border: 1px solid #ddd; + text-align: center; + color: #999; + font-size: 14px; + background-color: white; +} + +.dataTables_length { + width: 40%; + float: left; +} + +.dataTables_filter { + width: 50%; + float: right; + text-align: right; +} + +.dataTables_info { + width: 60%; + float: left; +} + +.dataTables_paginate { + float: right; + text-align: right; +} + +/* Pagination nested */ +.paginate_disabled_previous, .paginate_enabled_previous, +.paginate_disabled_next, .paginate_enabled_next { + height: 19px; + float: left; + cursor: pointer; + *cursor: hand; + color: #111 !important; +} +.paginate_disabled_previous:hover, .paginate_enabled_previous:hover, +.paginate_disabled_next:hover, .paginate_enabled_next:hover { + text-decoration: none !important; +} +.paginate_disabled_previous:active, .paginate_enabled_previous:active, +.paginate_disabled_next:active, .paginate_enabled_next:active { + outline: none; +} + +.paginate_disabled_previous, +.paginate_disabled_next { + color: #666 !important; +} +.paginate_disabled_previous, .paginate_enabled_previous { + padding-left: 23px; +} +.paginate_disabled_next, .paginate_enabled_next { + padding-right: 23px; + margin-left: 10px; +} + +.paginate_disabled_previous { + background: url('images/back_disabled.png') no-repeat top left; +} + +.paginate_enabled_previous { + background: url('images/back_enabled.png') no-repeat top left; +} +.paginate_enabled_previous:hover { + background: url('images/back_enabled_hover.png') no-repeat top left; +} + +.paginate_disabled_next { + background: url('images/forward_disabled.png') no-repeat top right; +} + +.paginate_enabled_next { + background: url('images/forward_enabled.png') no-repeat top right; +} +.paginate_enabled_next:hover { + background: url('images/forward_enabled_hover.png') no-repeat top right; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables display + */ +table.display { + margin: 0 auto; + clear: both; + width: 100%; + + /* Note Firefox 3.5 and before have a bug with border-collapse + * ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 ) + * border-spacing: 0; is one possible option. Conditional-css.com is + * useful for this kind of thing + * + * Further note IE 6/7 has problems when calculating widths with border width. + * It subtracts one px relative to the other browsers from the first column, and + * adds one to the end... + * + * If you want that effect I'd suggest setting a border-top/left on th/td's and + * then filling in the gaps with other borders. + */ +} + +table.display thead th { + padding: 3px 18px 3px 10px; + border-bottom: 1px solid black; + font-weight: bold; + cursor: pointer; + * cursor: hand; +} + +table.display tfoot th { + padding: 3px 18px 3px 10px; + border-top: 1px solid black; + font-weight: bold; +} + +table.display tr.heading2 td { + border-bottom: 1px solid #aaa; +} + +table.display td { + padding: 3px 10px; +} + +table.display td.center { + text-align: center; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables sorting + */ + +.sorting_asc { + background: url('images/sort_asc.png') no-repeat center right; +} + +.sorting_desc { + background: url('images/sort_desc.png') no-repeat center right; +} + +.sorting { + background: url('images/sort_both.png') no-repeat center right; +} + +.sorting_asc_disabled { + background: url('images/sort_asc_disabled.png') no-repeat center right; +} + +.sorting_desc_disabled { + background: url('images/sort_desc_disabled.png') no-repeat center right; +} + +table.display thead th:active, +table.display thead td:active { + outline: none; +} + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables row classes + */ +table.display tr.odd.gradeA { + background-color: #ddffdd; +} + +table.display tr.even.gradeA { + background-color: #eeffee; +} + +table.display tr.odd.gradeC { + background-color: #ddddff; +} + +table.display tr.even.gradeC { + background-color: #eeeeff; +} + +table.display tr.odd.gradeX { + background-color: #ffdddd; +} + +table.display tr.even.gradeX { + background-color: #ffeeee; +} + +table.display tr.odd.gradeU { + background-color: #ddd; +} + +table.display tr.even.gradeU { + background-color: #eee; +} + + +tr.odd { + background-color: #E2E4FF; +} + +tr.even { + background-color: white; +} + + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Misc + */ +.dataTables_scroll { + clear: both; +} + +.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; +} + +.top, .bottom { + padding: 15px; + background-color: #F5F5F5; + border: 1px solid #CCCCCC; +} + +.top .dataTables_info { + float: none; +} + +.clear { + clear: both; +} + +.dataTables_empty { + text-align: center; +} + +tfoot input { + margin: 0.5em 0; + width: 100%; + color: #444; +} + +tfoot input.search_init { + color: #999; +} + +td.group { + background-color: #d1cfd0; + border-bottom: 2px solid #A19B9E; + border-top: 2px solid #A19B9E; +} + +td.details { + background-color: #d1cfd0; + border: 2px solid #A19B9E; +} + + +.example_alt_pagination div.dataTables_info { + width: 40%; +} + +.paging_full_numbers { + width: 400px; + height: 22px; + line-height: 22px; +} + +.paging_full_numbers a:active { + outline: none +} + +.paging_full_numbers a:hover { + text-decoration: none; +} + +.paging_full_numbers a.paginate_button, + .paging_full_numbers a.paginate_active { + border: 1px solid #aaa; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + padding: 2px 5px; + margin: 0 3px; + cursor: pointer; + *cursor: hand; + color: #333 !important; +} + +.paging_full_numbers a.paginate_button { + background-color: #ddd; +} + +.paging_full_numbers a.paginate_button:hover { + background-color: #ccc; + text-decoration: none !important; +} + +.paging_full_numbers a.paginate_active { + background-color: #99B3FF; +} + +table.display tr.even.row_selected td { + background-color: #B0BED9; +} + +table.display tr.odd.row_selected td { + background-color: #9FAFD1; +} + + +/* + * Sorting classes for columns + */ +/* For the standard odd/even */ +tr.odd td.sorting_1 { + background-color: #D3D6FF; +} + +tr.odd td.sorting_2 { + background-color: #DADCFF; +} + +tr.odd td.sorting_3 { + background-color: #E0E2FF; +} + +tr.even td.sorting_1 { + background-color: #EAEBFF; +} + +tr.even td.sorting_2 { + background-color: #F2F3FF; +} + +tr.even td.sorting_3 { + background-color: #F9F9FF; +} + + +/* For the Conditional-CSS grading rows */ +/* + Colour calculations (based off the main row colours) + Level 1: + dd > c4 + ee > d5 + Level 2: + dd > d1 + ee > e2 + */ +tr.odd.gradeA td.sorting_1 { + background-color: #c4ffc4; +} + +tr.odd.gradeA td.sorting_2 { + background-color: #d1ffd1; +} + +tr.odd.gradeA td.sorting_3 { + background-color: #d1ffd1; +} + +tr.even.gradeA td.sorting_1 { + background-color: #d5ffd5; +} + +tr.even.gradeA td.sorting_2 { + background-color: #e2ffe2; +} + +tr.even.gradeA td.sorting_3 { + background-color: #e2ffe2; +} + +tr.odd.gradeC td.sorting_1 { + background-color: #c4c4ff; +} + +tr.odd.gradeC td.sorting_2 { + background-color: #d1d1ff; +} + +tr.odd.gradeC td.sorting_3 { + background-color: #d1d1ff; +} + +tr.even.gradeC td.sorting_1 { + background-color: #d5d5ff; +} + +tr.even.gradeC td.sorting_2 { + background-color: #e2e2ff; +} + +tr.even.gradeC td.sorting_3 { + background-color: #e2e2ff; +} + +tr.odd.gradeX td.sorting_1 { + background-color: #ffc4c4; +} + +tr.odd.gradeX td.sorting_2 { + background-color: #ffd1d1; +} + +tr.odd.gradeX td.sorting_3 { + background-color: #ffd1d1; +} + +tr.even.gradeX td.sorting_1 { + background-color: #ffd5d5; +} + +tr.even.gradeX td.sorting_2 { + background-color: #ffe2e2; +} + +tr.even.gradeX td.sorting_3 { + background-color: #ffe2e2; +} + +tr.odd.gradeU td.sorting_1 { + background-color: #c4c4c4; +} + +tr.odd.gradeU td.sorting_2 { + background-color: #d1d1d1; +} + +tr.odd.gradeU td.sorting_3 { + background-color: #d1d1d1; +} + +tr.even.gradeU td.sorting_1 { + background-color: #d5d5d5; +} + +tr.even.gradeU td.sorting_2 { + background-color: #e2e2e2; +} + +tr.even.gradeU td.sorting_3 { + background-color: #e2e2e2; +} + + +/* + * Row highlighting example + */ +.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted { + background-color: #ECFFB3; +} + +.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted { + background-color: #E6FF99; +} + +.ex_highlight_row #example tr.even:hover { + background-color: #ECFFB3; +} + +.ex_highlight_row #example tr.even:hover td.sorting_1 { + background-color: #DDFF75; +} + +.ex_highlight_row #example tr.even:hover td.sorting_2 { + background-color: #E7FF9E; +} + +.ex_highlight_row #example tr.even:hover td.sorting_3 { + background-color: #E2FF89; +} + +.ex_highlight_row #example tr.odd:hover { + background-color: #E6FF99; +} + +.ex_highlight_row #example tr.odd:hover td.sorting_1 { + background-color: #D6FF5C; +} + +.ex_highlight_row #example tr.odd:hover td.sorting_2 { + background-color: #E0FF84; +} + +.ex_highlight_row #example tr.odd:hover td.sorting_3 { + background-color: #DBFF70; +} + + +/* + * KeyTable + */ +table.KeyTable td { + border: 3px solid transparent; +} + +table.KeyTable td.focus { + border: 3px solid #3366FF; +} + +table.display tr.gradeA { + background-color: #eeffee; +} + +table.display tr.gradeC { + background-color: #ddddff; +} + +table.display tr.gradeX { + background-color: #ffdddd; +} + +table.display tr.gradeU { + background-color: #ddd; +} + +div.box { + height: 100px; + padding: 10px; + overflow: auto; + border: 1px solid #8080FF; + background-color: #E5E5FF; +} diff --git a/asset/tablesorter/images/Sorting icons.psd b/asset/tablesorter/images/Sorting icons.psd new file mode 100644 index 0000000..53b2e06 Binary files /dev/null and b/asset/tablesorter/images/Sorting icons.psd differ diff --git a/asset/tablesorter/images/back_disabled.png b/asset/tablesorter/images/back_disabled.png new file mode 100644 index 0000000..881de79 Binary files /dev/null and b/asset/tablesorter/images/back_disabled.png differ diff --git a/asset/tablesorter/images/back_enabled.png b/asset/tablesorter/images/back_enabled.png new file mode 100644 index 0000000..c608682 Binary files /dev/null and b/asset/tablesorter/images/back_enabled.png differ diff --git a/asset/tablesorter/images/back_enabled_hover.png b/asset/tablesorter/images/back_enabled_hover.png new file mode 100644 index 0000000..d300f10 Binary files /dev/null and b/asset/tablesorter/images/back_enabled_hover.png differ diff --git a/asset/tablesorter/images/favicon.ico b/asset/tablesorter/images/favicon.ico new file mode 100644 index 0000000..6eeaa2a Binary files /dev/null and b/asset/tablesorter/images/favicon.ico differ diff --git a/asset/tablesorter/images/forward_disabled.png b/asset/tablesorter/images/forward_disabled.png new file mode 100644 index 0000000..6a6ded7 Binary files /dev/null and b/asset/tablesorter/images/forward_disabled.png differ diff --git a/asset/tablesorter/images/forward_enabled.png b/asset/tablesorter/images/forward_enabled.png new file mode 100644 index 0000000..a4e6b53 Binary files /dev/null and b/asset/tablesorter/images/forward_enabled.png differ diff --git a/asset/tablesorter/images/forward_enabled_hover.png b/asset/tablesorter/images/forward_enabled_hover.png new file mode 100644 index 0000000..fc46c5e Binary files /dev/null and b/asset/tablesorter/images/forward_enabled_hover.png differ diff --git a/asset/tablesorter/images/sort_asc.png b/asset/tablesorter/images/sort_asc.png new file mode 100644 index 0000000..a88d797 Binary files /dev/null and b/asset/tablesorter/images/sort_asc.png differ diff --git a/asset/tablesorter/images/sort_asc_disabled.png b/asset/tablesorter/images/sort_asc_disabled.png new file mode 100644 index 0000000..4e144cf Binary files /dev/null and b/asset/tablesorter/images/sort_asc_disabled.png differ diff --git a/asset/tablesorter/images/sort_both.png b/asset/tablesorter/images/sort_both.png new file mode 100644 index 0000000..1867040 Binary files /dev/null and b/asset/tablesorter/images/sort_both.png differ diff --git a/asset/tablesorter/images/sort_desc.png b/asset/tablesorter/images/sort_desc.png new file mode 100644 index 0000000..def071e Binary files /dev/null and b/asset/tablesorter/images/sort_desc.png differ diff --git a/asset/tablesorter/images/sort_desc_disabled.png b/asset/tablesorter/images/sort_desc_disabled.png new file mode 100644 index 0000000..7824973 Binary files /dev/null and b/asset/tablesorter/images/sort_desc_disabled.png differ diff --git a/asset/tablesorter/jquery.dataTables.min.js b/asset/tablesorter/jquery.dataTables.min.js new file mode 100644 index 0000000..02694a4 --- /dev/null +++ b/asset/tablesorter/jquery.dataTables.min.js @@ -0,0 +1,155 @@ +/* + * File: jquery.dataTables.min.js + * Version: 1.9.4 + * Author: Allan Jardine (www.sprymedia.co.uk) + * Info: www.datatables.net + * + * Copyright 2008-2012 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + */ +(function(X,l,n){var L=function(h){var j=function(e){function o(a,b){var c=j.defaults.columns,d=a.aoColumns.length,c=h.extend({},j.models.oColumn,c,{sSortingClass:a.oClasses.sSortable,sSortingClassJUI:a.oClasses.sSortJUI,nTh:b?b:l.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.oDefaults:d});a.aoColumns.push(c);if(a.aoPreSearchCols[d]===n||null===a.aoPreSearchCols[d])a.aoPreSearchCols[d]=h.extend({},j.models.oSearch);else if(c=a.aoPreSearchCols[d], +c.bRegex===n&&(c.bRegex=!0),c.bSmart===n&&(c.bSmart=!0),c.bCaseInsensitive===n)c.bCaseInsensitive=!0;m(a,d,null)}function m(a,b,c){var d=a.aoColumns[b];c!==n&&null!==c&&(c.mDataProp&&!c.mData&&(c.mData=c.mDataProp),c.sType!==n&&(d.sType=c.sType,d._bAutoType=!1),h.extend(d,c),p(d,c,"sWidth","sWidthOrig"),c.iDataSort!==n&&(d.aDataSort=[c.iDataSort]),p(d,c,"aDataSort"));var i=d.mRender?Q(d.mRender):null,f=Q(d.mData);d.fnGetData=function(a,b){var c=f(a,b);return d.mRender&&b&&""!==b?i(c,b,a):c};d.fnSetData= +L(d.mData);a.oFeatures.bSort||(d.bSortable=!1);!d.bSortable||-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableNone,d.sSortingClassJUI=""):-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortable,d.sSortingClassJUI=a.oClasses.sSortJUI):-1!=h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableAsc,d.sSortingClassJUI=a.oClasses.sSortJUIAscAllowed):-1== +h.inArray("asc",d.asSorting)&&-1!=h.inArray("desc",d.asSorting)&&(d.sSortingClass=a.oClasses.sSortableDesc,d.sSortingClassJUI=a.oClasses.sSortJUIDescAllowed)}function k(a){if(!1===a.oFeatures.bAutoWidth)return!1;da(a);for(var b=0,c=a.aoColumns.length;bj[f])d(a.aoColumns.length+j[f],b[i]);else if("string"===typeof j[f]){e=0;for(w=a.aoColumns.length;eb&&a[d]--; -1!=c&&a.splice(c,1)}function S(a,b,c){var d=a.aoColumns[c];return d.fnRender({iDataRow:b,iDataColumn:c,oSettings:a,aData:a.aoData[b]._aData,mDataProp:d.mData},v(a,b,c,"display"))}function ea(a,b){var c=a.aoData[b],d;if(null===c.nTr){c.nTr=l.createElement("tr");c.nTr._DT_RowIndex=b;c._aData.DT_RowId&&(c.nTr.id=c._aData.DT_RowId);c._aData.DT_RowClass&& +(c.nTr.className=c._aData.DT_RowClass);for(var i=0,f=a.aoColumns.length;i=a.fnRecordsDisplay()?0:a.iInitDisplayStart,a.iInitDisplayStart=-1,y(a));if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++;else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!wa(a))return}else a.iDraw++;if(0!==a.aiDisplay.length){var g= +a._iDisplayStart;d=a._iDisplayEnd;a.oFeatures.bServerSide&&(g=0,d=a.aoData.length);for(;g")[0];a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=h('
    ')[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),i,f,g,e,w,o,k,m=0;m")[0];w=d[m+ +1];if("'"==w||'"'==w){o="";for(k=2;d[m+k]!=w;)o+=d[m+k],k++;"H"==o?o=a.oClasses.sJUIHeader:"F"==o&&(o=a.oClasses.sJUIFooter);-1!=o.indexOf(".")?(w=o.split("."),e.id=w[0].substr(1,w[0].length-1),e.className=w[1]):"#"==o.charAt(0)?e.id=o.substr(1,o.length-1):e.className=o;m+=k}c.appendChild(e);c=e}else if(">"==g)c=c.parentNode;else if("l"==g&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange)i=ya(a),f=1;else if("f"==g&&a.oFeatures.bFilter)i=za(a),f=1;else if("r"==g&&a.oFeatures.bProcessing)i=Aa(a),f= +1;else if("t"==g)i=Ba(a),f=1;else if("i"==g&&a.oFeatures.bInfo)i=Ca(a),f=1;else if("p"==g&&a.oFeatures.bPaginate)i=Da(a),f=1;else if(0!==j.ext.aoFeatures.length){e=j.ext.aoFeatures;k=0;for(w=e.length;k'):""===c?'':c+' ',d=l.createElement("div");d.className=a.oClasses.sFilter;d.innerHTML="";a.aanFeatures.f||(d.id=a.sTableId+"_filter");c=h('input[type="text"]',d);d._DT_Input=c[0];c.val(b.sSearch.replace('"',"""));c.bind("keyup.DT",function(){for(var c=a.aanFeatures.f,d=this.value===""?"":this.value, +g=0,e=c.length;g=b.length)a.aiDisplay.splice(0,a.aiDisplay.length),a.aiDisplay=a.aiDisplayMaster.slice();else if(a.aiDisplay.length==a.aiDisplayMaster.length||i.sSearch.length>b.length||1==c||0!==b.indexOf(i.sSearch)){a.aiDisplay.splice(0, +a.aiDisplay.length);la(a,1);for(b=0;b").html(c).text()); +return c.replace(/[\n\r]/g," ")}function ma(a,b,c,d){if(c)return a=b?a.split(" "):oa(a).split(" "),a="^(?=.*?"+a.join(")(?=.*?")+").*$",RegExp(a,d?"i":"");a=b?a:oa(a);return RegExp(a,d?"i":"")}function Ja(a,b){return"function"===typeof j.ext.ofnSearch[b]?j.ext.ofnSearch[b](a):null===a?"":"html"==b?a.replace(/[\r\n]/g," ").replace(/<.*?>/g,""):"string"===typeof a?a.replace(/[\r\n]/g," "):a}function oa(a){return a.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"), +"\\$1")}function Ca(a){var b=l.createElement("div");b.className=a.oClasses.sInfo;a.aanFeatures.i||(a.aoDrawCallback.push({fn:Ka,sName:"information"}),b.id=a.sTableId+"_info");a.nTable.setAttribute("aria-describedby",a.sTableId+"_info");return b}function Ka(a){if(a.oFeatures.bInfo&&0!==a.aanFeatures.i.length){var b=a.oLanguage,c=a._iDisplayStart+1,d=a.fnDisplayEnd(),i=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),g;g=0===f?b.sInfoEmpty:b.sInfo;f!=i&&(g+=" "+b.sInfoFiltered);g+=b.sInfoPostFix;g=ja(a,g); +null!==b.fnInfoCallback&&(g=b.fnInfoCallback.call(a.oInstance,a,c,d,i,f,g));a=a.aanFeatures.i;b=0;for(c=a.length;b",c,d,i=a.aLengthMenu;if(2==i.length&&"object"===typeof i[0]&&"object"===typeof i[1]){c=0;for(d=i[0].length;c'+i[1][c]+""}else{c=0;for(d=i.length;c'+i[c]+""}b+="";i=l.createElement("div");a.aanFeatures.l|| +(i.id=a.sTableId+"_length");i.className=a.oClasses.sLength;i.innerHTML="";h('select option[value="'+a._iDisplayLength+'"]',i).attr("selected",!0);h("select",i).bind("change.DT",function(){var b=h(this).val(),i=a.aanFeatures.l;c=0;for(d=i.length;ca.aiDisplay.length||-1==a._iDisplayLength?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Da(a){if(a.oScroll.bInfinite)return null;var b=l.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;j.ext.oPagination[a.sPaginationType].fnInit(a, +b,function(a){y(a);x(a)});a.aanFeatures.p||a.aoDrawCallback.push({fn:function(a){j.ext.oPagination[a.sPaginationType].fnUpdate(a,function(a){y(a);x(a)})},sName:"pagination"});return b}function qa(a,b){var c=a._iDisplayStart;if("number"===typeof b)a._iDisplayStart=b*a._iDisplayLength,a._iDisplayStart>a.fnRecordsDisplay()&&(a._iDisplayStart=0);else if("first"==b)a._iDisplayStart=0;else if("previous"==b)a._iDisplayStart=0<=a._iDisplayLength?a._iDisplayStart-a._iDisplayLength:0,0>a._iDisplayStart&&(a._iDisplayStart= +0);else if("next"==b)0<=a._iDisplayLength?a._iDisplayStart+a._iDisplayLengthh(a.nTable).height()-a.oScroll.iLoadGap&&a.fnDisplayEnd()d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(h(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else""!==a.oScroll.sXInner?a.nTable.style.width= +q(a.oScroll.sXInner):i==h(d).width()&&h(d).height()i-a.oScroll.iBarWidth&&(a.nTable.style.width=q(i))):a.nTable.style.width=q(i);i=h(a.nTable).outerWidth();C(s,e);C(function(a){p.push(q(h(a).width()))},e);C(function(a,b){a.style.width=p[b]},g);h(e).height(0);null!==a.nTFoot&&(C(s,j),C(function(a){n.push(q(h(a).width()))},j),C(function(a,b){a.style.width=n[b]},o),h(j).height(0));C(function(a,b){a.innerHTML= +"";a.style.width=p[b]},e);null!==a.nTFoot&&C(function(a,b){a.innerHTML="";a.style.width=n[b]},j);if(h(a.nTable).outerWidth()d.offsetHeight||"scroll"==h(d).css("overflow-y")?i+a.oScroll.iBarWidth:i;if(r&&(d.scrollHeight>d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(g-a.oScroll.iBarWidth);d.style.width=q(g);a.nScrollHead.style.width=q(g);null!==a.nTFoot&&(a.nScrollFoot.style.width=q(g));""===a.oScroll.sX?D(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width."): +""!==a.oScroll.sXInner&&D(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else d.style.width=q("100%"),a.nScrollHead.style.width=q("100%"),null!==a.nTFoot&&(a.nScrollFoot.style.width=q("100%"));""===a.oScroll.sY&&r&&(d.style.height=q(a.nTable.offsetHeight+a.oScroll.iBarWidth));""!==a.oScroll.sY&&a.oScroll.bCollapse&&(d.style.height=q(a.oScroll.sY),r=""!==a.oScroll.sX&&a.nTable.offsetWidth> +d.offsetWidth?a.oScroll.iBarWidth:0,a.nTable.offsetHeightd.clientHeight||"scroll"==h(d).css("overflow-y");b.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px";null!==a.nTFoot&&(R.style.width=q(r),l.style.width=q(r),l.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px");h(d).scroll();if(a.bSorted||a.bFiltered)d.scrollTop=0}function C(a,b,c){for(var d= +0,i=0,f=b.length,g,e;itd",b));j=N(a,f);for(f=d=0;fc)return null;if(null===a.aoData[c].nTr){var d=l.createElement("td");d.innerHTML=v(a,c,b,"");return d}return J(a,c)[b]}function Pa(a,b){for(var c=-1,d=-1,i=0;i/g,"");e.length>c&&(c=e.length,d=i)}return d}function q(a){if(null===a)return"0px";if("number"==typeof a)return 0>a?"0px":a+"px";var b=a.charCodeAt(a.length-1); +return 48>b||57/g,""),i=q[c].nTh,i.removeAttribute("aria-sort"),i.removeAttribute("aria-label"),q[c].bSortable?0d&&d++;f=RegExp(f+"[123]");var o;b=0;for(c=a.length;b
    ')[0];l.body.appendChild(b);a.oBrowser.bScrollOversize= +100===h("#DT_BrowserTest",b)[0].offsetWidth?!0:!1;l.body.removeChild(b)}function Va(a){return function(){var b=[s(this[j.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return j.ext.oApi[a].apply(this,b)}}var U=/\[.*?\]$/,Wa=X.JSON?JSON.stringify:function(a){var b=typeof a;if("object"!==b||null===a)return"string"===b&&(a='"'+a+'"'),a+"";var c,d,e=[],f=h.isArray(a);for(c in a)d=a[c],b=typeof d,"string"===b?d='"'+d+'"':"object"===b&&null!==d&&(d=Wa(d)),e.push((f?"":'"'+c+'":')+d);return(f? +"[":"{")+e+(f?"]":"}")};this.$=function(a,b){var c,d,e=[],f;d=s(this[j.ext.iApiIndex]);var g=d.aoData,o=d.aiDisplay,k=d.aiDisplayMaster;b||(b={});b=h.extend({},{filter:"none",order:"current",page:"all"},b);if("current"==b.page){c=d._iDisplayStart;for(d=d.fnDisplayEnd();c=d.fnRecordsDisplay()&&(d._iDisplayStart-=d._iDisplayLength,0>d._iDisplayStart&&(d._iDisplayStart=0));if(c===n||c)y(d),x(d);return g};this.fnDestroy=function(a){var b=s(this[j.ext.iApiIndex]),c=b.nTableWrapper.parentNode,d=b.nTBody,i,f,a=a===n?!1:a;b.bDestroying=!0;A(b,"aoDestroyCallback","destroy",[b]);if(!a){i=0;for(f=b.aoColumns.length;itr>td."+b.oClasses.sRowEmpty,b.nTable).parent().remove();b.nTable!=b.nTHead.parentNode&&(h(b.nTable).children("thead").remove(),b.nTable.appendChild(b.nTHead));b.nTFoot&&b.nTable!=b.nTFoot.parentNode&&(h(b.nTable).children("tfoot").remove(),b.nTable.appendChild(b.nTFoot));b.nTable.parentNode.removeChild(b.nTable);h(b.nTableWrapper).remove();b.aaSorting=[];b.aaSortingFixed=[];P(b);h(T(b)).removeClass(b.asStripeClasses.join(" "));h("th, td",b.nTHead).removeClass([b.oClasses.sSortable,b.oClasses.sSortableAsc, +b.oClasses.sSortableDesc,b.oClasses.sSortableNone].join(" "));b.bJUI&&(h("th span."+b.oClasses.sSortIcon+", td span."+b.oClasses.sSortIcon,b.nTHead).remove(),h("th, td",b.nTHead).each(function(){var a=h("div."+b.oClasses.sSortJUIWrapper,this),c=a.contents();h(this).append(c);a.remove()}));!a&&b.nTableReinsertBefore?c.insertBefore(b.nTable,b.nTableReinsertBefore):a||c.appendChild(b.nTable);i=0;for(f=b.aoData.length;i=t(d);if(!m)for(e=a;et<"F"ip>')):h.extend(g.oClasses,j.ext.oStdClasses);h(this).addClass(g.oClasses.sTable);if(""!==g.oScroll.sX||""!==g.oScroll.sY)g.oScroll.iBarWidth=Qa();g.iInitDisplayStart===n&&(g.iInitDisplayStart=e.iDisplayStart, +g._iDisplayStart=e.iDisplayStart);e.bStateSave&&(g.oFeatures.bStateSave=!0,Sa(g,e),z(g,"aoDrawCallback",ra,"state_save"));null!==e.iDeferLoading&&(g.bDeferLoading=!0,a=h.isArray(e.iDeferLoading),g._iRecordsDisplay=a?e.iDeferLoading[0]:e.iDeferLoading,g._iRecordsTotal=a?e.iDeferLoading[1]:e.iDeferLoading);null!==e.aaData&&(f=!0);""!==e.oLanguage.sUrl?(g.oLanguage.sUrl=e.oLanguage.sUrl,h.getJSON(g.oLanguage.sUrl,null,function(a){pa(a);h.extend(true,g.oLanguage,e.oLanguage,a);ba(g)}),i=!0):h.extend(!0, +g.oLanguage,e.oLanguage);null===e.asStripeClasses&&(g.asStripeClasses=[g.oClasses.sStripeOdd,g.oClasses.sStripeEven]);b=g.asStripeClasses.length;g.asDestroyStripes=[];if(b){c=!1;d=h(this).children("tbody").children("tr:lt("+b+")");for(a=0;a=g.aoColumns.length&&(g.aaSorting[a][0]=0);var k=g.aoColumns[g.aaSorting[a][0]];g.aaSorting[a][2]===n&&(g.aaSorting[a][2]=0);e.aaSorting===n&&g.saved_aaSorting===n&&(g.aaSorting[a][1]= +k.asSorting[0]);c=0;for(d=k.asSorting.length;c=parseInt(n,10)};j.fnIsDataTable=function(e){for(var h=j.settings,m=0;me)return e;for(var h=e+"",e=h.split(""),j="",h=h.length,k=0;k'+k.sPrevious+''+k.sNext+"":'';h(j).append(k);var l=h("a",j), +k=l[0],l=l[1];e.oApi._fnBindAction(k,{action:"previous"},n);e.oApi._fnBindAction(l,{action:"next"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_previous",l.id=e.sTableId+"_next",k.setAttribute("aria-controls",e.sTableId),l.setAttribute("aria-controls",e.sTableId))},fnUpdate:function(e){if(e.aanFeatures.p)for(var h=e.oClasses,j=e.aanFeatures.p,k,l=0,n=j.length;l'+k.sFirst+''+k.sPrevious+''+k.sNext+''+k.sLast+"");var t=h("a",j),k=t[0],l=t[1],r=t[2],t=t[3];e.oApi._fnBindAction(k,{action:"first"},n);e.oApi._fnBindAction(l,{action:"previous"},n);e.oApi._fnBindAction(r,{action:"next"},n);e.oApi._fnBindAction(t,{action:"last"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",r.id=e.sTableId+"_next",t.id=e.sTableId+"_last")}, +fnUpdate:function(e,o){if(e.aanFeatures.p){var m=j.ext.oPagination.iFullNumbersShowPages,k=Math.floor(m/2),l=Math.ceil(e.fnRecordsDisplay()/e._iDisplayLength),n=Math.ceil(e._iDisplayStart/e._iDisplayLength)+1,t="",r,B=e.oClasses,u,M=e.aanFeatures.p,L=function(h){e.oApi._fnBindAction(this,{page:h+r-1},function(h){e.oApi._fnPageChange(e,h.data.page);o(e);h.preventDefault()})};-1===e._iDisplayLength?n=k=r=1:l=l-k?(r=l-m+1,k=l):(r=n-Math.ceil(m/2)+1,k=r+m-1);for(m=r;m<=k;m++)t+= +n!==m?''+e.fnFormatNumber(m)+"":''+e.fnFormatNumber(m)+"";m=0;for(k=M.length;mh?1:0},"string-desc":function(e,h){return eh?-1:0},"html-pre":function(e){return e.replace(/<.*?>/g,"").toLowerCase()},"html-asc":function(e,h){return eh?1:0},"html-desc":function(e,h){return e< +h?1:e>h?-1:0},"date-pre":function(e){e=Date.parse(e);if(isNaN(e)||""===e)e=Date.parse("01/01/1970 00:00:00");return e},"date-asc":function(e,h){return e-h},"date-desc":function(e,h){return h-e},"numeric-pre":function(e){return"-"==e||""===e?0:1*e},"numeric-asc":function(e,h){return e-h},"numeric-desc":function(e,h){return h-e}});h.extend(j.ext.aTypes,[function(e){if("number"===typeof e)return"numeric";if("string"!==typeof e)return null;var h,j=!1;h=e.charAt(0);if(-1=="0123456789-".indexOf(h))return null; +for(var k=1;k")?"html":null}]);h.fn.DataTable=j;h.fn.dataTable=j;h.fn.dataTableSettings=j.settings;h.fn.dataTableExt=j.ext};"function"===typeof define&&define.amd?define(["jquery"],L):jQuery&&!jQuery.fn.dataTable&& +L(jQuery)})(window,document); diff --git a/asset/tablesorter/jquery.js b/asset/tablesorter/jquery.js new file mode 100644 index 0000000..63174a0 --- /dev/null +++ b/asset/tablesorter/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.2 jquery.com | jquery.org/license */ +(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write(""),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b
    a",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="
    t
    ",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="
    ",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;be.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="
    ",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="

    ",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b0)for(e=d;e=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*\s*$/g,bz={option:[1,""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X
    ","
    "]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1>");try{for(;d1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]===""&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("
    ").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window); \ No newline at end of file diff --git a/everseiko.zip b/everseiko.zip new file mode 100644 index 0000000..7416f60 Binary files /dev/null and b/everseiko.zip differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..233f658 Binary files /dev/null and b/favicon.ico differ diff --git a/index.php b/index.php new file mode 100644 index 0000000..f4ac11a --- /dev/null +++ b/index.php @@ -0,0 +1,205 @@ +marker[$name] = microtime(); + } + + // -------------------------------------------------------------------- + + /** + * Calculates the time difference between two marked points. + * + * If the first parameter is empty this function instead returns the + * {elapsed_time} pseudo-variable. This permits the full system + * execution time to be shown in a template. The output class will + * swap the real value for this variable. + * + * @access public + * @param string a particular marked point + * @param string a particular marked point + * @param integer the number of decimal places + * @return mixed + */ + function elapsed_time($point1 = '', $point2 = '', $decimals = 4) + { + if ($point1 == '') + { + return '{elapsed_time}'; + } + + if ( ! isset($this->marker[$point1])) + { + return ''; + } + + if ( ! isset($this->marker[$point2])) + { + $this->marker[$point2] = microtime(); + } + + list($sm, $ss) = explode(' ', $this->marker[$point1]); + list($em, $es) = explode(' ', $this->marker[$point2]); + + return number_format(($em + $es) - ($sm + $ss), $decimals); + } + + // -------------------------------------------------------------------- + + /** + * Memory Usage + * + * This function returns the {memory_usage} pseudo-variable. + * This permits it to be put it anywhere in a template + * without the memory being calculated until the end. + * The output class will swap the real value for this variable. + * + * @access public + * @return string + */ + function memory_usage() + { + return '{memory_usage}'; + } + +} + +// END CI_Benchmark class + +/* End of file Benchmark.php */ +/* Location: ./system/core/Benchmark.php */ \ No newline at end of file diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php new file mode 100644 index 0000000..c16c79c --- /dev/null +++ b/system/core/CodeIgniter.php @@ -0,0 +1,402 @@ + $assign_to_config['subclass_prefix'])); + } + +/* + * ------------------------------------------------------ + * Set a liberal script execution time limit + * ------------------------------------------------------ + */ + if (function_exists("set_time_limit") == TRUE AND @ini_get("safe_mode") == 0) + { + @set_time_limit(300); + } + +/* + * ------------------------------------------------------ + * Start the timer... tick tock tick tock... + * ------------------------------------------------------ + */ + $BM =& load_class('Benchmark', 'core'); + $BM->mark('total_execution_time_start'); + $BM->mark('loading_time:_base_classes_start'); + +/* + * ------------------------------------------------------ + * Instantiate the hooks class + * ------------------------------------------------------ + */ + $EXT =& load_class('Hooks', 'core'); + +/* + * ------------------------------------------------------ + * Is there a "pre_system" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('pre_system'); + +/* + * ------------------------------------------------------ + * Instantiate the config class + * ------------------------------------------------------ + */ + $CFG =& load_class('Config', 'core'); + + // Do we have any manually set config items in the index.php file? + if (isset($assign_to_config)) + { + $CFG->_assign_to_config($assign_to_config); + } + +/* + * ------------------------------------------------------ + * Instantiate the UTF-8 class + * ------------------------------------------------------ + * + * Note: Order here is rather important as the UTF-8 + * class needs to be used very early on, but it cannot + * properly determine if UTf-8 can be supported until + * after the Config class is instantiated. + * + */ + + $UNI =& load_class('Utf8', 'core'); + +/* + * ------------------------------------------------------ + * Instantiate the URI class + * ------------------------------------------------------ + */ + $URI =& load_class('URI', 'core'); + +/* + * ------------------------------------------------------ + * Instantiate the routing class and set the routing + * ------------------------------------------------------ + */ + $RTR =& load_class('Router', 'core'); + $RTR->_set_routing(); + + // Set any routing overrides that may exist in the main index file + if (isset($routing)) + { + $RTR->_set_overrides($routing); + } + +/* + * ------------------------------------------------------ + * Instantiate the output class + * ------------------------------------------------------ + */ + $OUT =& load_class('Output', 'core'); + +/* + * ------------------------------------------------------ + * Is there a valid cache file? If so, we're done... + * ------------------------------------------------------ + */ + if ($EXT->_call_hook('cache_override') === FALSE) + { + if ($OUT->_display_cache($CFG, $URI) == TRUE) + { + exit; + } + } + +/* + * ----------------------------------------------------- + * Load the security class for xss and csrf support + * ----------------------------------------------------- + */ + $SEC =& load_class('Security', 'core'); + +/* + * ------------------------------------------------------ + * Load the Input class and sanitize globals + * ------------------------------------------------------ + */ + $IN =& load_class('Input', 'core'); + +/* + * ------------------------------------------------------ + * Load the Language class + * ------------------------------------------------------ + */ + $LANG =& load_class('Lang', 'core'); + +/* + * ------------------------------------------------------ + * Load the app controller and local controller + * ------------------------------------------------------ + * + */ + // Load the base controller class + require BASEPATH.'core/Controller.php'; + + function &get_instance() + { + return CI_Controller::get_instance(); + } + + + if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php')) + { + require APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'; + } + + // Load the local application controller + // Note: The Router class automatically validates the controller path using the router->_validate_request(). + // If this include fails it means that the default controller in the Routes.php file is not resolving to something valid. + if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php')) + { + show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.'); + } + + include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php'); + + // Set a mark point for benchmarking + $BM->mark('loading_time:_base_classes_end'); + +/* + * ------------------------------------------------------ + * Security check + * ------------------------------------------------------ + * + * None of the functions in the app controller or the + * loader class can be called via the URI, nor can + * controller functions that begin with an underscore + */ + $class = $RTR->fetch_class(); + $method = $RTR->fetch_method(); + + if ( ! class_exists($class) + OR strncmp($method, '_', 1) == 0 + OR in_array(strtolower($method), array_map('strtolower', get_class_methods('CI_Controller'))) + ) + { + if ( ! empty($RTR->routes['404_override'])) + { + $x = explode('/', $RTR->routes['404_override']); + $class = $x[0]; + $method = (isset($x[1]) ? $x[1] : 'index'); + if ( ! class_exists($class)) + { + if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) + { + show_404("{$class}/{$method}"); + } + + include_once(APPPATH.'controllers/'.$class.'.php'); + } + } + else + { + show_404("{$class}/{$method}"); + } + } + +/* + * ------------------------------------------------------ + * Is there a "pre_controller" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('pre_controller'); + +/* + * ------------------------------------------------------ + * Instantiate the requested controller + * ------------------------------------------------------ + */ + // Mark a start point so we can benchmark the controller + $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start'); + + $CI = new $class(); + +/* + * ------------------------------------------------------ + * Is there a "post_controller_constructor" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('post_controller_constructor'); + +/* + * ------------------------------------------------------ + * Call the requested method + * ------------------------------------------------------ + */ + // Is there a "remap" function? If so, we call it instead + if (method_exists($CI, '_remap')) + { + $CI->_remap($method, array_slice($URI->rsegments, 2)); + } + else + { + // is_callable() returns TRUE on some versions of PHP 5 for private and protected + // methods, so we'll use this workaround for consistent behavior + if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($CI)))) + { + // Check and see if we are using a 404 override and use it. + if ( ! empty($RTR->routes['404_override'])) + { + $x = explode('/', $RTR->routes['404_override']); + $class = $x[0]; + $method = (isset($x[1]) ? $x[1] : 'index'); + if ( ! class_exists($class)) + { + if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) + { + show_404("{$class}/{$method}"); + } + + include_once(APPPATH.'controllers/'.$class.'.php'); + unset($CI); + $CI = new $class(); + } + } + else + { + show_404("{$class}/{$method}"); + } + } + + // Call the requested method. + // Any URI segments present (besides the class/function) will be passed to the method for convenience + call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); + } + + + // Mark a benchmark end point + $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end'); + +/* + * ------------------------------------------------------ + * Is there a "post_controller" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('post_controller'); + +/* + * ------------------------------------------------------ + * Send the final rendered output to the browser + * ------------------------------------------------------ + */ + if ($EXT->_call_hook('display_override') === FALSE) + { + $OUT->_display(); + } + +/* + * ------------------------------------------------------ + * Is there a "post_system" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('post_system'); + +/* + * ------------------------------------------------------ + * Close the DB connection if one exists + * ------------------------------------------------------ + */ + if (class_exists('CI_DB') AND isset($CI->db)) + { + $CI->db->close(); + } + + +/* End of file CodeIgniter.php */ +/* Location: ./system/core/CodeIgniter.php */ \ No newline at end of file diff --git a/system/core/Common.php b/system/core/Common.php new file mode 100644 index 0000000..07534c5 --- /dev/null +++ b/system/core/Common.php @@ -0,0 +1,564 @@ + 5 +* we'll set a static variable. +* +* @access public +* @param string +* @return bool TRUE if the current version is $version or higher +*/ +if ( ! function_exists('is_php')) +{ + function is_php($version = '5.0.0') + { + static $_is_php; + $version = (string)$version; + + if ( ! isset($_is_php[$version])) + { + $_is_php[$version] = (version_compare(PHP_VERSION, $version) < 0) ? FALSE : TRUE; + } + + return $_is_php[$version]; + } +} + +// ------------------------------------------------------------------------ + +/** + * Tests for file writability + * + * is_writable() returns TRUE on Windows servers when you really can't write to + * the file, based on the read-only attribute. is_writable() is also unreliable + * on Unix servers if safe_mode is on. + * + * @access private + * @return void + */ +if ( ! function_exists('is_really_writable')) +{ + function is_really_writable($file) + { + // If we're on a Unix server with safe_mode off we call is_writable + if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE) + { + return is_writable($file); + } + + // For windows servers and safe_mode "on" installations we'll actually + // write a file then read it. Bah... + if (is_dir($file)) + { + $file = rtrim($file, '/').'/'.md5(mt_rand(1,100).mt_rand(1,100)); + + if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) + { + return FALSE; + } + + fclose($fp); + @chmod($file, DIR_WRITE_MODE); + @unlink($file); + return TRUE; + } + elseif ( ! is_file($file) OR ($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) + { + return FALSE; + } + + fclose($fp); + return TRUE; + } +} + +// ------------------------------------------------------------------------ + +/** +* Class registry +* +* This function acts as a singleton. If the requested class does not +* exist it is instantiated and set to a static variable. If it has +* previously been instantiated the variable is returned. +* +* @access public +* @param string the class name being requested +* @param string the directory where the class should be found +* @param string the class name prefix +* @return object +*/ +if ( ! function_exists('load_class')) +{ + function &load_class($class, $directory = 'libraries', $prefix = 'CI_') + { + static $_classes = array(); + + // Does the class exist? If so, we're done... + if (isset($_classes[$class])) + { + return $_classes[$class]; + } + + $name = FALSE; + + // Look for the class first in the local application/libraries folder + // then in the native system/libraries folder + foreach (array(APPPATH, BASEPATH) as $path) + { + if (file_exists($path.$directory.'/'.$class.'.php')) + { + $name = $prefix.$class; + + if (class_exists($name) === FALSE) + { + require($path.$directory.'/'.$class.'.php'); + } + + break; + } + } + + // Is the request a class extension? If so we load it too + if (file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php')) + { + $name = config_item('subclass_prefix').$class; + + if (class_exists($name) === FALSE) + { + require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'); + } + } + + // Did we find the class? + if ($name === FALSE) + { + // Note: We use exit() rather then show_error() in order to avoid a + // self-referencing loop with the Excptions class + exit('Unable to locate the specified class: '.$class.'.php'); + } + + // Keep track of what we just loaded + is_loaded($class); + + $_classes[$class] = new $name(); + return $_classes[$class]; + } +} + +// -------------------------------------------------------------------- + +/** +* Keeps track of which libraries have been loaded. This function is +* called by the load_class() function above +* +* @access public +* @return array +*/ +if ( ! function_exists('is_loaded')) +{ + function &is_loaded($class = '') + { + static $_is_loaded = array(); + + if ($class != '') + { + $_is_loaded[strtolower($class)] = $class; + } + + return $_is_loaded; + } +} + +// ------------------------------------------------------------------------ + +/** +* Loads the main config.php file +* +* This function lets us grab the config file even if the Config class +* hasn't been instantiated yet +* +* @access private +* @return array +*/ +if ( ! function_exists('get_config')) +{ + function &get_config($replace = array()) + { + static $_config; + + if (isset($_config)) + { + return $_config[0]; + } + + // Is the config file in the environment folder? + if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php')) + { + $file_path = APPPATH.'config/config.php'; + } + + // Fetch the config file + if ( ! file_exists($file_path)) + { + exit('The configuration file does not exist.'); + } + + require($file_path); + + // Does the $config array exist in the file? + if ( ! isset($config) OR ! is_array($config)) + { + exit('Your config file does not appear to be formatted correctly.'); + } + + // Are any values being dynamically replaced? + if (count($replace) > 0) + { + foreach ($replace as $key => $val) + { + if (isset($config[$key])) + { + $config[$key] = $val; + } + } + } + + return $_config[0] =& $config; + } +} + +// ------------------------------------------------------------------------ + +/** +* Returns the specified config item +* +* @access public +* @return mixed +*/ +if ( ! function_exists('config_item')) +{ + function config_item($item) + { + static $_config_item = array(); + + if ( ! isset($_config_item[$item])) + { + $config =& get_config(); + + if ( ! isset($config[$item])) + { + return FALSE; + } + $_config_item[$item] = $config[$item]; + } + + return $_config_item[$item]; + } +} + +// ------------------------------------------------------------------------ + +/** +* Error Handler +* +* This function lets us invoke the exception class and +* display errors using the standard error template located +* in application/errors/errors.php +* This function will send the error page directly to the +* browser and exit. +* +* @access public +* @return void +*/ +if ( ! function_exists('show_error')) +{ + function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered') + { + $_error =& load_class('Exceptions', 'core'); + echo $_error->show_error($heading, $message, 'error_general', $status_code); + exit; + } +} + +// ------------------------------------------------------------------------ + +/** +* 404 Page Handler +* +* This function is similar to the show_error() function above +* However, instead of the standard error template it displays +* 404 errors. +* +* @access public +* @return void +*/ +if ( ! function_exists('show_404')) +{ + function show_404($page = '', $log_error = TRUE) + { + $_error =& load_class('Exceptions', 'core'); + $_error->show_404($page, $log_error); + exit; + } +} + +// ------------------------------------------------------------------------ + +/** +* Error Logging Interface +* +* We use this as a simple mechanism to access the logging +* class and send messages to be logged. +* +* @access public +* @return void +*/ +if ( ! function_exists('log_message')) +{ + function log_message($level = 'error', $message, $php_error = FALSE) + { + static $_log; + + if (config_item('log_threshold') == 0) + { + return; + } + + $_log =& load_class('Log'); + $_log->write_log($level, $message, $php_error); + } +} + +// ------------------------------------------------------------------------ + +/** + * Set HTTP Status Header + * + * @access public + * @param int the status code + * @param string + * @return void + */ +if ( ! function_exists('set_status_header')) +{ + function set_status_header($code = 200, $text = '') + { + $stati = array( + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + + 400 => 'Bad Request', + 401 => 'Unauthorized', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported' + ); + + if ($code == '' OR ! is_numeric($code)) + { + show_error('Status codes must be numeric', 500); + } + + if (isset($stati[$code]) AND $text == '') + { + $text = $stati[$code]; + } + + if ($text == '') + { + show_error('No status text available. Please check your status code number or supply your own message text.', 500); + } + + $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE; + + if (substr(php_sapi_name(), 0, 3) == 'cgi') + { + header("Status: {$code} {$text}", TRUE); + } + elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0') + { + header($server_protocol." {$code} {$text}", TRUE, $code); + } + else + { + header("HTTP/1.1 {$code} {$text}", TRUE, $code); + } + } +} + +// -------------------------------------------------------------------- + +/** +* Exception Handler +* +* This is the custom exception handler that is declaired at the top +* of Codeigniter.php. The main reason we use this is to permit +* PHP errors to be logged in our own log files since the user may +* not have access to server logs. Since this function +* effectively intercepts PHP errors, however, we also need +* to display errors based on the current error_reporting level. +* We do that with the use of a PHP error template. +* +* @access private +* @return void +*/ +if ( ! function_exists('_exception_handler')) +{ + function _exception_handler($severity, $message, $filepath, $line) + { + // We don't bother with "strict" notices since they tend to fill up + // the log file with excess information that isn't normally very helpful. + // For example, if you are running PHP 5 and you use version 4 style + // class functions (without prefixes like "public", "private", etc.) + // you'll get notices telling you that these have been deprecated. + if ($severity == E_STRICT) + { + return; + } + + $_error =& load_class('Exceptions', 'core'); + + // Should we display the error? We'll get the current error_reporting + // level and add its bits with the severity bits to find out. + if (($severity & error_reporting()) == $severity) + { + $_error->show_php_error($severity, $message, $filepath, $line); + } + + // Should we log the error? No? We're done... + if (config_item('log_threshold') == 0) + { + return; + } + + $_error->log_exception($severity, $message, $filepath, $line); + } +} + +// -------------------------------------------------------------------- + +/** + * Remove Invisible Characters + * + * This prevents sandwiching null characters + * between ascii characters, like Java\0script. + * + * @access public + * @param string + * @return string + */ +if ( ! function_exists('remove_invisible_characters')) +{ + function remove_invisible_characters($str, $url_encoded = TRUE) + { + $non_displayables = array(); + + // every control character except newline (dec 10) + // carriage return (dec 13), and horizontal tab (dec 09) + + if ($url_encoded) + { + $non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15 + $non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31 + } + + $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 + + do + { + $str = preg_replace($non_displayables, '', $str, -1, $count); + } + while ($count); + + return $str; + } +} + +// ------------------------------------------------------------------------ + +/** +* Returns HTML escaped variable +* +* @access public +* @param mixed +* @return mixed +*/ +if ( ! function_exists('html_escape')) +{ + function html_escape($var) + { + if (is_array($var)) + { + return array_map('html_escape', $var); + } + else + { + return htmlspecialchars($var, ENT_QUOTES, config_item('charset')); + } + } +} + +/* End of file Common.php */ +/* Location: ./system/core/Common.php */ \ No newline at end of file diff --git a/system/core/Config.php b/system/core/Config.php new file mode 100644 index 0000000..5dffbf3 --- /dev/null +++ b/system/core/Config.php @@ -0,0 +1,379 @@ +config =& get_config(); + log_message('debug', "Config Class Initialized"); + + // Set the base_url automatically if none was provided + if ($this->config['base_url'] == '') + { + if (isset($_SERVER['HTTP_HOST'])) + { + $base_url = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http'; + $base_url .= '://'. $_SERVER['HTTP_HOST']; + $base_url .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); + } + + else + { + $base_url = 'http://localhost/'; + } + + $this->set_item('base_url', $base_url); + } + } + + // -------------------------------------------------------------------- + + /** + * Load Config File + * + * @access public + * @param string the config file name + * @param boolean if configuration values should be loaded into their own section + * @param boolean true if errors should just return false, false if an error message should be displayed + * @return boolean if the file was loaded correctly + */ + function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) + { + $file = ($file == '') ? 'config' : str_replace('.php', '', $file); + $found = FALSE; + $loaded = FALSE; + + $check_locations = defined('ENVIRONMENT') + ? array(ENVIRONMENT.'/'.$file, $file) + : array($file); + + foreach ($this->_config_paths as $path) + { + foreach ($check_locations as $location) + { + $file_path = $path.'config/'.$location.'.php'; + + if (in_array($file_path, $this->is_loaded, TRUE)) + { + $loaded = TRUE; + continue 2; + } + + if (file_exists($file_path)) + { + $found = TRUE; + break; + } + } + + if ($found === FALSE) + { + continue; + } + + include($file_path); + + if ( ! isset($config) OR ! is_array($config)) + { + if ($fail_gracefully === TRUE) + { + return FALSE; + } + show_error('Your '.$file_path.' file does not appear to contain a valid configuration array.'); + } + + if ($use_sections === TRUE) + { + if (isset($this->config[$file])) + { + $this->config[$file] = array_merge($this->config[$file], $config); + } + else + { + $this->config[$file] = $config; + } + } + else + { + $this->config = array_merge($this->config, $config); + } + + $this->is_loaded[] = $file_path; + unset($config); + + $loaded = TRUE; + log_message('debug', 'Config file loaded: '.$file_path); + break; + } + + if ($loaded === FALSE) + { + if ($fail_gracefully === TRUE) + { + return FALSE; + } + show_error('The configuration file '.$file.'.php does not exist.'); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Fetch a config file item + * + * + * @access public + * @param string the config item name + * @param string the index name + * @param bool + * @return string + */ + function item($item, $index = '') + { + if ($index == '') + { + if ( ! isset($this->config[$item])) + { + return FALSE; + } + + $pref = $this->config[$item]; + } + else + { + if ( ! isset($this->config[$index])) + { + return FALSE; + } + + if ( ! isset($this->config[$index][$item])) + { + return FALSE; + } + + $pref = $this->config[$index][$item]; + } + + return $pref; + } + + // -------------------------------------------------------------------- + + /** + * Fetch a config file item - adds slash after item (if item is not empty) + * + * @access public + * @param string the config item name + * @param bool + * @return string + */ + function slash_item($item) + { + if ( ! isset($this->config[$item])) + { + return FALSE; + } + if( trim($this->config[$item]) == '') + { + return ''; + } + + return rtrim($this->config[$item], '/').'/'; + } + + // -------------------------------------------------------------------- + + /** + * Site URL + * Returns base_url . index_page [. uri_string] + * + * @access public + * @param string the URI string + * @return string + */ + function site_url($uri = '') + { + if ($uri == '') + { + return $this->slash_item('base_url').$this->item('index_page'); + } + + if ($this->item('enable_query_strings') == FALSE) + { + $suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix'); + return $this->slash_item('base_url').$this->slash_item('index_page').$this->_uri_string($uri).$suffix; + } + else + { + return $this->slash_item('base_url').$this->item('index_page').'?'.$this->_uri_string($uri); + } + } + + // ------------------------------------------------------------- + + /** + * Base URL + * Returns base_url [. uri_string] + * + * @access public + * @param string $uri + * @return string + */ + function base_url($uri = '') + { + return $this->slash_item('base_url').ltrim($this->_uri_string($uri), '/'); + } + + // ------------------------------------------------------------- + + /** + * Build URI string for use in Config::site_url() and Config::base_url() + * + * @access protected + * @param $uri + * @return string + */ + protected function _uri_string($uri) + { + if ($this->item('enable_query_strings') == FALSE) + { + if (is_array($uri)) + { + $uri = implode('/', $uri); + } + $uri = trim($uri, '/'); + } + else + { + if (is_array($uri)) + { + $i = 0; + $str = ''; + foreach ($uri as $key => $val) + { + $prefix = ($i == 0) ? '' : '&'; + $str .= $prefix.$key.'='.$val; + $i++; + } + $uri = $str; + } + } + return $uri; + } + + // -------------------------------------------------------------------- + + /** + * System URL + * + * @access public + * @return string + */ + function system_url() + { + $x = explode("/", preg_replace("|/*(.+?)/*$|", "\\1", BASEPATH)); + return $this->slash_item('base_url').end($x).'/'; + } + + // -------------------------------------------------------------------- + + /** + * Set a config file item + * + * @access public + * @param string the config item key + * @param string the config item value + * @return void + */ + function set_item($item, $value) + { + $this->config[$item] = $value; + } + + // -------------------------------------------------------------------- + + /** + * Assign to Config + * + * This function is called by the front controller (CodeIgniter.php) + * after the Config class is instantiated. It permits config items + * to be assigned or overriden by variables contained in the index.php file + * + * @access private + * @param array + * @return void + */ + function _assign_to_config($items = array()) + { + if (is_array($items)) + { + foreach ($items as $key => $val) + { + $this->set_item($key, $val); + } + } + } +} + +// END CI_Config class + +/* End of file Config.php */ +/* Location: ./system/core/Config.php */ diff --git a/system/core/Controller.php b/system/core/Controller.php new file mode 100644 index 0000000..fddb81e --- /dev/null +++ b/system/core/Controller.php @@ -0,0 +1,64 @@ + $class) + { + $this->$var =& load_class($class); + } + + $this->load =& load_class('Loader', 'core'); + + $this->load->initialize(); + + log_message('debug', "Controller Class Initialized"); + } + + public static function &get_instance() + { + return self::$instance; + } +} +// END Controller class + +/* End of file Controller.php */ +/* Location: ./system/core/Controller.php */ \ No newline at end of file diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php new file mode 100644 index 0000000..869739a --- /dev/null +++ b/system/core/Exceptions.php @@ -0,0 +1,193 @@ + 'Error', + E_WARNING => 'Warning', + E_PARSE => 'Parsing Error', + E_NOTICE => 'Notice', + E_CORE_ERROR => 'Core Error', + E_CORE_WARNING => 'Core Warning', + E_COMPILE_ERROR => 'Compile Error', + E_COMPILE_WARNING => 'Compile Warning', + E_USER_ERROR => 'User Error', + E_USER_WARNING => 'User Warning', + E_USER_NOTICE => 'User Notice', + E_STRICT => 'Runtime Notice' + ); + + + /** + * Constructor + */ + public function __construct() + { + $this->ob_level = ob_get_level(); + // Note: Do not log messages from this constructor. + } + + // -------------------------------------------------------------------- + + /** + * Exception Logger + * + * This function logs PHP generated error messages + * + * @access private + * @param string the error severity + * @param string the error string + * @param string the error filepath + * @param string the error line number + * @return string + */ + function log_exception($severity, $message, $filepath, $line) + { + $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity]; + + log_message('error', 'Severity: '.$severity.' --> '.$message. ' '.$filepath.' '.$line, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * 404 Page Not Found Handler + * + * @access private + * @param string the page + * @param bool log error yes/no + * @return string + */ + function show_404($page = '', $log_error = TRUE) + { + $heading = "404 Page Not Found"; + $message = "The page you requested was not found."; + + // By default we log this, but allow a dev to skip it + if ($log_error) + { + log_message('error', '404 Page Not Found --> '.$page); + } + + echo $this->show_error($heading, $message, 'error_404', 404); + exit; + } + + // -------------------------------------------------------------------- + + /** + * General Error Page + * + * This function takes an error message as input + * (either as a string or an array) and displays + * it using the specified template. + * + * @access private + * @param string the heading + * @param string the message + * @param string the template name + * @param int the status code + * @return string + */ + function show_error($heading, $message, $template = 'error_general', $status_code = 500) + { + set_status_header($status_code); + + $message = '

    '.implode('

    ', ( ! is_array($message)) ? array($message) : $message).'

    '; + + if (ob_get_level() > $this->ob_level + 1) + { + ob_end_flush(); + } + ob_start(); + include(APPPATH.'errors/'.$template.'.php'); + $buffer = ob_get_contents(); + ob_end_clean(); + return $buffer; + } + + // -------------------------------------------------------------------- + + /** + * Native PHP error handler + * + * @access private + * @param string the error severity + * @param string the error string + * @param string the error filepath + * @param string the error line number + * @return string + */ + function show_php_error($severity, $message, $filepath, $line) + { + $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity]; + + $filepath = str_replace("\\", "/", $filepath); + + // For safety reasons we do not show the full file path + if (FALSE !== strpos($filepath, '/')) + { + $x = explode('/', $filepath); + $filepath = $x[count($x)-2].'/'.end($x); + } + + if (ob_get_level() > $this->ob_level + 1) + { + ob_end_flush(); + } + ob_start(); + include(APPPATH.'errors/error_php.php'); + $buffer = ob_get_contents(); + ob_end_clean(); + echo $buffer; + } + + +} +// END Exceptions Class + +/* End of file Exceptions.php */ +/* Location: ./system/core/Exceptions.php */ \ No newline at end of file diff --git a/system/core/Hooks.php b/system/core/Hooks.php new file mode 100644 index 0000000..33f1c03 --- /dev/null +++ b/system/core/Hooks.php @@ -0,0 +1,248 @@ +_initialize(); + log_message('debug', "Hooks Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize the Hooks Preferences + * + * @access private + * @return void + */ + function _initialize() + { + $CFG =& load_class('Config', 'core'); + + // If hooks are not enabled in the config file + // there is nothing else to do + + if ($CFG->item('enable_hooks') == FALSE) + { + return; + } + + // Grab the "hooks" definition file. + // If there are no hooks, we're done. + + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/hooks.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'); + } + elseif (is_file(APPPATH.'config/hooks.php')) + { + include(APPPATH.'config/hooks.php'); + } + + + if ( ! isset($hook) OR ! is_array($hook)) + { + return; + } + + $this->hooks =& $hook; + $this->enabled = TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Call Hook + * + * Calls a particular hook + * + * @access private + * @param string the hook name + * @return mixed + */ + function _call_hook($which = '') + { + if ( ! $this->enabled OR ! isset($this->hooks[$which])) + { + return FALSE; + } + + if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0])) + { + foreach ($this->hooks[$which] as $val) + { + $this->_run_hook($val); + } + } + else + { + $this->_run_hook($this->hooks[$which]); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Run Hook + * + * Runs a particular hook + * + * @access private + * @param array the hook details + * @return bool + */ + function _run_hook($data) + { + if ( ! is_array($data)) + { + return FALSE; + } + + // ----------------------------------- + // Safety - Prevents run-away loops + // ----------------------------------- + + // If the script being called happens to have the same + // hook call within it a loop can happen + + if ($this->in_progress == TRUE) + { + return; + } + + // ----------------------------------- + // Set file path + // ----------------------------------- + + if ( ! isset($data['filepath']) OR ! isset($data['filename'])) + { + return FALSE; + } + + $filepath = APPPATH.$data['filepath'].'/'.$data['filename']; + + if ( ! file_exists($filepath)) + { + return FALSE; + } + + // ----------------------------------- + // Set class/function name + // ----------------------------------- + + $class = FALSE; + $function = FALSE; + $params = ''; + + if (isset($data['class']) AND $data['class'] != '') + { + $class = $data['class']; + } + + if (isset($data['function'])) + { + $function = $data['function']; + } + + if (isset($data['params'])) + { + $params = $data['params']; + } + + if ($class === FALSE AND $function === FALSE) + { + return FALSE; + } + + // ----------------------------------- + // Set the in_progress flag + // ----------------------------------- + + $this->in_progress = TRUE; + + // ----------------------------------- + // Call the requested class and/or function + // ----------------------------------- + + if ($class !== FALSE) + { + if ( ! class_exists($class)) + { + require($filepath); + } + + $HOOK = new $class; + $HOOK->$function($params); + } + else + { + if ( ! function_exists($function)) + { + require($filepath); + } + + $function($params); + } + + $this->in_progress = FALSE; + return TRUE; + } + +} + +// END CI_Hooks class + +/* End of file Hooks.php */ +/* Location: ./system/core/Hooks.php */ \ No newline at end of file diff --git a/system/core/Input.php b/system/core/Input.php new file mode 100644 index 0000000..0c1f2b0 --- /dev/null +++ b/system/core/Input.php @@ -0,0 +1,849 @@ +_allow_get_array = (config_item('allow_get_array') === TRUE); + $this->_enable_xss = (config_item('global_xss_filtering') === TRUE); + $this->_enable_csrf = (config_item('csrf_protection') === TRUE); + + global $SEC; + $this->security =& $SEC; + + // Do we need the UTF-8 class? + if (UTF8_ENABLED === TRUE) + { + global $UNI; + $this->uni =& $UNI; + } + + // Sanitize global arrays + $this->_sanitize_globals(); + } + + // -------------------------------------------------------------------- + + /** + * Fetch from array + * + * This is a helper function to retrieve values from global arrays + * + * @access private + * @param array + * @param string + * @param bool + * @return string + */ + function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE) + { + if ( ! isset($array[$index])) + { + return FALSE; + } + + if ($xss_clean === TRUE) + { + return $this->security->xss_clean($array[$index]); + } + + return $array[$index]; + } + + // -------------------------------------------------------------------- + + /** + * Fetch an item from the GET array + * + * @access public + * @param string + * @param bool + * @return string + */ + function get($index = NULL, $xss_clean = FALSE) + { + // Check if a field has been provided + if ($index === NULL AND ! empty($_GET)) + { + $get = array(); + + // loop through the full _GET array + foreach (array_keys($_GET) as $key) + { + $get[$key] = $this->_fetch_from_array($_GET, $key, $xss_clean); + } + return $get; + } + + return $this->_fetch_from_array($_GET, $index, $xss_clean); + } + + // -------------------------------------------------------------------- + + /** + * Fetch an item from the POST array + * + * @access public + * @param string + * @param bool + * @return string + */ + function post($index = NULL, $xss_clean = FALSE) + { + // Check if a field has been provided + if ($index === NULL AND ! empty($_POST)) + { + $post = array(); + + // Loop through the full _POST array and return it + foreach (array_keys($_POST) as $key) + { + $post[$key] = $this->_fetch_from_array($_POST, $key, $xss_clean); + } + return $post; + } + + return $this->_fetch_from_array($_POST, $index, $xss_clean); + } + + + // -------------------------------------------------------------------- + + /** + * Fetch an item from either the GET array or the POST + * + * @access public + * @param string The index key + * @param bool XSS cleaning + * @return string + */ + function get_post($index = '', $xss_clean = FALSE) + { + if ( ! isset($_POST[$index]) ) + { + return $this->get($index, $xss_clean); + } + else + { + return $this->post($index, $xss_clean); + } + } + + // -------------------------------------------------------------------- + + /** + * Fetch an item from the COOKIE array + * + * @access public + * @param string + * @param bool + * @return string + */ + function cookie($index = '', $xss_clean = FALSE) + { + return $this->_fetch_from_array($_COOKIE, $index, $xss_clean); + } + + // ------------------------------------------------------------------------ + + /** + * Set cookie + * + * Accepts six parameter, or you can submit an associative + * array in the first parameter containing all the values. + * + * @access public + * @param mixed + * @param string the value of the cookie + * @param string the number of seconds until expiration + * @param string the cookie domain. Usually: .yourdomain.com + * @param string the cookie path + * @param string the cookie prefix + * @param bool true makes the cookie secure + * @return void + */ + function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE) + { + if (is_array($name)) + { + // always leave 'name' in last place, as the loop will break otherwise, due to $$item + foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'name') as $item) + { + if (isset($name[$item])) + { + $$item = $name[$item]; + } + } + } + + if ($prefix == '' AND config_item('cookie_prefix') != '') + { + $prefix = config_item('cookie_prefix'); + } + if ($domain == '' AND config_item('cookie_domain') != '') + { + $domain = config_item('cookie_domain'); + } + if ($path == '/' AND config_item('cookie_path') != '/') + { + $path = config_item('cookie_path'); + } + if ($secure == FALSE AND config_item('cookie_secure') != FALSE) + { + $secure = config_item('cookie_secure'); + } + + if ( ! is_numeric($expire)) + { + $expire = time() - 86500; + } + else + { + $expire = ($expire > 0) ? time() + $expire : 0; + } + + setcookie($prefix.$name, $value, $expire, $path, $domain, $secure); + } + + // -------------------------------------------------------------------- + + /** + * Fetch an item from the SERVER array + * + * @access public + * @param string + * @param bool + * @return string + */ + function server($index = '', $xss_clean = FALSE) + { + return $this->_fetch_from_array($_SERVER, $index, $xss_clean); + } + + // -------------------------------------------------------------------- + + /** + * Fetch the IP Address + * + * @return string + */ + public function ip_address() + { + if ($this->ip_address !== FALSE) + { + return $this->ip_address; + } + + $proxy_ips = config_item('proxy_ips'); + if ( ! empty($proxy_ips)) + { + $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips)); + foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header) + { + if (($spoof = $this->server($header)) !== FALSE) + { + // Some proxies typically list the whole chain of IP + // addresses through which the client has reached us. + // e.g. client_ip, proxy_ip1, proxy_ip2, etc. + if (strpos($spoof, ',') !== FALSE) + { + $spoof = explode(',', $spoof, 2); + $spoof = $spoof[0]; + } + + if ( ! $this->valid_ip($spoof)) + { + $spoof = FALSE; + } + else + { + break; + } + } + } + + $this->ip_address = ($spoof !== FALSE && in_array($_SERVER['REMOTE_ADDR'], $proxy_ips, TRUE)) + ? $spoof : $_SERVER['REMOTE_ADDR']; + } + else + { + $this->ip_address = $_SERVER['REMOTE_ADDR']; + } + + if ( ! $this->valid_ip($this->ip_address)) + { + $this->ip_address = '0.0.0.0'; + } + + return $this->ip_address; + } + + // -------------------------------------------------------------------- + + /** + * Validate IP Address + * + * @access public + * @param string + * @param string ipv4 or ipv6 + * @return bool + */ + public function valid_ip($ip, $which = '') + { + $which = strtolower($which); + + // First check if filter_var is available + if (is_callable('filter_var')) + { + switch ($which) { + case 'ipv4': + $flag = FILTER_FLAG_IPV4; + break; + case 'ipv6': + $flag = FILTER_FLAG_IPV6; + break; + default: + $flag = ''; + break; + } + + return (bool) filter_var($ip, FILTER_VALIDATE_IP, $flag); + } + + if ($which !== 'ipv6' && $which !== 'ipv4') + { + if (strpos($ip, ':') !== FALSE) + { + $which = 'ipv6'; + } + elseif (strpos($ip, '.') !== FALSE) + { + $which = 'ipv4'; + } + else + { + return FALSE; + } + } + + $func = '_valid_'.$which; + return $this->$func($ip); + } + + // -------------------------------------------------------------------- + + /** + * Validate IPv4 Address + * + * Updated version suggested by Geert De Deckere + * + * @access protected + * @param string + * @return bool + */ + protected function _valid_ipv4($ip) + { + $ip_segments = explode('.', $ip); + + // Always 4 segments needed + if (count($ip_segments) !== 4) + { + return FALSE; + } + // IP can not start with 0 + if ($ip_segments[0][0] == '0') + { + return FALSE; + } + + // Check each segment + foreach ($ip_segments as $segment) + { + // IP segments must be digits and can not be + // longer than 3 digits or greater then 255 + if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3) + { + return FALSE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Validate IPv6 Address + * + * @access protected + * @param string + * @return bool + */ + protected function _valid_ipv6($str) + { + // 8 groups, separated by : + // 0-ffff per group + // one set of consecutive 0 groups can be collapsed to :: + + $groups = 8; + $collapsed = FALSE; + + $chunks = array_filter( + preg_split('/(:{1,2})/', $str, NULL, PREG_SPLIT_DELIM_CAPTURE) + ); + + // Rule out easy nonsense + if (current($chunks) == ':' OR end($chunks) == ':') + { + return FALSE; + } + + // PHP supports IPv4-mapped IPv6 addresses, so we'll expect those as well + if (strpos(end($chunks), '.') !== FALSE) + { + $ipv4 = array_pop($chunks); + + if ( ! $this->_valid_ipv4($ipv4)) + { + return FALSE; + } + + $groups--; + } + + while ($seg = array_pop($chunks)) + { + if ($seg[0] == ':') + { + if (--$groups == 0) + { + return FALSE; // too many groups + } + + if (strlen($seg) > 2) + { + return FALSE; // long separator + } + + if ($seg == '::') + { + if ($collapsed) + { + return FALSE; // multiple collapsed + } + + $collapsed = TRUE; + } + } + elseif (preg_match("/[^0-9a-f]/i", $seg) OR strlen($seg) > 4) + { + return FALSE; // invalid segment + } + } + + return $collapsed OR $groups == 1; + } + + // -------------------------------------------------------------------- + + /** + * User Agent + * + * @access public + * @return string + */ + function user_agent() + { + if ($this->user_agent !== FALSE) + { + return $this->user_agent; + } + + $this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT']; + + return $this->user_agent; + } + + // -------------------------------------------------------------------- + + /** + * Sanitize Globals + * + * This function does the following: + * + * Unsets $_GET data (if query strings are not enabled) + * + * Unsets all globals if register_globals is enabled + * + * Standardizes newline characters to \n + * + * @access private + * @return void + */ + function _sanitize_globals() + { + // It would be "wrong" to unset any of these GLOBALS. + $protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST', + '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA', + 'system_folder', 'application_folder', 'BM', 'EXT', + 'CFG', 'URI', 'RTR', 'OUT', 'IN'); + + // Unset globals for securiy. + // This is effectively the same as register_globals = off + foreach (array($_GET, $_POST, $_COOKIE) as $global) + { + if ( ! is_array($global)) + { + if ( ! in_array($global, $protected)) + { + global $$global; + $$global = NULL; + } + } + else + { + foreach ($global as $key => $val) + { + if ( ! in_array($key, $protected)) + { + global $$key; + $$key = NULL; + } + } + } + } + + // Is $_GET data allowed? If not we'll set the $_GET to an empty array + if ($this->_allow_get_array == FALSE) + { + $_GET = array(); + } + else + { + if (is_array($_GET) AND count($_GET) > 0) + { + foreach ($_GET as $key => $val) + { + $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + } + } + } + + // Clean $_POST Data + if (is_array($_POST) AND count($_POST) > 0) + { + foreach ($_POST as $key => $val) + { + $_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + } + } + + // Clean $_COOKIE Data + if (is_array($_COOKIE) AND count($_COOKIE) > 0) + { + // Also get rid of specially treated cookies that might be set by a server + // or silly application, that are of no use to a CI application anyway + // but that when present will trip our 'Disallowed Key Characters' alarm + // http://www.ietf.org/rfc/rfc2109.txt + // note that the key names below are single quoted strings, and are not PHP variables + unset($_COOKIE['$Version']); + unset($_COOKIE['$Path']); + unset($_COOKIE['$Domain']); + + foreach ($_COOKIE as $key => $val) + { + $_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + } + } + + // Sanitize PHP_SELF + $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']); + + + // CSRF Protection check on HTTP requests + if ($this->_enable_csrf == TRUE && ! $this->is_cli_request()) + { + $this->security->csrf_verify(); + } + + log_message('debug', "Global POST and COOKIE data sanitized"); + } + + // -------------------------------------------------------------------- + + /** + * Clean Input Data + * + * This is a helper function. It escapes data and + * standardizes newline characters to \n + * + * @access private + * @param string + * @return string + */ + function _clean_input_data($str) + { + if (is_array($str)) + { + $new_array = array(); + foreach ($str as $key => $val) + { + $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + } + return $new_array; + } + + /* We strip slashes if magic quotes is on to keep things consistent + + NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and + it will probably not exist in future versions at all. + */ + if ( ! is_php('5.4') && get_magic_quotes_gpc()) + { + $str = stripslashes($str); + } + + // Clean UTF-8 if supported + if (UTF8_ENABLED === TRUE) + { + $str = $this->uni->clean_string($str); + } + + // Remove control characters + $str = remove_invisible_characters($str); + + // Should we filter the input data? + if ($this->_enable_xss === TRUE) + { + $str = $this->security->xss_clean($str); + } + + // Standardize newlines if needed + if ($this->_standardize_newlines == TRUE) + { + if (strpos($str, "\r") !== FALSE) + { + $str = str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str); + } + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Clean Keys + * + * This is a helper function. To prevent malicious users + * from trying to exploit keys we make sure that keys are + * only named with alpha-numeric text and a few other items. + * + * @access private + * @param string + * @return string + */ + function _clean_input_keys($str) + { + if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str)) + { + exit('Disallowed Key Characters.'); + } + + // Clean UTF-8 if supported + if (UTF8_ENABLED === TRUE) + { + $str = $this->uni->clean_string($str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Request Headers + * + * In Apache, you can simply call apache_request_headers(), however for + * people running other webservers the function is undefined. + * + * @param bool XSS cleaning + * + * @return array + */ + public function request_headers($xss_clean = FALSE) + { + // Look at Apache go! + if (function_exists('apache_request_headers')) + { + $headers = apache_request_headers(); + } + else + { + $headers['Content-Type'] = (isset($_SERVER['CONTENT_TYPE'])) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE'); + + foreach ($_SERVER as $key => $val) + { + if (strncmp($key, 'HTTP_', 5) === 0) + { + $headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean); + } + } + } + + // take SOME_HEADER and turn it into Some-Header + foreach ($headers as $key => $val) + { + $key = str_replace('_', ' ', strtolower($key)); + $key = str_replace(' ', '-', ucwords($key)); + + $this->headers[$key] = $val; + } + + return $this->headers; + } + + // -------------------------------------------------------------------- + + /** + * Get Request Header + * + * Returns the value of a single member of the headers class member + * + * @param string array key for $this->headers + * @param boolean XSS Clean or not + * @return mixed FALSE on failure, string on success + */ + public function get_request_header($index, $xss_clean = FALSE) + { + if (empty($this->headers)) + { + $this->request_headers(); + } + + if ( ! isset($this->headers[$index])) + { + return FALSE; + } + + if ($xss_clean === TRUE) + { + return $this->security->xss_clean($this->headers[$index]); + } + + return $this->headers[$index]; + } + + // -------------------------------------------------------------------- + + /** + * Is ajax Request? + * + * Test to see if a request contains the HTTP_X_REQUESTED_WITH header + * + * @return boolean + */ + public function is_ajax_request() + { + return ($this->server('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest'); + } + + // -------------------------------------------------------------------- + + /** + * Is cli Request? + * + * Test to see if a request was made from the command line + * + * @return bool + */ + public function is_cli_request() + { + return (php_sapi_name() === 'cli' OR defined('STDIN')); + } + +} + +/* End of file Input.php */ +/* Location: ./system/core/Input.php */ \ No newline at end of file diff --git a/system/core/Lang.php b/system/core/Lang.php new file mode 100644 index 0000000..5ac6718 --- /dev/null +++ b/system/core/Lang.php @@ -0,0 +1,160 @@ +is_loaded, TRUE)) + { + return; + } + + $config =& get_config(); + + if ($idiom == '') + { + $deft_lang = ( ! isset($config['language'])) ? 'english' : $config['language']; + $idiom = ($deft_lang == '') ? 'english' : $deft_lang; + } + + // Determine where the language file is and load it + if ($alt_path != '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile)) + { + include($alt_path.'language/'.$idiom.'/'.$langfile); + } + else + { + $found = FALSE; + + foreach (get_instance()->load->get_package_paths(TRUE) as $package_path) + { + if (file_exists($package_path.'language/'.$idiom.'/'.$langfile)) + { + include($package_path.'language/'.$idiom.'/'.$langfile); + $found = TRUE; + break; + } + } + + if ($found !== TRUE) + { + show_error('Unable to load the requested language file: language/'.$idiom.'/'.$langfile); + } + } + + + if ( ! isset($lang)) + { + log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile); + return; + } + + if ($return == TRUE) + { + return $lang; + } + + $this->is_loaded[] = $langfile; + $this->language = array_merge($this->language, $lang); + unset($lang); + + log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Fetch a single line of text from the language array + * + * @access public + * @param string $line the language line + * @return string + */ + function line($line = '') + { + $value = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line]; + + // Because killer robots like unicorns! + if ($value === FALSE) + { + log_message('error', 'Could not find the language line "'.$line.'"'); + } + + return $value; + } + +} +// END Language Class + +/* End of file Lang.php */ +/* Location: ./system/core/Lang.php */ diff --git a/system/core/Loader.php b/system/core/Loader.php new file mode 100644 index 0000000..6b7ee0c --- /dev/null +++ b/system/core/Loader.php @@ -0,0 +1,1248 @@ + 'unit', + 'user_agent' => 'agent'); + + /** + * Constructor + * + * Sets the path to the view files and gets the initial output buffering level + */ + public function __construct() + { + $this->_ci_ob_level = ob_get_level(); + $this->_ci_library_paths = array(APPPATH, BASEPATH); + $this->_ci_helper_paths = array(APPPATH, BASEPATH); + $this->_ci_model_paths = array(APPPATH); + $this->_ci_view_paths = array(APPPATH.'views/' => TRUE); + + log_message('debug', "Loader Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize the Loader + * + * This method is called once in CI_Controller. + * + * @param array + * @return object + */ + public function initialize() + { + $this->_ci_classes = array(); + $this->_ci_loaded_files = array(); + $this->_ci_models = array(); + $this->_base_classes =& is_loaded(); + + $this->_ci_autoloader(); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Is Loaded + * + * A utility function to test if a class is in the self::$_ci_classes array. + * This function returns the object name if the class tested for is loaded, + * and returns FALSE if it isn't. + * + * It is mainly used in the form_helper -> _get_validation_object() + * + * @param string class being checked for + * @return mixed class object name on the CI SuperObject or FALSE + */ + public function is_loaded($class) + { + if (isset($this->_ci_classes[$class])) + { + return $this->_ci_classes[$class]; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Class Loader + * + * This function lets users load and instantiate classes. + * It is designed to be called from a user's app controllers. + * + * @param string the name of the class + * @param mixed the optional parameters + * @param string an optional object name + * @return void + */ + public function library($library = '', $params = NULL, $object_name = NULL) + { + if (is_array($library)) + { + foreach ($library as $class) + { + $this->library($class, $params); + } + + return; + } + + if ($library == '' OR isset($this->_base_classes[$library])) + { + return FALSE; + } + + if ( ! is_null($params) && ! is_array($params)) + { + $params = NULL; + } + + $this->_ci_load_class($library, $params, $object_name); + } + + // -------------------------------------------------------------------- + + /** + * Model Loader + * + * This function lets users load and instantiate models. + * + * @param string the name of the class + * @param string name for the model + * @param bool database connection + * @return void + */ + public function model($model, $name = '', $db_conn = FALSE) + { + if (is_array($model)) + { + foreach ($model as $babe) + { + $this->model($babe); + } + return; + } + + if ($model == '') + { + return; + } + + $path = ''; + + // Is the model in a sub-folder? If so, parse out the filename and path. + if (($last_slash = strrpos($model, '/')) !== FALSE) + { + // The path is in front of the last slash + $path = substr($model, 0, $last_slash + 1); + + // And the model name behind it + $model = substr($model, $last_slash + 1); + } + + if ($name == '') + { + $name = $model; + } + + if (in_array($name, $this->_ci_models, TRUE)) + { + return; + } + + $CI =& get_instance(); + if (isset($CI->$name)) + { + show_error('The model name you are loading is the name of a resource that is already being used: '.$name); + } + + $model = strtolower($model); + + foreach ($this->_ci_model_paths as $mod_path) + { + if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) + { + continue; + } + + if ($db_conn !== FALSE AND ! class_exists('CI_DB')) + { + if ($db_conn === TRUE) + { + $db_conn = ''; + } + + $CI->load->database($db_conn, FALSE, TRUE); + } + + if ( ! class_exists('CI_Model')) + { + load_class('Model', 'core'); + } + + require_once($mod_path.'models/'.$path.$model.'.php'); + + $model = ucfirst($model); + + $CI->$name = new $model(); + + $this->_ci_models[] = $name; + return; + } + + // couldn't find the model + show_error('Unable to locate the model you have specified: '.$model); + } + + // -------------------------------------------------------------------- + + /** + * Database Loader + * + * @param string the DB credentials + * @param bool whether to return the DB object + * @param bool whether to enable active record (this allows us to override the config setting) + * @return object + */ + public function database($params = '', $return = FALSE, $active_record = NULL) + { + // Grab the super object + $CI =& get_instance(); + + // Do we even need to load the database class? + if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db)) + { + return FALSE; + } + + require_once(BASEPATH.'database/DB.php'); + + if ($return === TRUE) + { + return DB($params, $active_record); + } + + // Initialize the db variable. Needed to prevent + // reference errors with some configurations + $CI->db = ''; + + // Load the DB class + $CI->db =& DB($params, $active_record); + } + + // -------------------------------------------------------------------- + + /** + * Load the Utilities Class + * + * @return string + */ + public function dbutil() + { + if ( ! class_exists('CI_DB')) + { + $this->database(); + } + + $CI =& get_instance(); + + // for backwards compatibility, load dbforge so we can extend dbutils off it + // this use is deprecated and strongly discouraged + $CI->load->dbforge(); + + require_once(BASEPATH.'database/DB_utility.php'); + require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility.php'); + $class = 'CI_DB_'.$CI->db->dbdriver.'_utility'; + + $CI->dbutil = new $class(); + } + + // -------------------------------------------------------------------- + + /** + * Load the Database Forge Class + * + * @return string + */ + public function dbforge() + { + if ( ! class_exists('CI_DB')) + { + $this->database(); + } + + $CI =& get_instance(); + + require_once(BASEPATH.'database/DB_forge.php'); + require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge.php'); + $class = 'CI_DB_'.$CI->db->dbdriver.'_forge'; + + $CI->dbforge = new $class(); + } + + // -------------------------------------------------------------------- + + /** + * Load View + * + * This function is used to load a "view" file. It has three parameters: + * + * 1. The name of the "view" file to be included. + * 2. An associative array of data to be extracted for use in the view. + * 3. TRUE/FALSE - whether to return the data or load it. In + * some cases it's advantageous to be able to return data so that + * a developer can process it in some way. + * + * @param string + * @param array + * @param bool + * @return void + */ + public function view($view, $vars = array(), $return = FALSE) + { + return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return)); + } + + // -------------------------------------------------------------------- + + /** + * Load File + * + * This is a generic file loader + * + * @param string + * @param bool + * @return string + */ + public function file($path, $return = FALSE) + { + return $this->_ci_load(array('_ci_path' => $path, '_ci_return' => $return)); + } + + // -------------------------------------------------------------------- + + /** + * Set Variables + * + * Once variables are set they become available within + * the controller class and its "view" files. + * + * @param array + * @param string + * @return void + */ + public function vars($vars = array(), $val = '') + { + if ($val != '' AND is_string($vars)) + { + $vars = array($vars => $val); + } + + $vars = $this->_ci_object_to_array($vars); + + if (is_array($vars) AND count($vars) > 0) + { + foreach ($vars as $key => $val) + { + $this->_ci_cached_vars[$key] = $val; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Get Variable + * + * Check if a variable is set and retrieve it. + * + * @param array + * @return void + */ + public function get_var($key) + { + return isset($this->_ci_cached_vars[$key]) ? $this->_ci_cached_vars[$key] : NULL; + } + + // -------------------------------------------------------------------- + + /** + * Load Helper + * + * This function loads the specified helper file. + * + * @param mixed + * @return void + */ + public function helper($helpers = array()) + { + foreach ($this->_ci_prep_filename($helpers, '_helper') as $helper) + { + if (isset($this->_ci_helpers[$helper])) + { + continue; + } + + $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.'.php'; + + // Is this a helper extension request? + if (file_exists($ext_helper)) + { + $base_helper = BASEPATH.'helpers/'.$helper.'.php'; + + if ( ! file_exists($base_helper)) + { + show_error('Unable to load the requested file: helpers/'.$helper.'.php'); + } + + include_once($ext_helper); + include_once($base_helper); + + $this->_ci_helpers[$helper] = TRUE; + log_message('debug', 'Helper loaded: '.$helper); + continue; + } + + // Try to load the helper + foreach ($this->_ci_helper_paths as $path) + { + if (file_exists($path.'helpers/'.$helper.'.php')) + { + include_once($path.'helpers/'.$helper.'.php'); + + $this->_ci_helpers[$helper] = TRUE; + log_message('debug', 'Helper loaded: '.$helper); + break; + } + } + + // unable to load the helper + if ( ! isset($this->_ci_helpers[$helper])) + { + show_error('Unable to load the requested file: helpers/'.$helper.'.php'); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Load Helpers + * + * This is simply an alias to the above function in case the + * user has written the plural form of this function. + * + * @param array + * @return void + */ + public function helpers($helpers = array()) + { + $this->helper($helpers); + } + + // -------------------------------------------------------------------- + + /** + * Loads a language file + * + * @param array + * @param string + * @return void + */ + public function language($file = array(), $lang = '') + { + $CI =& get_instance(); + + if ( ! is_array($file)) + { + $file = array($file); + } + + foreach ($file as $langfile) + { + $CI->lang->load($langfile, $lang); + } + } + + // -------------------------------------------------------------------- + + /** + * Loads a config file + * + * @param string + * @param bool + * @param bool + * @return void + */ + public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) + { + $CI =& get_instance(); + $CI->config->load($file, $use_sections, $fail_gracefully); + } + + // -------------------------------------------------------------------- + + /** + * Driver + * + * Loads a driver library + * + * @param string the name of the class + * @param mixed the optional parameters + * @param string an optional object name + * @return void + */ + public function driver($library = '', $params = NULL, $object_name = NULL) + { + if ( ! class_exists('CI_Driver_Library')) + { + // we aren't instantiating an object here, that'll be done by the Library itself + require BASEPATH.'libraries/Driver.php'; + } + + if ($library == '') + { + return FALSE; + } + + // We can save the loader some time since Drivers will *always* be in a subfolder, + // and typically identically named to the library + if ( ! strpos($library, '/')) + { + $library = ucfirst($library).'/'.$library; + } + + return $this->library($library, $params, $object_name); + } + + // -------------------------------------------------------------------- + + /** + * Add Package Path + * + * Prepends a parent path to the library, model, helper, and config path arrays + * + * @param string + * @param boolean + * @return void + */ + public function add_package_path($path, $view_cascade=TRUE) + { + $path = rtrim($path, '/').'/'; + + array_unshift($this->_ci_library_paths, $path); + array_unshift($this->_ci_model_paths, $path); + array_unshift($this->_ci_helper_paths, $path); + + $this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths; + + // Add config file path + $config =& $this->_ci_get_component('config'); + array_unshift($config->_config_paths, $path); + } + + // -------------------------------------------------------------------- + + /** + * Get Package Paths + * + * Return a list of all package paths, by default it will ignore BASEPATH. + * + * @param string + * @return void + */ + public function get_package_paths($include_base = FALSE) + { + return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths; + } + + // -------------------------------------------------------------------- + + /** + * Remove Package Path + * + * Remove a path from the library, model, and helper path arrays if it exists + * If no path is provided, the most recently added path is removed. + * + * @param type + * @param bool + * @return type + */ + public function remove_package_path($path = '', $remove_config_path = TRUE) + { + $config =& $this->_ci_get_component('config'); + + if ($path == '') + { + $void = array_shift($this->_ci_library_paths); + $void = array_shift($this->_ci_model_paths); + $void = array_shift($this->_ci_helper_paths); + $void = array_shift($this->_ci_view_paths); + $void = array_shift($config->_config_paths); + } + else + { + $path = rtrim($path, '/').'/'; + foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var) + { + if (($key = array_search($path, $this->{$var})) !== FALSE) + { + unset($this->{$var}[$key]); + } + } + + if (isset($this->_ci_view_paths[$path.'views/'])) + { + unset($this->_ci_view_paths[$path.'views/']); + } + + if (($key = array_search($path, $config->_config_paths)) !== FALSE) + { + unset($config->_config_paths[$key]); + } + } + + // make sure the application default paths are still in the array + $this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH))); + $this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH))); + $this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH))); + $this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE)); + $config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH))); + } + + // -------------------------------------------------------------------- + + /** + * Loader + * + * This function is used to load views and files. + * Variables are prefixed with _ci_ to avoid symbol collision with + * variables made available to view files + * + * @param array + * @return void + */ + protected function _ci_load($_ci_data) + { + // Set the default data variables + foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val) + { + $$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val]; + } + + $file_exists = FALSE; + + // Set the path to the requested file + if ($_ci_path != '') + { + $_ci_x = explode('/', $_ci_path); + $_ci_file = end($_ci_x); + } + else + { + $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); + $_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view; + + foreach ($this->_ci_view_paths as $view_file => $cascade) + { + if (file_exists($view_file.$_ci_file)) + { + $_ci_path = $view_file.$_ci_file; + $file_exists = TRUE; + break; + } + + if ( ! $cascade) + { + break; + } + } + } + + if ( ! $file_exists && ! file_exists($_ci_path)) + { + show_error('Unable to load the requested file: '.$_ci_file); + } + + // This allows anything loaded using $this->load (views, files, etc.) + // to become accessible from within the Controller and Model functions. + + $_ci_CI =& get_instance(); + foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var) + { + if ( ! isset($this->$_ci_key)) + { + $this->$_ci_key =& $_ci_CI->$_ci_key; + } + } + + /* + * Extract and cache variables + * + * You can either set variables using the dedicated $this->load_vars() + * function or via the second parameter of this function. We'll merge + * the two types and cache them so that views that are embedded within + * other views can have access to these variables. + */ + if (is_array($_ci_vars)) + { + $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars); + } + extract($this->_ci_cached_vars); + + /* + * Buffer the output + * + * We buffer the output for two reasons: + * 1. Speed. You get a significant speed boost. + * 2. So that the final rendered template can be + * post-processed by the output class. Why do we + * need post processing? For one thing, in order to + * show the elapsed page load time. Unless we + * can intercept the content right before it's sent to + * the browser and then stop the timer it won't be accurate. + */ + ob_start(); + + // If the PHP installation does not support short tags we'll + // do a little string replacement, changing the short tags + // to standard PHP echo statements. + + if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE) + { + echo eval('?>'.preg_replace("/;*\s*\?>/", "; ?>", str_replace(' $this->_ci_ob_level + 1) + { + ob_end_flush(); + } + else + { + $_ci_CI->output->append_output(ob_get_contents()); + @ob_end_clean(); + } + } + + // -------------------------------------------------------------------- + + /** + * Load class + * + * This function loads the requested class. + * + * @param string the item that is being loaded + * @param mixed any additional parameters + * @param string an optional object name + * @return void + */ + protected function _ci_load_class($class, $params = NULL, $object_name = NULL) + { + // Get the class name, and while we're at it trim any slashes. + // The directory path can be included as part of the class name, + // but we don't want a leading slash + $class = str_replace('.php', '', trim($class, '/')); + + // Was the path included with the class name? + // We look for a slash to determine this + $subdir = ''; + if (($last_slash = strrpos($class, '/')) !== FALSE) + { + // Extract the path + $subdir = substr($class, 0, $last_slash + 1); + + // Get the filename from the path + $class = substr($class, $last_slash + 1); + } + + // We'll test for both lowercase and capitalized versions of the file name + foreach (array(ucfirst($class), strtolower($class)) as $class) + { + $subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php'; + + // Is this a class extension request? + if (file_exists($subclass)) + { + $baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php'; + + if ( ! file_exists($baseclass)) + { + log_message('error', "Unable to load the requested class: ".$class); + show_error("Unable to load the requested class: ".$class); + } + + // Safety: Was the class already loaded by a previous call? + if (in_array($subclass, $this->_ci_loaded_files)) + { + // Before we deem this to be a duplicate request, let's see + // if a custom object name is being supplied. If so, we'll + // return a new instance of the object + if ( ! is_null($object_name)) + { + $CI =& get_instance(); + if ( ! isset($CI->$object_name)) + { + return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); + } + } + + $is_duplicate = TRUE; + log_message('debug', $class." class already loaded. Second attempt ignored."); + return; + } + + include_once($baseclass); + include_once($subclass); + $this->_ci_loaded_files[] = $subclass; + + return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); + } + + // Lets search for the requested library file and load it. + $is_duplicate = FALSE; + foreach ($this->_ci_library_paths as $path) + { + $filepath = $path.'libraries/'.$subdir.$class.'.php'; + + // Does the file exist? No? Bummer... + if ( ! file_exists($filepath)) + { + continue; + } + + // Safety: Was the class already loaded by a previous call? + if (in_array($filepath, $this->_ci_loaded_files)) + { + // Before we deem this to be a duplicate request, let's see + // if a custom object name is being supplied. If so, we'll + // return a new instance of the object + if ( ! is_null($object_name)) + { + $CI =& get_instance(); + if ( ! isset($CI->$object_name)) + { + return $this->_ci_init_class($class, '', $params, $object_name); + } + } + + $is_duplicate = TRUE; + log_message('debug', $class." class already loaded. Second attempt ignored."); + return; + } + + include_once($filepath); + $this->_ci_loaded_files[] = $filepath; + return $this->_ci_init_class($class, '', $params, $object_name); + } + + } // END FOREACH + + // One last attempt. Maybe the library is in a subdirectory, but it wasn't specified? + if ($subdir == '') + { + $path = strtolower($class).'/'.$class; + return $this->_ci_load_class($path, $params); + } + + // If we got this far we were unable to find the requested class. + // We do not issue errors if the load call failed due to a duplicate request + if ($is_duplicate == FALSE) + { + log_message('error', "Unable to load the requested class: ".$class); + show_error("Unable to load the requested class: ".$class); + } + } + + // -------------------------------------------------------------------- + + /** + * Instantiates a class + * + * @param string + * @param string + * @param bool + * @param string an optional object name + * @return null + */ + protected function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) + { + // Is there an associated config file for this class? Note: these should always be lowercase + if ($config === NULL) + { + // Fetch the config paths containing any package paths + $config_component = $this->_ci_get_component('config'); + + if (is_array($config_component->_config_paths)) + { + // Break on the first found file, thus package files + // are not overridden by default paths + foreach ($config_component->_config_paths as $path) + { + // We test for both uppercase and lowercase, for servers that + // are case-sensitive with regard to file names. Check for environment + // first, global next + if (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php')) + { + include($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'); + break; + } + elseif (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php')) + { + include($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'); + break; + } + elseif (file_exists($path .'config/'.strtolower($class).'.php')) + { + include($path .'config/'.strtolower($class).'.php'); + break; + } + elseif (file_exists($path .'config/'.ucfirst(strtolower($class)).'.php')) + { + include($path .'config/'.ucfirst(strtolower($class)).'.php'); + break; + } + } + } + } + + if ($prefix == '') + { + if (class_exists('CI_'.$class)) + { + $name = 'CI_'.$class; + } + elseif (class_exists(config_item('subclass_prefix').$class)) + { + $name = config_item('subclass_prefix').$class; + } + else + { + $name = $class; + } + } + else + { + $name = $prefix.$class; + } + + // Is the class name valid? + if ( ! class_exists($name)) + { + log_message('error', "Non-existent class: ".$name); + show_error("Non-existent class: ".$class); + } + + // Set the variable name we will assign the class to + // Was a custom class name supplied? If so we'll use it + $class = strtolower($class); + + if (is_null($object_name)) + { + $classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class]; + } + else + { + $classvar = $object_name; + } + + // Save the class name and object name + $this->_ci_classes[$class] = $classvar; + + // Instantiate the class + $CI =& get_instance(); + if ($config !== NULL) + { + $CI->$classvar = new $name($config); + } + else + { + $CI->$classvar = new $name; + } + } + + // -------------------------------------------------------------------- + + /** + * Autoloader + * + * The config/autoload.php file contains an array that permits sub-systems, + * libraries, and helpers to be loaded automatically. + * + * @param array + * @return void + */ + private function _ci_autoloader() + { + if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'); + } + else + { + include(APPPATH.'config/autoload.php'); + } + + if ( ! isset($autoload)) + { + return FALSE; + } + + // Autoload packages + if (isset($autoload['packages'])) + { + foreach ($autoload['packages'] as $package_path) + { + $this->add_package_path($package_path); + } + } + + // Load any custom config file + if (count($autoload['config']) > 0) + { + $CI =& get_instance(); + foreach ($autoload['config'] as $key => $val) + { + $CI->config->load($val); + } + } + + // Autoload helpers and languages + foreach (array('helper', 'language') as $type) + { + if (isset($autoload[$type]) AND count($autoload[$type]) > 0) + { + $this->$type($autoload[$type]); + } + } + + // A little tweak to remain backward compatible + // The $autoload['core'] item was deprecated + if ( ! isset($autoload['libraries']) AND isset($autoload['core'])) + { + $autoload['libraries'] = $autoload['core']; + } + + // Load libraries + if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0) + { + // Load the database driver. + if (in_array('database', $autoload['libraries'])) + { + $this->database(); + $autoload['libraries'] = array_diff($autoload['libraries'], array('database')); + } + + // Load all other libraries + foreach ($autoload['libraries'] as $item) + { + $this->library($item); + } + } + + // Autoload models + if (isset($autoload['model'])) + { + $this->model($autoload['model']); + } + } + + // -------------------------------------------------------------------- + + /** + * Object to Array + * + * Takes an object as input and converts the class variables to array key/vals + * + * @param object + * @return array + */ + protected function _ci_object_to_array($object) + { + return (is_object($object)) ? get_object_vars($object) : $object; + } + + // -------------------------------------------------------------------- + + /** + * Get a reference to a specific library or model + * + * @param string + * @return bool + */ + protected function &_ci_get_component($component) + { + $CI =& get_instance(); + return $CI->$component; + } + + // -------------------------------------------------------------------- + + /** + * Prep filename + * + * This function preps the name of various items to make loading them more reliable. + * + * @param mixed + * @param string + * @return array + */ + protected function _ci_prep_filename($filename, $extension) + { + if ( ! is_array($filename)) + { + return array(strtolower(str_replace('.php', '', str_replace($extension, '', $filename)).$extension)); + } + else + { + foreach ($filename as $key => $val) + { + $filename[$key] = strtolower(str_replace('.php', '', str_replace($extension, '', $val)).$extension); + } + + return $filename; + } + } +} + +/* End of file Loader.php */ +/* Location: ./system/core/Loader.php */ \ No newline at end of file diff --git a/system/core/Model.php b/system/core/Model.php new file mode 100644 index 0000000..e15ffbe --- /dev/null +++ b/system/core/Model.php @@ -0,0 +1,57 @@ +$key; + } +} +// END Model Class + +/* End of file Model.php */ +/* Location: ./system/core/Model.php */ \ No newline at end of file diff --git a/system/core/Output.php b/system/core/Output.php new file mode 100644 index 0000000..ccecafd --- /dev/null +++ b/system/core/Output.php @@ -0,0 +1,574 @@ +_zlib_oc = @ini_get('zlib.output_compression'); + + // Get mime types for later + if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) + { + include APPPATH.'config/'.ENVIRONMENT.'/mimes.php'; + } + else + { + include APPPATH.'config/mimes.php'; + } + + + $this->mime_types = $mimes; + + log_message('debug', "Output Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Get Output + * + * Returns the current output string + * + * @access public + * @return string + */ + function get_output() + { + return $this->final_output; + } + + // -------------------------------------------------------------------- + + /** + * Set Output + * + * Sets the output string + * + * @access public + * @param string + * @return void + */ + function set_output($output) + { + $this->final_output = $output; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Append Output + * + * Appends data onto the output string + * + * @access public + * @param string + * @return void + */ + function append_output($output) + { + if ($this->final_output == '') + { + $this->final_output = $output; + } + else + { + $this->final_output .= $output; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Header + * + * Lets you set a server header which will be outputted with the final display. + * + * Note: If a file is cached, headers will not be sent. We need to figure out + * how to permit header data to be saved with the cache data... + * + * @access public + * @param string + * @param bool + * @return void + */ + function set_header($header, $replace = TRUE) + { + // If zlib.output_compression is enabled it will compress the output, + // but it will not modify the content-length header to compensate for + // the reduction, causing the browser to hang waiting for more data. + // We'll just skip content-length in those cases. + + if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) == 0) + { + return; + } + + $this->headers[] = array($header, $replace); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Content Type Header + * + * @access public + * @param string extension of the file we're outputting + * @return void + */ + function set_content_type($mime_type) + { + if (strpos($mime_type, '/') === FALSE) + { + $extension = ltrim($mime_type, '.'); + + // Is this extension supported? + if (isset($this->mime_types[$extension])) + { + $mime_type =& $this->mime_types[$extension]; + + if (is_array($mime_type)) + { + $mime_type = current($mime_type); + } + } + } + + $header = 'Content-Type: '.$mime_type; + + $this->headers[] = array($header, TRUE); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set HTTP Status Header + * moved to Common procedural functions in 1.7.2 + * + * @access public + * @param int the status code + * @param string + * @return void + */ + function set_status_header($code = 200, $text = '') + { + set_status_header($code, $text); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Enable/disable Profiler + * + * @access public + * @param bool + * @return void + */ + function enable_profiler($val = TRUE) + { + $this->enable_profiler = (is_bool($val)) ? $val : TRUE; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Profiler Sections + * + * Allows override of default / config settings for Profiler section display + * + * @access public + * @param array + * @return void + */ + function set_profiler_sections($sections) + { + foreach ($sections as $section => $enable) + { + $this->_profiler_sections[$section] = ($enable !== FALSE) ? TRUE : FALSE; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Cache + * + * @access public + * @param integer + * @return void + */ + function cache($time) + { + $this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Display Output + * + * All "view" data is automatically put into this variable by the controller class: + * + * $this->final_output + * + * This function sends the finalized output data to the browser along + * with any server headers and profile data. It also stops the + * benchmark timer so the page rendering speed and memory usage can be shown. + * + * @access public + * @param string + * @return mixed + */ + function _display($output = '') + { + // Note: We use globals because we can't use $CI =& get_instance() + // since this function is sometimes called by the caching mechanism, + // which happens before the CI super object is available. + global $BM, $CFG; + + // Grab the super object if we can. + if (class_exists('CI_Controller')) + { + $CI =& get_instance(); + } + + // -------------------------------------------------------------------- + + // Set the output data + if ($output == '') + { + $output =& $this->final_output; + } + + // -------------------------------------------------------------------- + + // Do we need to write a cache file? Only if the controller does not have its + // own _output() method and we are not dealing with a cache file, which we + // can determine by the existence of the $CI object above + if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output')) + { + $this->_write_cache($output); + } + + // -------------------------------------------------------------------- + + // Parse out the elapsed time and memory usage, + // then swap the pseudo-variables with the data + + $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end'); + + if ($this->parse_exec_vars === TRUE) + { + $memory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB'; + + $output = str_replace('{elapsed_time}', $elapsed, $output); + $output = str_replace('{memory_usage}', $memory, $output); + } + + // -------------------------------------------------------------------- + + // Is compression requested? + if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc == FALSE) + { + if (extension_loaded('zlib')) + { + if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) AND strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE) + { + ob_start('ob_gzhandler'); + } + } + } + + // -------------------------------------------------------------------- + + // Are there any server headers to send? + if (count($this->headers) > 0) + { + foreach ($this->headers as $header) + { + @header($header[0], $header[1]); + } + } + + // -------------------------------------------------------------------- + + // Does the $CI object exist? + // If not we know we are dealing with a cache file so we'll + // simply echo out the data and exit. + if ( ! isset($CI)) + { + echo $output; + log_message('debug', "Final output sent to browser"); + log_message('debug', "Total execution time: ".$elapsed); + return TRUE; + } + + // -------------------------------------------------------------------- + + // Do we need to generate profile data? + // If so, load the Profile class and run it. + if ($this->enable_profiler == TRUE) + { + $CI->load->library('profiler'); + + if ( ! empty($this->_profiler_sections)) + { + $CI->profiler->set_sections($this->_profiler_sections); + } + + // If the output data contains closing and tags + // we will remove them and add them back after we insert the profile data + if (preg_match("|.*?|is", $output)) + { + $output = preg_replace("|.*?|is", '', $output); + $output .= $CI->profiler->run(); + $output .= ''; + } + else + { + $output .= $CI->profiler->run(); + } + } + + // -------------------------------------------------------------------- + + // Does the controller contain a function named _output()? + // If so send the output there. Otherwise, echo it. + if (method_exists($CI, '_output')) + { + $CI->_output($output); + } + else + { + echo $output; // Send it to the browser! + } + + log_message('debug', "Final output sent to browser"); + log_message('debug', "Total execution time: ".$elapsed); + } + + // -------------------------------------------------------------------- + + /** + * Write a Cache File + * + * @access public + * @param string + * @return void + */ + function _write_cache($output) + { + $CI =& get_instance(); + $path = $CI->config->item('cache_path'); + + $cache_path = ($path == '') ? APPPATH.'cache/' : $path; + + if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path)) + { + log_message('error', "Unable to write cache file: ".$cache_path); + return; + } + + $uri = $CI->config->item('base_url'). + $CI->config->item('index_page'). + $CI->uri->uri_string(); + + $cache_path .= md5($uri); + + if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE)) + { + log_message('error', "Unable to write cache file: ".$cache_path); + return; + } + + $expire = time() + ($this->cache_expiration * 60); + + if (flock($fp, LOCK_EX)) + { + fwrite($fp, $expire.'TS--->'.$output); + flock($fp, LOCK_UN); + } + else + { + log_message('error', "Unable to secure a file lock for file at: ".$cache_path); + return; + } + fclose($fp); + @chmod($cache_path, FILE_WRITE_MODE); + + log_message('debug', "Cache file written: ".$cache_path); + } + + // -------------------------------------------------------------------- + + /** + * Update/serve a cached file + * + * @access public + * @param object config class + * @param object uri class + * @return void + */ + function _display_cache(&$CFG, &$URI) + { + $cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path'); + + // Build the file path. The file name is an MD5 hash of the full URI + $uri = $CFG->item('base_url'). + $CFG->item('index_page'). + $URI->uri_string; + + $filepath = $cache_path.md5($uri); + + if ( ! @file_exists($filepath)) + { + return FALSE; + } + + if ( ! $fp = @fopen($filepath, FOPEN_READ)) + { + return FALSE; + } + + flock($fp, LOCK_SH); + + $cache = ''; + if (filesize($filepath) > 0) + { + $cache = fread($fp, filesize($filepath)); + } + + flock($fp, LOCK_UN); + fclose($fp); + + // Strip out the embedded timestamp + if ( ! preg_match("/(\d+TS--->)/", $cache, $match)) + { + return FALSE; + } + + // Has the file expired? If so we'll delete it. + if (time() >= trim(str_replace('TS--->', '', $match['1']))) + { + if (is_really_writable($cache_path)) + { + @unlink($filepath); + log_message('debug', "Cache file has expired. File deleted"); + return FALSE; + } + } + + // Display the cache + $this->_display(str_replace($match['0'], '', $cache)); + log_message('debug', "Cache file is current. Sending it to browser."); + return TRUE; + } + + +} +// END Output Class + +/* End of file Output.php */ +/* Location: ./system/core/Output.php */ \ No newline at end of file diff --git a/system/core/Router.php b/system/core/Router.php new file mode 100644 index 0000000..6da6674 --- /dev/null +++ b/system/core/Router.php @@ -0,0 +1,522 @@ +config =& load_class('Config', 'core'); + $this->uri =& load_class('URI', 'core'); + log_message('debug', "Router Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Set the route mapping + * + * This function determines what should be served based on the URI request, + * as well as any "routes" that have been set in the routing config file. + * + * @access private + * @return void + */ + function _set_routing() + { + // Are query strings enabled in the config file? Normally CI doesn't utilize query strings + // since URI segments are more search-engine friendly, but they can optionally be used. + // If this feature is enabled, we will gather the directory/class/method a little differently + $segments = array(); + if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')])) + { + if (isset($_GET[$this->config->item('directory_trigger')])) + { + $this->set_directory(trim($this->uri->_filter_uri($_GET[$this->config->item('directory_trigger')]))); + $segments[] = $this->fetch_directory(); + } + + if (isset($_GET[$this->config->item('controller_trigger')])) + { + $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')]))); + $segments[] = $this->fetch_class(); + } + + if (isset($_GET[$this->config->item('function_trigger')])) + { + $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')]))); + $segments[] = $this->fetch_method(); + } + } + + // Load the routes.php file. + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/routes.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/routes.php'); + } + elseif (is_file(APPPATH.'config/routes.php')) + { + include(APPPATH.'config/routes.php'); + } + + $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route; + unset($route); + + // Set the default controller so we can display it in the event + // the URI doesn't correlated to a valid controller. + $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']); + + // Were there any query string segments? If so, we'll validate them and bail out since we're done. + if (count($segments) > 0) + { + return $this->_validate_request($segments); + } + + // Fetch the complete URI string + $this->uri->_fetch_uri_string(); + + // Is there a URI string? If not, the default controller specified in the "routes" file will be shown. + if ($this->uri->uri_string == '') + { + return $this->_set_default_controller(); + } + + // Do we need to remove the URL suffix? + $this->uri->_remove_url_suffix(); + + // Compile the segments into an array + $this->uri->_explode_segments(); + + // Parse any custom routing that may exist + $this->_parse_routes(); + + // Re-index the segment array so that it starts with 1 rather than 0 + $this->uri->_reindex_segments(); + } + + // -------------------------------------------------------------------- + + /** + * Set the default controller + * + * @access private + * @return void + */ + function _set_default_controller() + { + if ($this->default_controller === FALSE) + { + show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file."); + } + // Is the method being specified? + if (strpos($this->default_controller, '/') !== FALSE) + { + $x = explode('/', $this->default_controller); + + $this->set_class($x[0]); + $this->set_method($x[1]); + $this->_set_request($x); + } + else + { + $this->set_class($this->default_controller); + $this->set_method('index'); + $this->_set_request(array($this->default_controller, 'index')); + } + + // re-index the routed segments array so it starts with 1 rather than 0 + $this->uri->_reindex_segments(); + + log_message('debug', "No URI present. Default controller set."); + } + + // -------------------------------------------------------------------- + + /** + * Set the Route + * + * This function takes an array of URI segments as + * input, and sets the current class/method + * + * @access private + * @param array + * @param bool + * @return void + */ + function _set_request($segments = array()) + { + $segments = $this->_validate_request($segments); + + if (count($segments) == 0) + { + return $this->_set_default_controller(); + } + + $this->set_class($segments[0]); + + if (isset($segments[1])) + { + // A standard method request + $this->set_method($segments[1]); + } + else + { + // This lets the "routed" segment array identify that the default + // index method is being used. + $segments[1] = 'index'; + } + + // Update our "routed" segment array to contain the segments. + // Note: If there is no custom routing, this array will be + // identical to $this->uri->segments + $this->uri->rsegments = $segments; + } + + // -------------------------------------------------------------------- + + /** + * Validates the supplied segments. Attempts to determine the path to + * the controller. + * + * @access private + * @param array + * @return array + */ + function _validate_request($segments) + { + if (count($segments) == 0) + { + return $segments; + } + + // Does the requested controller exist in the root folder? + if (file_exists(APPPATH.'controllers/'.$segments[0].'.php')) + { + return $segments; + } + + // Is the controller in a sub-folder? + if (is_dir(APPPATH.'controllers/'.$segments[0])) + { + // Set the directory and remove it from the segment array + $this->set_directory($segments[0]); + $segments = array_slice($segments, 1); + + if (count($segments) > 0) + { + // Does the requested controller exist in the sub-folder? + if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php')) + { + if ( ! empty($this->routes['404_override'])) + { + $x = explode('/', $this->routes['404_override']); + + $this->set_directory(''); + $this->set_class($x[0]); + $this->set_method(isset($x[1]) ? $x[1] : 'index'); + + return $x; + } + else + { + show_404($this->fetch_directory().$segments[0]); + } + } + } + else + { + // Is the method being specified in the route? + if (strpos($this->default_controller, '/') !== FALSE) + { + $x = explode('/', $this->default_controller); + + $this->set_class($x[0]); + $this->set_method($x[1]); + } + else + { + $this->set_class($this->default_controller); + $this->set_method('index'); + } + + // Does the default controller exist in the sub-folder? + if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php')) + { + $this->directory = ''; + return array(); + } + + } + + return $segments; + } + + + // If we've gotten this far it means that the URI does not correlate to a valid + // controller class. We will now see if there is an override + if ( ! empty($this->routes['404_override'])) + { + $x = explode('/', $this->routes['404_override']); + + $this->set_class($x[0]); + $this->set_method(isset($x[1]) ? $x[1] : 'index'); + + return $x; + } + + + // Nothing else to do at this point but show a 404 + show_404($segments[0]); + } + + // -------------------------------------------------------------------- + + /** + * Parse Routes + * + * This function matches any routes that may exist in + * the config/routes.php file against the URI to + * determine if the class/method need to be remapped. + * + * @access private + * @return void + */ + function _parse_routes() + { + // Turn the segment array into a URI string + $uri = implode('/', $this->uri->segments); + + // Is there a literal match? If so we're done + if (isset($this->routes[$uri])) + { + return $this->_set_request(explode('/', $this->routes[$uri])); + } + + // Loop through the route array looking for wild-cards + foreach ($this->routes as $key => $val) + { + // Convert wild-cards to RegEx + $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key)); + + // Does the RegEx match? + if (preg_match('#^'.$key.'$#', $uri)) + { + // Do we have a back-reference? + if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE) + { + $val = preg_replace('#^'.$key.'$#', $val, $uri); + } + + return $this->_set_request(explode('/', $val)); + } + } + + // If we got this far it means we didn't encounter a + // matching route so we'll set the site default route + $this->_set_request($this->uri->segments); + } + + // -------------------------------------------------------------------- + + /** + * Set the class name + * + * @access public + * @param string + * @return void + */ + function set_class($class) + { + $this->class = str_replace(array('/', '.'), '', $class); + } + + // -------------------------------------------------------------------- + + /** + * Fetch the current class + * + * @access public + * @return string + */ + function fetch_class() + { + return $this->class; + } + + // -------------------------------------------------------------------- + + /** + * Set the method name + * + * @access public + * @param string + * @return void + */ + function set_method($method) + { + $this->method = $method; + } + + // -------------------------------------------------------------------- + + /** + * Fetch the current method + * + * @access public + * @return string + */ + function fetch_method() + { + if ($this->method == $this->fetch_class()) + { + return 'index'; + } + + return $this->method; + } + + // -------------------------------------------------------------------- + + /** + * Set the directory name + * + * @access public + * @param string + * @return void + */ + function set_directory($dir) + { + $this->directory = str_replace(array('/', '.'), '', $dir).'/'; + } + + // -------------------------------------------------------------------- + + /** + * Fetch the sub-directory (if any) that contains the requested controller class + * + * @access public + * @return string + */ + function fetch_directory() + { + return $this->directory; + } + + // -------------------------------------------------------------------- + + /** + * Set the controller overrides + * + * @access public + * @param array + * @return null + */ + function _set_overrides($routing) + { + if ( ! is_array($routing)) + { + return; + } + + if (isset($routing['directory'])) + { + $this->set_directory($routing['directory']); + } + + if (isset($routing['controller']) AND $routing['controller'] != '') + { + $this->set_class($routing['controller']); + } + + if (isset($routing['function'])) + { + $routing['function'] = ($routing['function'] == '') ? 'index' : $routing['function']; + $this->set_method($routing['function']); + } + } + + +} +// END Router Class + +/* End of file Router.php */ +/* Location: ./system/core/Router.php */ \ No newline at end of file diff --git a/system/core/Security.php b/system/core/Security.php new file mode 100644 index 0000000..00089d7 --- /dev/null +++ b/system/core/Security.php @@ -0,0 +1,876 @@ + '[removed]', + 'document.write' => '[removed]', + '.parentNode' => '[removed]', + '.innerHTML' => '[removed]', + 'window.location' => '[removed]', + '-moz-binding' => '[removed]', + '' => '-->', + ' '<![CDATA[', + '' => '<comment>' + ); + + /* never allowed, regex replacement */ + /** + * List of never allowed regex replacement + * + * @var array + * @access protected + */ + protected $_never_allowed_regex = array( + 'javascript\s*:', + 'expression\s*(\(|&\#40;)', // CSS and IE + 'vbscript\s*:', // IE, surprise! + 'Redirect\s+302', + "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?" + ); + + /** + * Constructor + * + * @return void + */ + public function __construct() + { + // Is CSRF protection enabled? + if (config_item('csrf_protection') === TRUE) + { + // CSRF config + foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key) + { + if (FALSE !== ($val = config_item($key))) + { + $this->{'_'.$key} = $val; + } + } + + // Append application specific cookie prefix + if (config_item('cookie_prefix')) + { + $this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name; + } + + // Set the CSRF hash + $this->_csrf_set_hash(); + } + + log_message('debug', "Security Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Verify Cross Site Request Forgery Protection + * + * @return object + */ + public function csrf_verify() + { + // If it's not a POST request we will set the CSRF cookie + if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') + { + return $this->csrf_set_cookie(); + } + + // Do the tokens exist in both the _POST and _COOKIE arrays? + if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])) + { + $this->csrf_show_error(); + } + + // Do the tokens match? + if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name]) + { + $this->csrf_show_error(); + } + + // We kill this since we're done and we don't want to + // polute the _POST array + unset($_POST[$this->_csrf_token_name]); + + // Nothing should last forever + unset($_COOKIE[$this->_csrf_cookie_name]); + $this->_csrf_set_hash(); + $this->csrf_set_cookie(); + + log_message('debug', 'CSRF token verified'); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Cross Site Request Forgery Protection Cookie + * + * @return object + */ + public function csrf_set_cookie() + { + $expire = time() + $this->_csrf_expire; + $secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0; + + if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off')) + { + return FALSE; + } + + setcookie($this->_csrf_cookie_name, $this->_csrf_hash, $expire, config_item('cookie_path'), config_item('cookie_domain'), $secure_cookie); + + log_message('debug', "CRSF cookie Set"); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Show CSRF Error + * + * @return void + */ + public function csrf_show_error() + { + show_error('The action you have requested is not allowed.'); + } + + // -------------------------------------------------------------------- + + /** + * Get CSRF Hash + * + * Getter Method + * + * @return string self::_csrf_hash + */ + public function get_csrf_hash() + { + return $this->_csrf_hash; + } + + // -------------------------------------------------------------------- + + /** + * Get CSRF Token Name + * + * Getter Method + * + * @return string self::csrf_token_name + */ + public function get_csrf_token_name() + { + return $this->_csrf_token_name; + } + + // -------------------------------------------------------------------- + + /** + * XSS Clean + * + * Sanitizes data so that Cross Site Scripting Hacks can be + * prevented. This function does a fair amount of work but + * it is extremely thorough, designed to prevent even the + * most obscure XSS attempts. Nothing is ever 100% foolproof, + * of course, but I haven't been able to get anything passed + * the filter. + * + * Note: This function should only be used to deal with data + * upon submission. It's not something that should + * be used for general runtime processing. + * + * This function was based in part on some code and ideas I + * got from Bitflux: http://channel.bitflux.ch/wiki/XSS_Prevention + * + * To help develop this script I used this great list of + * vulnerabilities along with a few other hacks I've + * harvested from examining vulnerabilities in other programs: + * http://ha.ckers.org/xss.html + * + * @param mixed string or array + * @param bool + * @return string + */ + public function xss_clean($str, $is_image = FALSE) + { + /* + * Is the string an array? + * + */ + if (is_array($str)) + { + while (list($key) = each($str)) + { + $str[$key] = $this->xss_clean($str[$key]); + } + + return $str; + } + + /* + * Remove Invisible Characters + */ + $str = remove_invisible_characters($str); + + // Validate Entities in URLs + $str = $this->_validate_entities($str); + + /* + * URL Decode + * + * Just in case stuff like this is submitted: + * + * Google + * + * Note: Use rawurldecode() so it does not remove plus signs + * + */ + $str = rawurldecode($str); + + /* + * Convert character entities to ASCII + * + * This permits our tests below to work reliably. + * We only convert entities that are within tags since + * these are the ones that will pose security problems. + * + */ + + $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str); + + $str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, '_decode_entity'), $str); + + /* + * Remove Invisible Characters Again! + */ + $str = remove_invisible_characters($str); + + /* + * Convert all tabs to spaces + * + * This prevents strings like this: ja vascript + * NOTE: we deal with spaces between characters later. + * NOTE: preg_replace was found to be amazingly slow here on + * large blocks of data, so we use str_replace. + */ + + if (strpos($str, "\t") !== FALSE) + { + $str = str_replace("\t", ' ', $str); + } + + /* + * Capture converted string for later comparison + */ + $converted_string = $str; + + // Remove Strings that are never allowed + $str = $this->_do_never_allowed($str); + + /* + * Makes PHP tags safe + * + * Note: XML tags are inadvertently replaced too: + * + * '), array('<?', '?>'), $str); + } + + /* + * Compact any exploded words + * + * This corrects words like: j a v a s c r i p t + * These words are compacted back to their correct state. + */ + $words = array( + 'javascript', 'expression', 'vbscript', 'script', 'base64', + 'applet', 'alert', 'document', 'write', 'cookie', 'window' + ); + + foreach ($words as $word) + { + $temp = ''; + + for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++) + { + $temp .= substr($word, $i, 1)."\s*"; + } + + // We only want to do this when it is followed by a non-word character + // That way valid stuff like "dealer to" does not become "dealerto" + $str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str); + } + + /* + * Remove disallowed Javascript in links or img tags + * We used to do some version comparisons and use of stripos for PHP5, + * but it is dog slow compared to these simplified non-capturing + * preg_match(), especially if the pattern exists in the string + */ + do + { + $original = $str; + + if (preg_match("/]*?)(>|$)#si", array($this, '_js_link_removal'), $str); + } + + if (preg_match("/]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str); + } + + if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str)) + { + $str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str); + } + } + while($original != $str); + + unset($original); + + // Remove evil attributes such as style, onclick and xmlns + $str = $this->_remove_evil_attributes($str, $is_image); + + /* + * Sanitize naughty HTML elements + * + * If a tag containing any of the words in the list + * below is found, the tag gets converted to entities. + * + * So this: + * Becomes: <blink> + */ + $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss'; + $str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str); + + /* + * Sanitize naughty scripting elements + * + * Similar to above, only instead of looking for + * tags it looks for PHP and JavaScript commands + * that are disallowed. Rather than removing the + * code, it simply converts the parenthesis to entities + * rendering the code un-executable. + * + * For example: eval('some code') + * Becomes: eval('some code') + */ + $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2(\\3)", $str); + + + // Final clean up + // This adds a bit of extra precaution in case + // something got through the above filters + $str = $this->_do_never_allowed($str); + + /* + * Images are Handled in a Special Way + * - Essentially, we want to know that after all of the character + * conversion is done whether any unwanted, likely XSS, code was found. + * If not, we return TRUE, as the image is clean. + * However, if the string post-conversion does not matched the + * string post-removal of XSS, then it fails, as there was unwanted XSS + * code found and removed/changed during processing. + */ + + if ($is_image === TRUE) + { + return ($str == $converted_string) ? TRUE: FALSE; + } + + log_message('debug', "XSS Filtering completed"); + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Random Hash for protecting URLs + * + * @return string + */ + public function xss_hash() + { + if ($this->_xss_hash == '') + { + mt_srand(); + $this->_xss_hash = md5(time() + mt_rand(0, 1999999999)); + } + + return $this->_xss_hash; + } + + // -------------------------------------------------------------------- + + /** + * HTML Entities Decode + * + * This function is a replacement for html_entity_decode() + * + * The reason we are not using html_entity_decode() by itself is because + * while it is not technically correct to leave out the semicolon + * at the end of an entity most browsers will still interpret the entity + * correctly. html_entity_decode() does not convert entities without + * semicolons, so we are left with our own little solution here. Bummer. + * + * @param string + * @param string + * @return string + */ + public function entity_decode($str, $charset='UTF-8') + { + if (stristr($str, '&') === FALSE) + { + return $str; + } + + $str = html_entity_decode($str, ENT_COMPAT, $charset); + $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str); + return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str); + } + + // -------------------------------------------------------------------- + + /** + * Filename Security + * + * @param string + * @param bool + * @return string + */ + public function sanitize_filename($str, $relative_path = FALSE) + { + $bad = array( + "../", + "", + "<", + ">", + "'", + '"', + '&', + '$', + '#', + '{', + '}', + '[', + ']', + '=', + ';', + '?', + "%20", + "%22", + "%3c", // < + "%253c", // < + "%3e", // > + "%0e", // > + "%28", // ( + "%29", // ) + "%2528", // ( + "%26", // & + "%24", // $ + "%3f", // ? + "%3b", // ; + "%3d" // = + ); + + if ( ! $relative_path) + { + $bad[] = './'; + $bad[] = '/'; + } + + $str = remove_invisible_characters($str, FALSE); + return stripslashes(str_replace($bad, '', $str)); + } + + // ---------------------------------------------------------------- + + /** + * Compact Exploded Words + * + * Callback function for xss_clean() to remove whitespace from + * things like j a v a s c r i p t + * + * @param type + * @return type + */ + protected function _compact_exploded_words($matches) + { + return preg_replace('/\s+/s', '', $matches[1]).$matches[2]; + } + + // -------------------------------------------------------------------- + + /* + * Remove Evil HTML Attributes (like evenhandlers and style) + * + * It removes the evil attribute and either: + * - Everything up until a space + * For example, everything between the pipes: + * + * - Everything inside the quotes + * For example, everything between the pipes: + * + * + * @param string $str The string to check + * @param boolean $is_image TRUE if this is an image + * @return string The string with the evil attributes removed + */ + protected function _remove_evil_attributes($str, $is_image) + { + // All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns + $evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction'); + + if ($is_image === TRUE) + { + /* + * Adobe Photoshop puts XML metadata into JFIF images, + * including namespacing, so we have to allow this for images. + */ + unset($evil_attributes[array_search('xmlns', $evil_attributes)]); + } + + do { + $count = 0; + $attribs = array(); + + // find occurrences of illegal attribute strings without quotes + preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s>]*)/is', $str, $matches, PREG_SET_ORDER); + + foreach ($matches as $attr) + { + + $attribs[] = preg_quote($attr[0], '/'); + } + + // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes) + preg_match_all("/(".implode('|', $evil_attributes).")\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is", $str, $matches, PREG_SET_ORDER); + + foreach ($matches as $attr) + { + $attribs[] = preg_quote($attr[0], '/'); + } + + // replace illegal attribute strings that are inside an html tag + if (count($attribs) > 0) + { + $str = preg_replace("/<(\/?[^><]+?)([^A-Za-z<>\-])(.*?)(".implode('|', $attribs).")(.*?)([\s><])([><]*)/i", '<$1 $3$5$6$7', $str, -1, $count); + } + + } while ($count); + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Sanitize Naughty HTML + * + * Callback function for xss_clean() to remove naughty HTML elements + * + * @param array + * @return string + */ + protected function _sanitize_naughty_html($matches) + { + // encode opening brace + $str = '<'.$matches[1].$matches[2].$matches[3]; + + // encode captured opening or closing brace to prevent recursive vectors + $str .= str_replace(array('>', '<'), array('>', '<'), + $matches[4]); + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * JS Link Removal + * + * Callback function for xss_clean() to sanitize links + * This limits the PCRE backtracks, making it more performance friendly + * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in + * PHP 5.2+ on link-heavy strings + * + * @param array + * @return string + */ + protected function _js_link_removal($match) + { + return str_replace( + $match[1], + preg_replace( + '#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) + ), + $match[0] + ); + } + + // -------------------------------------------------------------------- + + /** + * JS Image Removal + * + * Callback function for xss_clean() to sanitize image tags + * This limits the PCRE backtracks, making it more performance friendly + * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in + * PHP 5.2+ on image tag heavy strings + * + * @param array + * @return string + */ + protected function _js_img_removal($match) + { + return str_replace( + $match[1], + preg_replace( + '#src=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) + ), + $match[0] + ); + } + + // -------------------------------------------------------------------- + + /** + * Attribute Conversion + * + * Used as a callback for XSS Clean + * + * @param array + * @return string + */ + protected function _convert_attribute($match) + { + return str_replace(array('>', '<', '\\'), array('>', '<', '\\\\'), $match[0]); + } + + // -------------------------------------------------------------------- + + /** + * Filter Attributes + * + * Filters tag attributes for consistency and safety + * + * @param string + * @return string + */ + protected function _filter_attributes($str) + { + $out = ''; + + if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches)) + { + foreach ($matches[0] as $match) + { + $out .= preg_replace("#/\*.*?\*/#s", '', $match); + } + } + + return $out; + } + + // -------------------------------------------------------------------- + + /** + * HTML Entity Decode Callback + * + * Used as a callback for XSS Clean + * + * @param array + * @return string + */ + protected function _decode_entity($match) + { + return $this->entity_decode($match[0], strtoupper(config_item('charset'))); + } + + // -------------------------------------------------------------------- + + /** + * Validate URL entities + * + * Called by xss_clean() + * + * @param string + * @return string + */ + protected function _validate_entities($str) + { + /* + * Protect GET variables in URLs + */ + + // 901119URL5918AMP18930PROTECT8198 + + $str = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i', $this->xss_hash()."\\1=\\2", $str); + + /* + * Validate standard character entities + * + * Add a semicolon if missing. We do this to enable + * the conversion of entities to ASCII later. + * + */ + $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str); + + /* + * Validate UTF16 two byte encoding (x00) + * + * Just as above, adds a semicolon if missing. + * + */ + $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str); + + /* + * Un-Protect GET variables in URLs + */ + $str = str_replace($this->xss_hash(), '&', $str); + + return $str; + } + + // ---------------------------------------------------------------------- + + /** + * Do Never Allowed + * + * A utility function for xss_clean() + * + * @param string + * @return string + */ + protected function _do_never_allowed($str) + { + $str = str_replace(array_keys($this->_never_allowed_str), $this->_never_allowed_str, $str); + + foreach ($this->_never_allowed_regex as $regex) + { + $str = preg_replace('#'.$regex.'#is', '[removed]', $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Set Cross Site Request Forgery Protection Cookie + * + * @return string + */ + protected function _csrf_set_hash() + { + if ($this->_csrf_hash == '') + { + // If the cookie exists we will use it's value. + // We don't necessarily want to regenerate it with + // each page load since a page could contain embedded + // sub-pages causing this feature to fail + if (isset($_COOKIE[$this->_csrf_cookie_name]) && + preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_csrf_cookie_name]) === 1) + { + return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name]; + } + + return $this->_csrf_hash = md5(uniqid(rand(), TRUE)); + } + + return $this->_csrf_hash; + } + +} + +/* End of file Security.php */ +/* Location: ./system/libraries/Security.php */ \ No newline at end of file diff --git a/system/core/URI.php b/system/core/URI.php new file mode 100644 index 0000000..a3ae20c --- /dev/null +++ b/system/core/URI.php @@ -0,0 +1,654 @@ +config =& load_class('Config', 'core'); + log_message('debug', "URI Class Initialized"); + } + + + // -------------------------------------------------------------------- + + /** + * Get the URI String + * + * @access private + * @return string + */ + function _fetch_uri_string() + { + if (strtoupper($this->config->item('uri_protocol')) == 'AUTO') + { + // Is the request coming from the command line? + if (php_sapi_name() == 'cli' or defined('STDIN')) + { + $this->_set_uri_string($this->_parse_cli_args()); + return; + } + + // Let's try the REQUEST_URI first, this will work in most situations + if ($uri = $this->_detect_uri()) + { + $this->_set_uri_string($uri); + return; + } + + // Is there a PATH_INFO variable? + // Note: some servers seem to have trouble with getenv() so we'll test it two ways + $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO'); + if (trim($path, '/') != '' && $path != "/".SELF) + { + $this->_set_uri_string($path); + return; + } + + // No PATH_INFO?... What about QUERY_STRING? + $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING'); + if (trim($path, '/') != '') + { + $this->_set_uri_string($path); + return; + } + + // As a last ditch effort lets try using the $_GET array + if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '') + { + $this->_set_uri_string(key($_GET)); + return; + } + + // We've exhausted all our options... + $this->uri_string = ''; + return; + } + + $uri = strtoupper($this->config->item('uri_protocol')); + + if ($uri == 'REQUEST_URI') + { + $this->_set_uri_string($this->_detect_uri()); + return; + } + elseif ($uri == 'CLI') + { + $this->_set_uri_string($this->_parse_cli_args()); + return; + } + + $path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri); + $this->_set_uri_string($path); + } + + // -------------------------------------------------------------------- + + /** + * Set the URI String + * + * @access public + * @param string + * @return string + */ + function _set_uri_string($str) + { + // Filter out control characters + $str = remove_invisible_characters($str, FALSE); + + // If the URI contains only a slash we'll kill it + $this->uri_string = ($str == '/') ? '' : $str; + } + + // -------------------------------------------------------------------- + + /** + * Detects the URI + * + * This function will detect the URI automatically and fix the query string + * if necessary. + * + * @access private + * @return string + */ + private function _detect_uri() + { + if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME'])) + { + return ''; + } + + $uri = $_SERVER['REQUEST_URI']; + if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) + { + $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); + } + elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) + { + $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME']))); + } + + // This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct + // URI is found, and also fixes the QUERY_STRING server var and $_GET array. + if (strncmp($uri, '?/', 2) === 0) + { + $uri = substr($uri, 2); + } + $parts = preg_split('#\?#i', $uri, 2); + $uri = $parts[0]; + if (isset($parts[1])) + { + $_SERVER['QUERY_STRING'] = $parts[1]; + parse_str($_SERVER['QUERY_STRING'], $_GET); + } + else + { + $_SERVER['QUERY_STRING'] = ''; + $_GET = array(); + } + + if ($uri == '/' || empty($uri)) + { + return '/'; + } + + $uri = parse_url($uri, PHP_URL_PATH); + + // Do some final cleaning of the URI and return it + return str_replace(array('//', '../'), '/', trim($uri, '/')); + } + + // -------------------------------------------------------------------- + + /** + * Parse cli arguments + * + * Take each command line argument and assume it is a URI segment. + * + * @access private + * @return string + */ + private function _parse_cli_args() + { + $args = array_slice($_SERVER['argv'], 1); + + return $args ? '/' . implode('/', $args) : ''; + } + + // -------------------------------------------------------------------- + + /** + * Filter segments for malicious characters + * + * @access private + * @param string + * @return string + */ + function _filter_uri($str) + { + if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE) + { + // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards + // compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern + if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str)) + { + show_error('The URI you submitted has disallowed characters.', 400); + } + } + + // Convert programatic characters to entities + $bad = array('$', '(', ')', '%28', '%29'); + $good = array('$', '(', ')', '(', ')'); + + return str_replace($bad, $good, $str); + } + + // -------------------------------------------------------------------- + + /** + * Remove the suffix from the URL if needed + * + * @access private + * @return void + */ + function _remove_url_suffix() + { + if ($this->config->item('url_suffix') != "") + { + $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string); + } + } + + // -------------------------------------------------------------------- + + /** + * Explode the URI Segments. The individual segments will + * be stored in the $this->segments array. + * + * @access private + * @return void + */ + function _explode_segments() + { + foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) + { + // Filter segments for security + $val = trim($this->_filter_uri($val)); + + if ($val != '') + { + $this->segments[] = $val; + } + } + } + + // -------------------------------------------------------------------- + /** + * Re-index Segments + * + * This function re-indexes the $this->segment array so that it + * starts at 1 rather than 0. Doing so makes it simpler to + * use functions like $this->uri->segment(n) since there is + * a 1:1 relationship between the segment array and the actual segments. + * + * @access private + * @return void + */ + function _reindex_segments() + { + array_unshift($this->segments, NULL); + array_unshift($this->rsegments, NULL); + unset($this->segments[0]); + unset($this->rsegments[0]); + } + + // -------------------------------------------------------------------- + + /** + * Fetch a URI Segment + * + * This function returns the URI segment based on the number provided. + * + * @access public + * @param integer + * @param bool + * @return string + */ + function segment($n, $no_result = FALSE) + { + return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n]; + } + + // -------------------------------------------------------------------- + + /** + * Fetch a URI "routed" Segment + * + * This function returns the re-routed URI segment (assuming routing rules are used) + * based on the number provided. If there is no routing this function returns the + * same result as $this->segment() + * + * @access public + * @param integer + * @param bool + * @return string + */ + function rsegment($n, $no_result = FALSE) + { + return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n]; + } + + // -------------------------------------------------------------------- + + /** + * Generate a key value pair from the URI string + * + * This function generates and associative array of URI data starting + * at the supplied segment. For example, if this is your URI: + * + * example.com/user/search/name/joe/location/UK/gender/male + * + * You can use this function to generate an array with this prototype: + * + * array ( + * name => joe + * location => UK + * gender => male + * ) + * + * @access public + * @param integer the starting segment number + * @param array an array of default values + * @return array + */ + function uri_to_assoc($n = 3, $default = array()) + { + return $this->_uri_to_assoc($n, $default, 'segment'); + } + /** + * Identical to above only it uses the re-routed segment array + * + * @access public + * @param integer the starting segment number + * @param array an array of default values + * @return array + * + */ + function ruri_to_assoc($n = 3, $default = array()) + { + return $this->_uri_to_assoc($n, $default, 'rsegment'); + } + + // -------------------------------------------------------------------- + + /** + * Generate a key value pair from the URI string or Re-routed URI string + * + * @access private + * @param integer the starting segment number + * @param array an array of default values + * @param string which array we should use + * @return array + */ + function _uri_to_assoc($n = 3, $default = array(), $which = 'segment') + { + if ($which == 'segment') + { + $total_segments = 'total_segments'; + $segment_array = 'segment_array'; + } + else + { + $total_segments = 'total_rsegments'; + $segment_array = 'rsegment_array'; + } + + if ( ! is_numeric($n)) + { + return $default; + } + + if (isset($this->keyval[$n])) + { + return $this->keyval[$n]; + } + + if ($this->$total_segments() < $n) + { + if (count($default) == 0) + { + return array(); + } + + $retval = array(); + foreach ($default as $val) + { + $retval[$val] = FALSE; + } + return $retval; + } + + $segments = array_slice($this->$segment_array(), ($n - 1)); + + $i = 0; + $lastval = ''; + $retval = array(); + foreach ($segments as $seg) + { + if ($i % 2) + { + $retval[$lastval] = $seg; + } + else + { + $retval[$seg] = FALSE; + $lastval = $seg; + } + + $i++; + } + + if (count($default) > 0) + { + foreach ($default as $val) + { + if ( ! array_key_exists($val, $retval)) + { + $retval[$val] = FALSE; + } + } + } + + // Cache the array for reuse + $this->keyval[$n] = $retval; + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Generate a URI string from an associative array + * + * + * @access public + * @param array an associative array of key/values + * @return array + */ + function assoc_to_uri($array) + { + $temp = array(); + foreach ((array)$array as $key => $val) + { + $temp[] = $key; + $temp[] = $val; + } + + return implode('/', $temp); + } + + // -------------------------------------------------------------------- + + /** + * Fetch a URI Segment and add a trailing slash + * + * @access public + * @param integer + * @param string + * @return string + */ + function slash_segment($n, $where = 'trailing') + { + return $this->_slash_segment($n, $where, 'segment'); + } + + // -------------------------------------------------------------------- + + /** + * Fetch a URI Segment and add a trailing slash + * + * @access public + * @param integer + * @param string + * @return string + */ + function slash_rsegment($n, $where = 'trailing') + { + return $this->_slash_segment($n, $where, 'rsegment'); + } + + // -------------------------------------------------------------------- + + /** + * Fetch a URI Segment and add a trailing slash - helper function + * + * @access private + * @param integer + * @param string + * @param string + * @return string + */ + function _slash_segment($n, $where = 'trailing', $which = 'segment') + { + $leading = '/'; + $trailing = '/'; + + if ($where == 'trailing') + { + $leading = ''; + } + elseif ($where == 'leading') + { + $trailing = ''; + } + + return $leading.$this->$which($n).$trailing; + } + + // -------------------------------------------------------------------- + + /** + * Segment Array + * + * @access public + * @return array + */ + function segment_array() + { + return $this->segments; + } + + // -------------------------------------------------------------------- + + /** + * Routed Segment Array + * + * @access public + * @return array + */ + function rsegment_array() + { + return $this->rsegments; + } + + // -------------------------------------------------------------------- + + /** + * Total number of segments + * + * @access public + * @return integer + */ + function total_segments() + { + return count($this->segments); + } + + // -------------------------------------------------------------------- + + /** + * Total number of routed segments + * + * @access public + * @return integer + */ + function total_rsegments() + { + return count($this->rsegments); + } + + // -------------------------------------------------------------------- + + /** + * Fetch the entire URI string + * + * @access public + * @return string + */ + function uri_string() + { + return $this->uri_string; + } + + + // -------------------------------------------------------------------- + + /** + * Fetch the entire Re-routed URI string + * + * @access public + * @return string + */ + function ruri_string() + { + return '/'.implode('/', $this->rsegment_array()); + } + +} +// END URI Class + +/* End of file URI.php */ +/* Location: ./system/core/URI.php */ \ No newline at end of file diff --git a/system/core/Utf8.php b/system/core/Utf8.php new file mode 100644 index 0000000..2a27d1f --- /dev/null +++ b/system/core/Utf8.php @@ -0,0 +1,165 @@ +item('charset') == 'UTF-8' // Application charset must be UTF-8 + ) + { + log_message('debug', "UTF-8 Support Enabled"); + + define('UTF8_ENABLED', TRUE); + + // set internal encoding for multibyte string functions if necessary + // and set a flag so we don't have to repeatedly use extension_loaded() + // or function_exists() + if (extension_loaded('mbstring')) + { + define('MB_ENABLED', TRUE); + mb_internal_encoding('UTF-8'); + } + else + { + define('MB_ENABLED', FALSE); + } + } + else + { + log_message('debug', "UTF-8 Support Disabled"); + define('UTF8_ENABLED', FALSE); + } + } + + // -------------------------------------------------------------------- + + /** + * Clean UTF-8 strings + * + * Ensures strings are UTF-8 + * + * @access public + * @param string + * @return string + */ + function clean_string($str) + { + if ($this->_is_ascii($str) === FALSE) + { + $str = @iconv('UTF-8', 'UTF-8//IGNORE', $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Remove ASCII control characters + * + * Removes all ASCII control characters except horizontal tabs, + * line feeds, and carriage returns, as all others can cause + * problems in XML + * + * @access public + * @param string + * @return string + */ + function safe_ascii_for_xml($str) + { + return remove_invisible_characters($str, FALSE); + } + + // -------------------------------------------------------------------- + + /** + * Convert to UTF-8 + * + * Attempts to convert a string to UTF-8 + * + * @access public + * @param string + * @param string - input encoding + * @return string + */ + function convert_to_utf8($str, $encoding) + { + if (function_exists('iconv')) + { + $str = @iconv($encoding, 'UTF-8', $str); + } + elseif (function_exists('mb_convert_encoding')) + { + $str = @mb_convert_encoding($str, 'UTF-8', $encoding); + } + else + { + return FALSE; + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Is ASCII? + * + * Tests if a string is standard 7-bit ASCII or not + * + * @access public + * @param string + * @return bool + */ + function _is_ascii($str) + { + return (preg_match('/[^\x00-\x7F]/S', $str) == 0); + } + + // -------------------------------------------------------------------- + +} +// End Utf8 Class + +/* End of file Utf8.php */ +/* Location: ./system/core/Utf8.php */ \ No newline at end of file diff --git a/system/core/index.html b/system/core/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/core/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/DB.php b/system/database/DB.php new file mode 100644 index 0000000..8314d3b --- /dev/null +++ b/system/database/DB.php @@ -0,0 +1,162 @@ + $dns['scheme'], + 'hostname' => (isset($dns['host'])) ? rawurldecode($dns['host']) : '', + 'username' => (isset($dns['user'])) ? rawurldecode($dns['user']) : '', + 'password' => (isset($dns['pass'])) ? rawurldecode($dns['pass']) : '', + 'database' => (isset($dns['path'])) ? rawurldecode(substr($dns['path'], 1)) : '' + ); + + // were additional config items set? + if (isset($dns['query'])) + { + parse_str($dns['query'], $extra); + + foreach ($extra as $key => $val) + { + // booleans please + if (strtoupper($val) == "TRUE") + { + $val = TRUE; + } + elseif (strtoupper($val) == "FALSE") + { + $val = FALSE; + } + + $params[$key] = $val; + } + } + } + + // No DB specified yet? Beat them senseless... + if ( ! isset($params['dbdriver']) OR $params['dbdriver'] == '') + { + show_error('You have not selected a database type to connect to.'); + } + + // Load the DB classes. Note: Since the active record class is optional + // we need to dynamically create a class that extends proper parent class + // based on whether we're using the active record class or not. + // Kudos to Paul for discovering this clever use of eval() + + if ($active_record_override !== NULL) + { + $active_record = $active_record_override; + } + + require_once(BASEPATH.'database/DB_driver.php'); + + if ( ! isset($active_record) OR $active_record == TRUE) + { + require_once(BASEPATH.'database/DB_active_rec.php'); + + if ( ! class_exists('CI_DB')) + { + eval('class CI_DB extends CI_DB_active_record { }'); + } + } + else + { + if ( ! class_exists('CI_DB')) + { + eval('class CI_DB extends CI_DB_driver { }'); + } + } + + require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php'); + + // Instantiate the DB adapter + $driver = 'CI_DB_'.$params['dbdriver'].'_driver'; + $DB = new $driver($params); + + if ($DB->autoinit == TRUE) + { + $DB->initialize(); + } + + if (isset($params['stricton']) && $params['stricton'] == TRUE) + { + $DB->query('SET SESSION sql_mode="STRICT_ALL_TABLES"'); + } + + return $DB; +} + + + +/* End of file DB.php */ +/* Location: ./system/database/DB.php */ \ No newline at end of file diff --git a/system/database/DB_active_rec.php b/system/database/DB_active_rec.php new file mode 100644 index 0000000..10febb1 --- /dev/null +++ b/system/database/DB_active_rec.php @@ -0,0 +1,2045 @@ +ar_select[] = $val; + $this->ar_no_escape[] = $escape; + + if ($this->ar_caching === TRUE) + { + $this->ar_cache_select[] = $val; + $this->ar_cache_exists[] = 'select'; + $this->ar_cache_no_escape[] = $escape; + } + } + } + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Select Max + * + * Generates a SELECT MAX(field) portion of a query + * + * @param string the field + * @param string an alias + * @return object + */ + public function select_max($select = '', $alias = '') + { + return $this->_max_min_avg_sum($select, $alias, 'MAX'); + } + + // -------------------------------------------------------------------- + + /** + * Select Min + * + * Generates a SELECT MIN(field) portion of a query + * + * @param string the field + * @param string an alias + * @return object + */ + public function select_min($select = '', $alias = '') + { + return $this->_max_min_avg_sum($select, $alias, 'MIN'); + } + + // -------------------------------------------------------------------- + + /** + * Select Average + * + * Generates a SELECT AVG(field) portion of a query + * + * @param string the field + * @param string an alias + * @return object + */ + public function select_avg($select = '', $alias = '') + { + return $this->_max_min_avg_sum($select, $alias, 'AVG'); + } + + // -------------------------------------------------------------------- + + /** + * Select Sum + * + * Generates a SELECT SUM(field) portion of a query + * + * @param string the field + * @param string an alias + * @return object + */ + public function select_sum($select = '', $alias = '') + { + return $this->_max_min_avg_sum($select, $alias, 'SUM'); + } + + // -------------------------------------------------------------------- + + /** + * Processing Function for the four functions above: + * + * select_max() + * select_min() + * select_avg() + * select_sum() + * + * @param string the field + * @param string an alias + * @return object + */ + protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX') + { + if ( ! is_string($select) OR $select == '') + { + $this->display_error('db_invalid_query'); + } + + $type = strtoupper($type); + + if ( ! in_array($type, array('MAX', 'MIN', 'AVG', 'SUM'))) + { + show_error('Invalid function type: '.$type); + } + + if ($alias == '') + { + $alias = $this->_create_alias_from_table(trim($select)); + } + + $sql = $type.'('.$this->_protect_identifiers(trim($select)).') AS '.$alias; + + $this->ar_select[] = $sql; + + if ($this->ar_caching === TRUE) + { + $this->ar_cache_select[] = $sql; + $this->ar_cache_exists[] = 'select'; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Determines the alias name based on the table + * + * @param string + * @return string + */ + protected function _create_alias_from_table($item) + { + if (strpos($item, '.') !== FALSE) + { + return end(explode('.', $item)); + } + + return $item; + } + + // -------------------------------------------------------------------- + + /** + * DISTINCT + * + * Sets a flag which tells the query string compiler to add DISTINCT + * + * @param bool + * @return object + */ + public function distinct($val = TRUE) + { + $this->ar_distinct = (is_bool($val)) ? $val : TRUE; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * From + * + * Generates the FROM portion of the query + * + * @param mixed can be a string or array + * @return object + */ + public function from($from) + { + foreach ((array) $from as $val) + { + if (strpos($val, ',') !== FALSE) + { + foreach (explode(',', $val) as $v) + { + $v = trim($v); + $this->_track_aliases($v); + + $this->ar_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE); + + if ($this->ar_caching === TRUE) + { + $this->ar_cache_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE); + $this->ar_cache_exists[] = 'from'; + } + } + + } + else + { + $val = trim($val); + + // Extract any aliases that might exist. We use this information + // in the _protect_identifiers to know whether to add a table prefix + $this->_track_aliases($val); + + $this->ar_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE); + + if ($this->ar_caching === TRUE) + { + $this->ar_cache_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE); + $this->ar_cache_exists[] = 'from'; + } + } + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Join + * + * Generates the JOIN portion of the query + * + * @param string + * @param string the join condition + * @param string the type of join + * @return object + */ + public function join($table, $cond, $type = '') + { + if ($type != '') + { + $type = strtoupper(trim($type)); + + if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'))) + { + $type = ''; + } + else + { + $type .= ' '; + } + } + + // Extract any aliases that might exist. We use this information + // in the _protect_identifiers to know whether to add a table prefix + $this->_track_aliases($table); + + // Strip apart the condition and protect the identifiers + if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match)) + { + $match[1] = $this->_protect_identifiers($match[1]); + $match[3] = $this->_protect_identifiers($match[3]); + + $cond = $match[1].$match[2].$match[3]; + } + + // Assemble the JOIN statement + $join = $type.'JOIN '.$this->_protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond; + + $this->ar_join[] = $join; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_join[] = $join; + $this->ar_cache_exists[] = 'join'; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Where + * + * Generates the WHERE portion of the query. Separates + * multiple calls with AND + * + * @param mixed + * @param mixed + * @return object + */ + public function where($key, $value = NULL, $escape = TRUE) + { + return $this->_where($key, $value, 'AND ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * OR Where + * + * Generates the WHERE portion of the query. Separates + * multiple calls with OR + * + * @param mixed + * @param mixed + * @return object + */ + public function or_where($key, $value = NULL, $escape = TRUE) + { + return $this->_where($key, $value, 'OR ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * Where + * + * Called by where() or or_where() + * + * @param mixed + * @param mixed + * @param string + * @return object + */ + protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL) + { + if ( ! is_array($key)) + { + $key = array($key => $value); + } + + // If the escape value was not set will will base it on the global setting + if ( ! is_bool($escape)) + { + $escape = $this->_protect_identifiers; + } + + foreach ($key as $k => $v) + { + $prefix = (count($this->ar_where) == 0 AND count($this->ar_cache_where) == 0) ? '' : $type; + + if (is_null($v) && ! $this->_has_operator($k)) + { + // value appears not to have been set, assign the test to IS NULL + $k .= ' IS NULL'; + } + + if ( ! is_null($v)) + { + if ($escape === TRUE) + { + $k = $this->_protect_identifiers($k, FALSE, $escape); + + $v = ' '.$this->escape($v); + } + + if ( ! $this->_has_operator($k)) + { + $k .= ' = '; + } + } + else + { + $k = $this->_protect_identifiers($k, FALSE, $escape); + } + + $this->ar_where[] = $prefix.$k.$v; + + if ($this->ar_caching === TRUE) + { + $this->ar_cache_where[] = $prefix.$k.$v; + $this->ar_cache_exists[] = 'where'; + } + + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Where_in + * + * Generates a WHERE field IN ('item', 'item') SQL query joined with + * AND if appropriate + * + * @param string The field to search + * @param array The values searched on + * @return object + */ + public function where_in($key = NULL, $values = NULL) + { + return $this->_where_in($key, $values); + } + + // -------------------------------------------------------------------- + + /** + * Where_in_or + * + * Generates a WHERE field IN ('item', 'item') SQL query joined with + * OR if appropriate + * + * @param string The field to search + * @param array The values searched on + * @return object + */ + public function or_where_in($key = NULL, $values = NULL) + { + return $this->_where_in($key, $values, FALSE, 'OR '); + } + + // -------------------------------------------------------------------- + + /** + * Where_not_in + * + * Generates a WHERE field NOT IN ('item', 'item') SQL query joined + * with AND if appropriate + * + * @param string The field to search + * @param array The values searched on + * @return object + */ + public function where_not_in($key = NULL, $values = NULL) + { + return $this->_where_in($key, $values, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Where_not_in_or + * + * Generates a WHERE field NOT IN ('item', 'item') SQL query joined + * with OR if appropriate + * + * @param string The field to search + * @param array The values searched on + * @return object + */ + public function or_where_not_in($key = NULL, $values = NULL) + { + return $this->_where_in($key, $values, TRUE, 'OR '); + } + + // -------------------------------------------------------------------- + + /** + * Where_in + * + * Called by where_in, where_in_or, where_not_in, where_not_in_or + * + * @param string The field to search + * @param array The values searched on + * @param boolean If the statement would be IN or NOT IN + * @param string + * @return object + */ + protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ') + { + if ($key === NULL OR $values === NULL) + { + return; + } + + if ( ! is_array($values)) + { + $values = array($values); + } + + $not = ($not) ? ' NOT' : ''; + + foreach ($values as $value) + { + $this->ar_wherein[] = $this->escape($value); + } + + $prefix = (count($this->ar_where) == 0) ? '' : $type; + + $where_in = $prefix . $this->_protect_identifiers($key) . $not . " IN (" . implode(", ", $this->ar_wherein) . ") "; + + $this->ar_where[] = $where_in; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_where[] = $where_in; + $this->ar_cache_exists[] = 'where'; + } + + // reset the array for multiple calls + $this->ar_wherein = array(); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Like + * + * Generates a %LIKE% portion of the query. Separates + * multiple calls with AND + * + * @param mixed + * @param mixed + * @return object + */ + public function like($field, $match = '', $side = 'both') + { + return $this->_like($field, $match, 'AND ', $side); + } + + // -------------------------------------------------------------------- + + /** + * Not Like + * + * Generates a NOT LIKE portion of the query. Separates + * multiple calls with AND + * + * @param mixed + * @param mixed + * @return object + */ + public function not_like($field, $match = '', $side = 'both') + { + return $this->_like($field, $match, 'AND ', $side, 'NOT'); + } + + // -------------------------------------------------------------------- + + /** + * OR Like + * + * Generates a %LIKE% portion of the query. Separates + * multiple calls with OR + * + * @param mixed + * @param mixed + * @return object + */ + public function or_like($field, $match = '', $side = 'both') + { + return $this->_like($field, $match, 'OR ', $side); + } + + // -------------------------------------------------------------------- + + /** + * OR Not Like + * + * Generates a NOT LIKE portion of the query. Separates + * multiple calls with OR + * + * @param mixed + * @param mixed + * @return object + */ + public function or_not_like($field, $match = '', $side = 'both') + { + return $this->_like($field, $match, 'OR ', $side, 'NOT'); + } + + // -------------------------------------------------------------------- + + /** + * Like + * + * Called by like() or orlike() + * + * @param mixed + * @param mixed + * @param string + * @return object + */ + protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '') + { + if ( ! is_array($field)) + { + $field = array($field => $match); + } + + foreach ($field as $k => $v) + { + $k = $this->_protect_identifiers($k); + + $prefix = (count($this->ar_like) == 0) ? '' : $type; + + $v = $this->escape_like_str($v); + + if ($side == 'none') + { + $like_statement = $prefix." $k $not LIKE '{$v}'"; + } + elseif ($side == 'before') + { + $like_statement = $prefix." $k $not LIKE '%{$v}'"; + } + elseif ($side == 'after') + { + $like_statement = $prefix." $k $not LIKE '{$v}%'"; + } + else + { + $like_statement = $prefix." $k $not LIKE '%{$v}%'"; + } + + // some platforms require an escape sequence definition for LIKE wildcards + if ($this->_like_escape_str != '') + { + $like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_chr); + } + + $this->ar_like[] = $like_statement; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_like[] = $like_statement; + $this->ar_cache_exists[] = 'like'; + } + + } + return $this; + } + + // -------------------------------------------------------------------- + + /** + * GROUP BY + * + * @param string + * @return object + */ + public function group_by($by) + { + if (is_string($by)) + { + $by = explode(',', $by); + } + + foreach ($by as $val) + { + $val = trim($val); + + if ($val != '') + { + $this->ar_groupby[] = $this->_protect_identifiers($val); + + if ($this->ar_caching === TRUE) + { + $this->ar_cache_groupby[] = $this->_protect_identifiers($val); + $this->ar_cache_exists[] = 'groupby'; + } + } + } + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Sets the HAVING value + * + * Separates multiple calls with AND + * + * @param string + * @param string + * @return object + */ + public function having($key, $value = '', $escape = TRUE) + { + return $this->_having($key, $value, 'AND ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * Sets the OR HAVING value + * + * Separates multiple calls with OR + * + * @param string + * @param string + * @return object + */ + public function or_having($key, $value = '', $escape = TRUE) + { + return $this->_having($key, $value, 'OR ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * Sets the HAVING values + * + * Called by having() or or_having() + * + * @param string + * @param string + * @return object + */ + protected function _having($key, $value = '', $type = 'AND ', $escape = TRUE) + { + if ( ! is_array($key)) + { + $key = array($key => $value); + } + + foreach ($key as $k => $v) + { + $prefix = (count($this->ar_having) == 0) ? '' : $type; + + if ($escape === TRUE) + { + $k = $this->_protect_identifiers($k); + } + + if ( ! $this->_has_operator($k)) + { + $k .= ' = '; + } + + if ($v != '') + { + $v = ' '.$this->escape($v); + } + + $this->ar_having[] = $prefix.$k.$v; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_having[] = $prefix.$k.$v; + $this->ar_cache_exists[] = 'having'; + } + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Sets the ORDER BY value + * + * @param string + * @param string direction: asc or desc + * @return object + */ + public function order_by($orderby, $direction = '') + { + if (strtolower($direction) == 'random') + { + $orderby = ''; // Random results want or don't need a field name + $direction = $this->_random_keyword; + } + elseif (trim($direction) != '') + { + $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC'; + } + + + if (strpos($orderby, ',') !== FALSE) + { + $temp = array(); + foreach (explode(',', $orderby) as $part) + { + $part = trim($part); + if ( ! in_array($part, $this->ar_aliased_tables)) + { + $part = $this->_protect_identifiers(trim($part)); + } + + $temp[] = $part; + } + + $orderby = implode(', ', $temp); + } + else if ($direction != $this->_random_keyword) + { + $orderby = $this->_protect_identifiers($orderby); + } + + $orderby_statement = $orderby.$direction; + + $this->ar_orderby[] = $orderby_statement; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_orderby[] = $orderby_statement; + $this->ar_cache_exists[] = 'orderby'; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Sets the LIMIT value + * + * @param integer the limit value + * @param integer the offset value + * @return object + */ + public function limit($value, $offset = '') + { + $this->ar_limit = (int) $value; + + if ($offset != '') + { + $this->ar_offset = (int) $offset; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Sets the OFFSET value + * + * @param integer the offset value + * @return object + */ + public function offset($offset) + { + $this->ar_offset = $offset; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * The "set" function. Allows key/value pairs to be set for inserting or updating + * + * @param mixed + * @param string + * @param boolean + * @return object + */ + public function set($key, $value = '', $escape = TRUE) + { + $key = $this->_object_to_array($key); + + if ( ! is_array($key)) + { + $key = array($key => $value); + } + + foreach ($key as $k => $v) + { + if ($escape === FALSE) + { + $this->ar_set[$this->_protect_identifiers($k)] = $v; + } + else + { + $this->ar_set[$this->_protect_identifiers($k, FALSE, TRUE)] = $this->escape($v); + } + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Get + * + * Compiles the select statement based on the other functions called + * and runs the query + * + * @param string the table + * @param string the limit clause + * @param string the offset clause + * @return object + */ + public function get($table = '', $limit = null, $offset = null) + { + if ($table != '') + { + $this->_track_aliases($table); + $this->from($table); + } + + if ( ! is_null($limit)) + { + $this->limit($limit, $offset); + } + + $sql = $this->_compile_select(); + + $result = $this->query($sql); + $this->_reset_select(); + return $result; + } + + /** + * "Count All Results" query + * + * Generates a platform-specific query string that counts all records + * returned by an Active Record query. + * + * @param string + * @return string + */ + public function count_all_results($table = '') + { + if ($table != '') + { + $this->_track_aliases($table); + $this->from($table); + } + + $sql = $this->_compile_select($this->_count_string . $this->_protect_identifiers('numrows')); + + $query = $this->query($sql); + $this->_reset_select(); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * Get_Where + * + * Allows the where clause, limit and offset to be added directly + * + * @param string the where clause + * @param string the limit clause + * @param string the offset clause + * @return object + */ + public function get_where($table = '', $where = null, $limit = null, $offset = null) + { + if ($table != '') + { + $this->from($table); + } + + if ( ! is_null($where)) + { + $this->where($where); + } + + if ( ! is_null($limit)) + { + $this->limit($limit, $offset); + } + + $sql = $this->_compile_select(); + + $result = $this->query($sql); + $this->_reset_select(); + return $result; + } + + // -------------------------------------------------------------------- + + /** + * Insert_Batch + * + * Compiles batch insert strings and runs the queries + * + * @param string the table to retrieve the results from + * @param array an associative array of insert values + * @return object + */ + public function insert_batch($table = '', $set = NULL) + { + if ( ! is_null($set)) + { + $this->set_insert_batch($set); + } + + if (count($this->ar_set) == 0) + { + if ($this->db_debug) + { + //No valid data array. Folds in cases where keys and values did not match up + return $this->display_error('db_must_use_set'); + } + return FALSE; + } + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + + // Batch this baby + for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100) + { + + $sql = $this->_insert_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100)); + + //echo $sql; + + $this->query($sql); + } + + $this->_reset_write(); + + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * The "set_insert_batch" function. Allows key/value pairs to be set for batch inserts + * + * @param mixed + * @param string + * @param boolean + * @return object + */ + public function set_insert_batch($key, $value = '', $escape = TRUE) + { + $key = $this->_object_to_array_batch($key); + + if ( ! is_array($key)) + { + $key = array($key => $value); + } + + $keys = array_keys(current($key)); + sort($keys); + + foreach ($key as $row) + { + if (count(array_diff($keys, array_keys($row))) > 0 OR count(array_diff(array_keys($row), $keys)) > 0) + { + // batch function above returns an error on an empty array + $this->ar_set[] = array(); + return; + } + + ksort($row); // puts $row in the same order as our keys + + if ($escape === FALSE) + { + $this->ar_set[] = '('.implode(',', $row).')'; + } + else + { + $clean = array(); + + foreach ($row as $value) + { + $clean[] = $this->escape($value); + } + + $this->ar_set[] = '('.implode(',', $clean).')'; + } + } + + foreach ($keys as $k) + { + $this->ar_keys[] = $this->_protect_identifiers($k); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Insert + * + * Compiles an insert string and runs the query + * + * @param string the table to insert data into + * @param array an associative array of insert values + * @return object + */ + function insert($table = '', $set = NULL) + { + if ( ! is_null($set)) + { + $this->set($set); + } + + if (count($this->ar_set) == 0) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_set'); + } + return FALSE; + } + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + + $sql = $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set)); + + $this->_reset_write(); + return $this->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Replace + * + * Compiles an replace into string and runs the query + * + * @param string the table to replace data into + * @param array an associative array of insert values + * @return object + */ + public function replace($table = '', $set = NULL) + { + if ( ! is_null($set)) + { + $this->set($set); + } + + if (count($this->ar_set) == 0) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_set'); + } + return FALSE; + } + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + + $sql = $this->_replace($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set)); + + $this->_reset_write(); + return $this->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Update + * + * Compiles an update string and runs the query + * + * @param string the table to retrieve the results from + * @param array an associative array of update values + * @param mixed the where clause + * @return object + */ + public function update($table = '', $set = NULL, $where = NULL, $limit = NULL) + { + // Combine any cached components with the current statements + $this->_merge_cache(); + + if ( ! is_null($set)) + { + $this->set($set); + } + + if (count($this->ar_set) == 0) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_set'); + } + return FALSE; + } + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + + if ($where != NULL) + { + $this->where($where); + } + + if ($limit != NULL) + { + $this->limit($limit); + } + + $sql = $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit); + + $this->_reset_write(); + return $this->query($sql); + } + + + // -------------------------------------------------------------------- + + /** + * Update_Batch + * + * Compiles an update string and runs the query + * + * @param string the table to retrieve the results from + * @param array an associative array of update values + * @param string the where key + * @return object + */ + public function update_batch($table = '', $set = NULL, $index = NULL) + { + // Combine any cached components with the current statements + $this->_merge_cache(); + + if (is_null($index)) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_index'); + } + + return FALSE; + } + + if ( ! is_null($set)) + { + $this->set_update_batch($set, $index); + } + + if (count($this->ar_set) == 0) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_set'); + } + + return FALSE; + } + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + + // Batch this baby + for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100) + { + $sql = $this->_update_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->ar_set, $i, 100), $this->_protect_identifiers($index), $this->ar_where); + + $this->query($sql); + } + + $this->_reset_write(); + } + + // -------------------------------------------------------------------- + + /** + * The "set_update_batch" function. Allows key/value pairs to be set for batch updating + * + * @param array + * @param string + * @param boolean + * @return object + */ + public function set_update_batch($key, $index = '', $escape = TRUE) + { + $key = $this->_object_to_array_batch($key); + + if ( ! is_array($key)) + { + // @todo error + } + + foreach ($key as $k => $v) + { + $index_set = FALSE; + $clean = array(); + + foreach ($v as $k2 => $v2) + { + if ($k2 == $index) + { + $index_set = TRUE; + } + else + { + $not[] = $k.'-'.$v; + } + + if ($escape === FALSE) + { + $clean[$this->_protect_identifiers($k2)] = $v2; + } + else + { + $clean[$this->_protect_identifiers($k2)] = $this->escape($v2); + } + } + + if ($index_set == FALSE) + { + return $this->display_error('db_batch_missing_index'); + } + + $this->ar_set[] = $clean; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Empty Table + * + * Compiles a delete string and runs "DELETE FROM table" + * + * @param string the table to empty + * @return object + */ + public function empty_table($table = '') + { + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + else + { + $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE); + } + + $sql = $this->_delete($table); + + $this->_reset_write(); + + return $this->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Truncate + * + * Compiles a truncate string and runs the query + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @param string the table to truncate + * @return object + */ + public function truncate($table = '') + { + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + else + { + $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE); + } + + $sql = $this->_truncate($table); + + $this->_reset_write(); + + return $this->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Delete + * + * Compiles a delete string and runs the query + * + * @param mixed the table(s) to delete from. String or array + * @param mixed the where clause + * @param mixed the limit clause + * @param boolean + * @return object + */ + public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) + { + // Combine any cached components with the current statements + $this->_merge_cache(); + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + elseif (is_array($table)) + { + foreach ($table as $single_table) + { + $this->delete($single_table, $where, $limit, FALSE); + } + + $this->_reset_write(); + return; + } + else + { + $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE); + } + + if ($where != '') + { + $this->where($where); + } + + if ($limit != NULL) + { + $this->limit($limit); + } + + if (count($this->ar_where) == 0 && count($this->ar_wherein) == 0 && count($this->ar_like) == 0) + { + if ($this->db_debug) + { + return $this->display_error('db_del_must_use_where'); + } + + return FALSE; + } + + $sql = $this->_delete($table, $this->ar_where, $this->ar_like, $this->ar_limit); + + if ($reset_data) + { + $this->_reset_write(); + } + + return $this->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * DB Prefix + * + * Prepends a database prefix if one exists in configuration + * + * @param string the table + * @return string + */ + public function dbprefix($table = '') + { + if ($table == '') + { + $this->display_error('db_table_name_required'); + } + + return $this->dbprefix.$table; + } + + // -------------------------------------------------------------------- + + /** + * Set DB Prefix + * + * Set's the DB Prefix to something new without needing to reconnect + * + * @param string the prefix + * @return string + */ + public function set_dbprefix($prefix = '') + { + return $this->dbprefix = $prefix; + } + + // -------------------------------------------------------------------- + + /** + * Track Aliases + * + * Used to track SQL statements written with aliased tables. + * + * @param string The table to inspect + * @return string + */ + protected function _track_aliases($table) + { + if (is_array($table)) + { + foreach ($table as $t) + { + $this->_track_aliases($t); + } + return; + } + + // Does the string contain a comma? If so, we need to separate + // the string into discreet statements + if (strpos($table, ',') !== FALSE) + { + return $this->_track_aliases(explode(',', $table)); + } + + // if a table alias is used we can recognize it by a space + if (strpos($table, " ") !== FALSE) + { + // if the alias is written with the AS keyword, remove it + $table = preg_replace('/\s+AS\s+/i', ' ', $table); + + // Grab the alias + $table = trim(strrchr($table, " ")); + + // Store the alias, if it doesn't already exist + if ( ! in_array($table, $this->ar_aliased_tables)) + { + $this->ar_aliased_tables[] = $table; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Compile the SELECT statement + * + * Generates a query string based on which functions were used. + * Should not be called directly. The get() function calls it. + * + * @return string + */ + protected function _compile_select($select_override = FALSE) + { + // Combine any cached components with the current statements + $this->_merge_cache(); + + // ---------------------------------------------------------------- + + // Write the "select" portion of the query + + if ($select_override !== FALSE) + { + $sql = $select_override; + } + else + { + $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT '; + + if (count($this->ar_select) == 0) + { + $sql .= '*'; + } + else + { + // Cycle through the "select" portion of the query and prep each column name. + // The reason we protect identifiers here rather then in the select() function + // is because until the user calls the from() function we don't know if there are aliases + foreach ($this->ar_select as $key => $val) + { + $no_escape = isset($this->ar_no_escape[$key]) ? $this->ar_no_escape[$key] : NULL; + $this->ar_select[$key] = $this->_protect_identifiers($val, FALSE, $no_escape); + } + + $sql .= implode(', ', $this->ar_select); + } + } + + // ---------------------------------------------------------------- + + // Write the "FROM" portion of the query + + if (count($this->ar_from) > 0) + { + $sql .= "\nFROM "; + + $sql .= $this->_from_tables($this->ar_from); + } + + // ---------------------------------------------------------------- + + // Write the "JOIN" portion of the query + + if (count($this->ar_join) > 0) + { + $sql .= "\n"; + + $sql .= implode("\n", $this->ar_join); + } + + // ---------------------------------------------------------------- + + // Write the "WHERE" portion of the query + + if (count($this->ar_where) > 0 OR count($this->ar_like) > 0) + { + $sql .= "\nWHERE "; + } + + $sql .= implode("\n", $this->ar_where); + + // ---------------------------------------------------------------- + + // Write the "LIKE" portion of the query + + if (count($this->ar_like) > 0) + { + if (count($this->ar_where) > 0) + { + $sql .= "\nAND "; + } + + $sql .= implode("\n", $this->ar_like); + } + + // ---------------------------------------------------------------- + + // Write the "GROUP BY" portion of the query + + if (count($this->ar_groupby) > 0) + { + $sql .= "\nGROUP BY "; + + $sql .= implode(', ', $this->ar_groupby); + } + + // ---------------------------------------------------------------- + + // Write the "HAVING" portion of the query + + if (count($this->ar_having) > 0) + { + $sql .= "\nHAVING "; + $sql .= implode("\n", $this->ar_having); + } + + // ---------------------------------------------------------------- + + // Write the "ORDER BY" portion of the query + + if (count($this->ar_orderby) > 0) + { + $sql .= "\nORDER BY "; + $sql .= implode(', ', $this->ar_orderby); + + if ($this->ar_order !== FALSE) + { + $sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC'; + } + } + + // ---------------------------------------------------------------- + + // Write the "LIMIT" portion of the query + + if (is_numeric($this->ar_limit)) + { + $sql .= "\n"; + $sql = $this->_limit($sql, $this->ar_limit, $this->ar_offset); + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Object to Array + * + * Takes an object as input and converts the class variables to array key/vals + * + * @param object + * @return array + */ + public function _object_to_array($object) + { + if ( ! is_object($object)) + { + return $object; + } + + $array = array(); + foreach (get_object_vars($object) as $key => $val) + { + // There are some built in keys we need to ignore for this conversion + if ( ! is_object($val) && ! is_array($val) && $key != '_parent_name') + { + $array[$key] = $val; + } + } + + return $array; + } + + // -------------------------------------------------------------------- + + /** + * Object to Array + * + * Takes an object as input and converts the class variables to array key/vals + * + * @param object + * @return array + */ + public function _object_to_array_batch($object) + { + if ( ! is_object($object)) + { + return $object; + } + + $array = array(); + $out = get_object_vars($object); + $fields = array_keys($out); + + foreach ($fields as $val) + { + // There are some built in keys we need to ignore for this conversion + if ($val != '_parent_name') + { + + $i = 0; + foreach ($out[$val] as $data) + { + $array[$i][$val] = $data; + $i++; + } + } + } + + return $array; + } + + // -------------------------------------------------------------------- + + /** + * Start Cache + * + * Starts AR caching + * + * @return void + */ + public function start_cache() + { + $this->ar_caching = TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Stop Cache + * + * Stops AR caching + * + * @return void + */ + public function stop_cache() + { + $this->ar_caching = FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Flush Cache + * + * Empties the AR cache + * + * @access public + * @return void + */ + public function flush_cache() + { + $this->_reset_run(array( + 'ar_cache_select' => array(), + 'ar_cache_from' => array(), + 'ar_cache_join' => array(), + 'ar_cache_where' => array(), + 'ar_cache_like' => array(), + 'ar_cache_groupby' => array(), + 'ar_cache_having' => array(), + 'ar_cache_orderby' => array(), + 'ar_cache_set' => array(), + 'ar_cache_exists' => array(), + 'ar_cache_no_escape' => array() + )); + } + + // -------------------------------------------------------------------- + + /** + * Merge Cache + * + * When called, this function merges any cached AR arrays with + * locally called ones. + * + * @return void + */ + protected function _merge_cache() + { + if (count($this->ar_cache_exists) == 0) + { + return; + } + + foreach ($this->ar_cache_exists as $val) + { + $ar_variable = 'ar_'.$val; + $ar_cache_var = 'ar_cache_'.$val; + + if (count($this->$ar_cache_var) == 0) + { + continue; + } + + $this->$ar_variable = array_unique(array_merge($this->$ar_cache_var, $this->$ar_variable)); + } + + // If we are "protecting identifiers" we need to examine the "from" + // portion of the query to determine if there are any aliases + if ($this->_protect_identifiers === TRUE AND count($this->ar_cache_from) > 0) + { + $this->_track_aliases($this->ar_from); + } + + $this->ar_no_escape = $this->ar_cache_no_escape; + } + + // -------------------------------------------------------------------- + + /** + * Resets the active record values. Called by the get() function + * + * @param array An array of fields to reset + * @return void + */ + protected function _reset_run($ar_reset_items) + { + foreach ($ar_reset_items as $item => $default_value) + { + if ( ! in_array($item, $this->ar_store_array)) + { + $this->$item = $default_value; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Resets the active record values. Called by the get() function + * + * @return void + */ + protected function _reset_select() + { + $ar_reset_items = array( + 'ar_select' => array(), + 'ar_from' => array(), + 'ar_join' => array(), + 'ar_where' => array(), + 'ar_like' => array(), + 'ar_groupby' => array(), + 'ar_having' => array(), + 'ar_orderby' => array(), + 'ar_wherein' => array(), + 'ar_aliased_tables' => array(), + 'ar_no_escape' => array(), + 'ar_distinct' => FALSE, + 'ar_limit' => FALSE, + 'ar_offset' => FALSE, + 'ar_order' => FALSE, + ); + + $this->_reset_run($ar_reset_items); + } + + // -------------------------------------------------------------------- + + /** + * Resets the active record "write" values. + * + * Called by the insert() update() insert_batch() update_batch() and delete() functions + * + * @return void + */ + protected function _reset_write() + { + $ar_reset_items = array( + 'ar_set' => array(), + 'ar_from' => array(), + 'ar_where' => array(), + 'ar_like' => array(), + 'ar_orderby' => array(), + 'ar_keys' => array(), + 'ar_limit' => FALSE, + 'ar_order' => FALSE + ); + + $this->_reset_run($ar_reset_items); + } +} + +/* End of file DB_active_rec.php */ +/* Location: ./system/database/DB_active_rec.php */ \ No newline at end of file diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php new file mode 100644 index 0000000..ad1c28d --- /dev/null +++ b/system/database/DB_cache.php @@ -0,0 +1,195 @@ +CI + // and load the file helper since we use it a lot + $this->CI =& get_instance(); + $this->db =& $db; + $this->CI->load->helper('file'); + } + + // -------------------------------------------------------------------- + + /** + * Set Cache Directory Path + * + * @access public + * @param string the path to the cache directory + * @return bool + */ + function check_path($path = '') + { + if ($path == '') + { + if ($this->db->cachedir == '') + { + return $this->db->cache_off(); + } + + $path = $this->db->cachedir; + } + + // Add a trailing slash to the path if needed + $path = preg_replace("/(.+?)\/*$/", "\\1/", $path); + + if ( ! is_dir($path) OR ! is_really_writable($path)) + { + // If the path is wrong we'll turn off caching + return $this->db->cache_off(); + } + + $this->db->cachedir = $path; + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Retrieve a cached query + * + * The URI being requested will become the name of the cache sub-folder. + * An MD5 hash of the SQL statement will become the cache file name + * + * @access public + * @return string + */ + function read($sql) + { + if ( ! $this->check_path()) + { + return $this->db->cache_off(); + } + + $segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1); + + $segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2); + + $filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql); + + if (FALSE === ($cachedata = read_file($filepath))) + { + return FALSE; + } + + return unserialize($cachedata); + } + + // -------------------------------------------------------------------- + + /** + * Write a query to a cache file + * + * @access public + * @return bool + */ + function write($sql, $object) + { + if ( ! $this->check_path()) + { + return $this->db->cache_off(); + } + + $segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1); + + $segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2); + + $dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'; + + $filename = md5($sql); + + if ( ! @is_dir($dir_path)) + { + if ( ! @mkdir($dir_path, DIR_WRITE_MODE)) + { + return FALSE; + } + + @chmod($dir_path, DIR_WRITE_MODE); + } + + if (write_file($dir_path.$filename, serialize($object)) === FALSE) + { + return FALSE; + } + + @chmod($dir_path.$filename, FILE_WRITE_MODE); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Delete cache files within a particular directory + * + * @access public + * @return bool + */ + function delete($segment_one = '', $segment_two = '') + { + if ($segment_one == '') + { + $segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1); + } + + if ($segment_two == '') + { + $segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2); + } + + $dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'; + + delete_files($dir_path, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Delete all existing cache files + * + * @access public + * @return bool + */ + function delete_all() + { + delete_files($this->db->cachedir, TRUE); + } + +} + + +/* End of file DB_cache.php */ +/* Location: ./system/database/DB_cache.php */ \ No newline at end of file diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php new file mode 100644 index 0000000..775fd33 --- /dev/null +++ b/system/database/DB_driver.php @@ -0,0 +1,1410 @@ + $val) + { + $this->$key = $val; + } + } + + log_message('debug', 'Database Driver Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Initialize Database Settings + * + * @access private Called by the constructor + * @param mixed + * @return void + */ + function initialize() + { + // If an existing connection resource is available + // there is no need to connect and select the database + if (is_resource($this->conn_id) OR is_object($this->conn_id)) + { + return TRUE; + } + + // ---------------------------------------------------------------- + + // Connect to the database and set the connection ID + $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect(); + + // No connection resource? Throw an error + if ( ! $this->conn_id) + { + log_message('error', 'Unable to connect to the database'); + + if ($this->db_debug) + { + $this->display_error('db_unable_to_connect'); + } + return FALSE; + } + + // ---------------------------------------------------------------- + + // Select the DB... assuming a database name is specified in the config file + if ($this->database != '') + { + if ( ! $this->db_select()) + { + log_message('error', 'Unable to select database: '.$this->database); + + if ($this->db_debug) + { + $this->display_error('db_unable_to_select', $this->database); + } + return FALSE; + } + else + { + // We've selected the DB. Now we set the character set + if ( ! $this->db_set_charset($this->char_set, $this->dbcollat)) + { + return FALSE; + } + + return TRUE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + if ( ! $this->_db_set_charset($this->char_set, $this->dbcollat)) + { + log_message('error', 'Unable to set database connection charset: '.$this->char_set); + + if ($this->db_debug) + { + $this->display_error('db_unable_to_set_charset', $this->char_set); + } + + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * The name of the platform in use (mysql, mssql, etc...) + * + * @access public + * @return string + */ + function platform() + { + return $this->dbdriver; + } + + // -------------------------------------------------------------------- + + /** + * Database Version Number. Returns a string containing the + * version of the database being used + * + * @access public + * @return string + */ + function version() + { + if (FALSE === ($sql = $this->_version())) + { + if ($this->db_debug) + { + return $this->display_error('db_unsupported_function'); + } + return FALSE; + } + + // Some DBs have functions that return the version, and don't run special + // SQL queries per se. In these instances, just return the result. + $driver_version_exceptions = array('oci8', 'sqlite', 'cubrid'); + + if (in_array($this->dbdriver, $driver_version_exceptions)) + { + return $sql; + } + else + { + $query = $this->query($sql); + return $query->row('ver'); + } + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * Accepts an SQL string as input and returns a result object upon + * successful execution of a "read" type query. Returns boolean TRUE + * upon successful execution of a "write" type query. Returns boolean + * FALSE upon failure, and if the $db_debug variable is set to TRUE + * will raise an error. + * + * @access public + * @param string An SQL query string + * @param array An array of binding data + * @return mixed + */ + function query($sql, $binds = FALSE, $return_object = TRUE) + { + if ($sql == '') + { + if ($this->db_debug) + { + log_message('error', 'Invalid query: '.$sql); + return $this->display_error('db_invalid_query'); + } + return FALSE; + } + + // Verify table prefix and replace if necessary + if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) ) + { + $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql); + } + + // Compile binds if needed + if ($binds !== FALSE) + { + $sql = $this->compile_binds($sql, $binds); + } + + // Is query caching enabled? If the query is a "read type" + // we will load the caching class and return the previously + // cached query if it exists + if ($this->cache_on == TRUE AND stristr($sql, 'SELECT')) + { + if ($this->_cache_init()) + { + $this->load_rdriver(); + if (FALSE !== ($cache = $this->CACHE->read($sql))) + { + return $cache; + } + } + } + + // Save the query for debugging + if ($this->save_queries == TRUE) + { + $this->queries[] = $sql; + } + + // Start the Query Timer + $time_start = list($sm, $ss) = explode(' ', microtime()); + + // Run the Query + if (FALSE === ($this->result_id = $this->simple_query($sql))) + { + if ($this->save_queries == TRUE) + { + $this->query_times[] = 0; + } + + // This will trigger a rollback if transactions are being used + $this->_trans_status = FALSE; + + if ($this->db_debug) + { + // grab the error number and message now, as we might run some + // additional queries before displaying the error + $error_no = $this->_error_number(); + $error_msg = $this->_error_message(); + + // We call this function in order to roll-back queries + // if transactions are enabled. If we don't call this here + // the error message will trigger an exit, causing the + // transactions to remain in limbo. + $this->trans_complete(); + + // Log and display errors + log_message('error', 'Query error: '.$error_msg); + return $this->display_error( + array( + 'Error Number: '.$error_no, + $error_msg, + $sql + ) + ); + } + + return FALSE; + } + + // Stop and aggregate the query time results + $time_end = list($em, $es) = explode(' ', microtime()); + $this->benchmark += ($em + $es) - ($sm + $ss); + + if ($this->save_queries == TRUE) + { + $this->query_times[] = ($em + $es) - ($sm + $ss); + } + + // Increment the query counter + $this->query_count++; + + // Was the query a "write" type? + // If so we'll simply return true + if ($this->is_write_type($sql) === TRUE) + { + // If caching is enabled we'll auto-cleanup any + // existing files related to this particular URI + if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init()) + { + $this->CACHE->delete(); + } + + return TRUE; + } + + // Return TRUE if we don't need to create a result object + // Currently only the Oracle driver uses this when stored + // procedures are used + if ($return_object !== TRUE) + { + return TRUE; + } + + // Load and instantiate the result driver + + $driver = $this->load_rdriver(); + $RES = new $driver(); + $RES->conn_id = $this->conn_id; + $RES->result_id = $this->result_id; + + if ($this->dbdriver == 'oci8') + { + $RES->stmt_id = $this->stmt_id; + $RES->curs_id = NULL; + $RES->limit_used = $this->limit_used; + $this->stmt_id = FALSE; + } + + // oci8 vars must be set before calling this + $RES->num_rows = $RES->num_rows(); + + // Is query caching enabled? If so, we'll serialize the + // result object and save it to a cache file. + if ($this->cache_on == TRUE AND $this->_cache_init()) + { + // We'll create a new instance of the result object + // only without the platform specific driver since + // we can't use it with cached data (the query result + // resource ID won't be any good once we've cached the + // result object, so we'll have to compile the data + // and save it) + $CR = new CI_DB_result(); + $CR->num_rows = $RES->num_rows(); + $CR->result_object = $RES->result_object(); + $CR->result_array = $RES->result_array(); + + // Reset these since cached objects can not utilize resource IDs. + $CR->conn_id = NULL; + $CR->result_id = NULL; + + $this->CACHE->write($sql, $CR); + } + + return $RES; + } + + // -------------------------------------------------------------------- + + /** + * Load the result drivers + * + * @access public + * @return string the name of the result class + */ + function load_rdriver() + { + $driver = 'CI_DB_'.$this->dbdriver.'_result'; + + if ( ! class_exists($driver)) + { + include_once(BASEPATH.'database/DB_result.php'); + include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php'); + } + + return $driver; + } + + // -------------------------------------------------------------------- + + /** + * Simple Query + * This is a simplified version of the query() function. Internally + * we only use it when running transaction commands since they do + * not require all the features of the main query() function. + * + * @access public + * @param string the sql query + * @return mixed + */ + function simple_query($sql) + { + if ( ! $this->conn_id) + { + $this->initialize(); + } + + return $this->_execute($sql); + } + + // -------------------------------------------------------------------- + + /** + * Disable Transactions + * This permits transactions to be disabled at run-time. + * + * @access public + * @return void + */ + function trans_off() + { + $this->trans_enabled = FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Enable/disable Transaction Strict Mode + * When strict mode is enabled, if you are running multiple groups of + * transactions, if one group fails all groups will be rolled back. + * If strict mode is disabled, each group is treated autonomously, meaning + * a failure of one group will not affect any others + * + * @access public + * @return void + */ + function trans_strict($mode = TRUE) + { + $this->trans_strict = is_bool($mode) ? $mode : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Start Transaction + * + * @access public + * @return void + */ + function trans_start($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return FALSE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + $this->_trans_depth += 1; + return; + } + + $this->trans_begin($test_mode); + } + + // -------------------------------------------------------------------- + + /** + * Complete Transaction + * + * @access public + * @return bool + */ + function trans_complete() + { + if ( ! $this->trans_enabled) + { + return FALSE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 1) + { + $this->_trans_depth -= 1; + return TRUE; + } + + // The query() function will set this flag to FALSE in the event that a query failed + if ($this->_trans_status === FALSE) + { + $this->trans_rollback(); + + // If we are NOT running in strict mode, we will reset + // the _trans_status flag so that subsequent groups of transactions + // will be permitted. + if ($this->trans_strict === FALSE) + { + $this->_trans_status = TRUE; + } + + log_message('debug', 'DB Transaction Failure'); + return FALSE; + } + + $this->trans_commit(); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Lets you retrieve the transaction flag to determine if it has failed + * + * @access public + * @return bool + */ + function trans_status() + { + return $this->_trans_status; + } + + // -------------------------------------------------------------------- + + /** + * Compile Bindings + * + * @access public + * @param string the sql statement + * @param array an array of bind data + * @return string + */ + function compile_binds($sql, $binds) + { + if (strpos($sql, $this->bind_marker) === FALSE) + { + return $sql; + } + + if ( ! is_array($binds)) + { + $binds = array($binds); + } + + // Get the sql segments around the bind markers + $segments = explode($this->bind_marker, $sql); + + // The count of bind should be 1 less then the count of segments + // If there are more bind arguments trim it down + if (count($binds) >= count($segments)) { + $binds = array_slice($binds, 0, count($segments)-1); + } + + // Construct the binded query + $result = $segments[0]; + $i = 0; + foreach ($binds as $bind) + { + $result .= $this->escape($bind); + $result .= $segments[++$i]; + } + + return $result; + } + + // -------------------------------------------------------------------- + + /** + * Determines if a query is a "write" type. + * + * @access public + * @param string An SQL query string + * @return boolean + */ + function is_write_type($sql) + { + if ( ! preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql)) + { + return FALSE; + } + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Calculate the aggregate query elapsed time + * + * @access public + * @param integer The number of decimal places + * @return integer + */ + function elapsed_time($decimals = 6) + { + return number_format($this->benchmark, $decimals); + } + + // -------------------------------------------------------------------- + + /** + * Returns the total number of queries + * + * @access public + * @return integer + */ + function total_queries() + { + return $this->query_count; + } + + // -------------------------------------------------------------------- + + /** + * Returns the last query that was executed + * + * @access public + * @return void + */ + function last_query() + { + return end($this->queries); + } + + // -------------------------------------------------------------------- + + /** + * "Smart" Escape String + * + * Escapes data based on type + * Sets boolean and null types + * + * @access public + * @param string + * @return mixed + */ + function escape($str) + { + if (is_string($str)) + { + $str = "'".$this->escape_str($str)."'"; + } + elseif (is_bool($str)) + { + $str = ($str === FALSE) ? 0 : 1; + } + elseif (is_null($str)) + { + $str = 'NULL'; + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Escape LIKE String + * + * Calls the individual driver for platform + * specific escaping for LIKE conditions + * + * @access public + * @param string + * @return mixed + */ + function escape_like_str($str) + { + return $this->escape_str($str, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Primary + * + * Retrieves the primary key. It assumes that the row in the first + * position is the primary key + * + * @access public + * @param string the table name + * @return string + */ + function primary($table = '') + { + $fields = $this->list_fields($table); + + if ( ! is_array($fields)) + { + return FALSE; + } + + return current($fields); + } + + // -------------------------------------------------------------------- + + /** + * Returns an array of table names + * + * @access public + * @return array + */ + function list_tables($constrain_by_prefix = FALSE) + { + // Is there a cached result? + if (isset($this->data_cache['table_names'])) + { + return $this->data_cache['table_names']; + } + + if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix))) + { + if ($this->db_debug) + { + return $this->display_error('db_unsupported_function'); + } + return FALSE; + } + + $retval = array(); + $query = $this->query($sql); + + if ($query->num_rows() > 0) + { + foreach ($query->result_array() as $row) + { + if (isset($row['TABLE_NAME'])) + { + $retval[] = $row['TABLE_NAME']; + } + else + { + $retval[] = array_shift($row); + } + } + } + + $this->data_cache['table_names'] = $retval; + return $this->data_cache['table_names']; + } + + // -------------------------------------------------------------------- + + /** + * Determine if a particular table exists + * @access public + * @return boolean + */ + function table_exists($table_name) + { + return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Fetch MySQL Field Names + * + * @access public + * @param string the table name + * @return array + */ + function list_fields($table = '') + { + // Is there a cached result? + if (isset($this->data_cache['field_names'][$table])) + { + return $this->data_cache['field_names'][$table]; + } + + if ($table == '') + { + if ($this->db_debug) + { + return $this->display_error('db_field_param_missing'); + } + return FALSE; + } + + if (FALSE === ($sql = $this->_list_columns($table))) + { + if ($this->db_debug) + { + return $this->display_error('db_unsupported_function'); + } + return FALSE; + } + + $query = $this->query($sql); + + $retval = array(); + foreach ($query->result_array() as $row) + { + if (isset($row['COLUMN_NAME'])) + { + $retval[] = $row['COLUMN_NAME']; + } + else + { + $retval[] = current($row); + } + } + + $this->data_cache['field_names'][$table] = $retval; + return $this->data_cache['field_names'][$table]; + } + + // -------------------------------------------------------------------- + + /** + * Determine if a particular field exists + * @access public + * @param string + * @param string + * @return boolean + */ + function field_exists($field_name, $table_name) + { + return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Returns an object with field data + * + * @access public + * @param string the table name + * @return object + */ + function field_data($table = '') + { + if ($table == '') + { + if ($this->db_debug) + { + return $this->display_error('db_field_param_missing'); + } + return FALSE; + } + + $query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE))); + + return $query->field_data(); + } + + // -------------------------------------------------------------------- + + /** + * Generate an insert string + * + * @access public + * @param string the table upon which the query will be performed + * @param array an associative array data of key/values + * @return string + */ + function insert_string($table, $data) + { + $fields = array(); + $values = array(); + + foreach ($data as $key => $val) + { + $fields[] = $this->_escape_identifiers($key); + $values[] = $this->escape($val); + } + + return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values); + } + + // -------------------------------------------------------------------- + + /** + * Generate an update string + * + * @access public + * @param string the table upon which the query will be performed + * @param array an associative array data of key/values + * @param mixed the "where" statement + * @return string + */ + function update_string($table, $data, $where) + { + if ($where == '') + { + return false; + } + + $fields = array(); + foreach ($data as $key => $val) + { + $fields[$this->_protect_identifiers($key)] = $this->escape($val); + } + + if ( ! is_array($where)) + { + $dest = array($where); + } + else + { + $dest = array(); + foreach ($where as $key => $val) + { + $prefix = (count($dest) == 0) ? '' : ' AND '; + + if ($val !== '') + { + if ( ! $this->_has_operator($key)) + { + $key .= ' ='; + } + + $val = ' '.$this->escape($val); + } + + $dest[] = $prefix.$key.$val; + } + } + + return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest); + } + + // -------------------------------------------------------------------- + + /** + * Tests whether the string has an SQL operator + * + * @access private + * @param string + * @return bool + */ + function _has_operator($str) + { + $str = trim($str); + if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str)) + { + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Enables a native PHP function to be run, using a platform agnostic wrapper. + * + * @access public + * @param string the function name + * @param mixed any parameters needed by the function + * @return mixed + */ + function call_function($function) + { + $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_'; + + if (FALSE === strpos($driver, $function)) + { + $function = $driver.$function; + } + + if ( ! function_exists($function)) + { + if ($this->db_debug) + { + return $this->display_error('db_unsupported_function'); + } + return FALSE; + } + else + { + $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null; + if (is_null($args)) + { + return call_user_func($function); + } + else + { + return call_user_func_array($function, $args); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Set Cache Directory Path + * + * @access public + * @param string the path to the cache directory + * @return void + */ + function cache_set_path($path = '') + { + $this->cachedir = $path; + } + + // -------------------------------------------------------------------- + + /** + * Enable Query Caching + * + * @access public + * @return void + */ + function cache_on() + { + $this->cache_on = TRUE; + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Disable Query Caching + * + * @access public + * @return void + */ + function cache_off() + { + $this->cache_on = FALSE; + return FALSE; + } + + + // -------------------------------------------------------------------- + + /** + * Delete the cache files associated with a particular URI + * + * @access public + * @return void + */ + function cache_delete($segment_one = '', $segment_two = '') + { + if ( ! $this->_cache_init()) + { + return FALSE; + } + return $this->CACHE->delete($segment_one, $segment_two); + } + + // -------------------------------------------------------------------- + + /** + * Delete All cache files + * + * @access public + * @return void + */ + function cache_delete_all() + { + if ( ! $this->_cache_init()) + { + return FALSE; + } + + return $this->CACHE->delete_all(); + } + + // -------------------------------------------------------------------- + + /** + * Initialize the Cache Class + * + * @access private + * @return void + */ + function _cache_init() + { + if (is_object($this->CACHE) AND class_exists('CI_DB_Cache')) + { + return TRUE; + } + + if ( ! class_exists('CI_DB_Cache')) + { + if ( ! @include(BASEPATH.'database/DB_cache.php')) + { + return $this->cache_off(); + } + } + + $this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @return void + */ + function close() + { + if (is_resource($this->conn_id) OR is_object($this->conn_id)) + { + $this->_close($this->conn_id); + } + $this->conn_id = FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Display an error message + * + * @access public + * @param string the error message + * @param string any "swap" values + * @param boolean whether to localize the message + * @return string sends the application/error_db.php template + */ + function display_error($error = '', $swap = '', $native = FALSE) + { + $LANG =& load_class('Lang', 'core'); + $LANG->load('db'); + + $heading = $LANG->line('db_error_heading'); + + if ($native == TRUE) + { + $message = $error; + } + else + { + $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error; + } + + // Find the most likely culprit of the error by going through + // the backtrace until the source file is no longer in the + // database folder. + + $trace = debug_backtrace(); + + foreach ($trace as $call) + { + if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE) + { + // Found it - use a relative path for safety + $message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']); + $message[] = 'Line Number: '.$call['line']; + + break; + } + } + + $error =& load_class('Exceptions', 'core'); + echo $error->show_error($heading, $message, 'error_db'); + exit; + } + + // -------------------------------------------------------------------- + + /** + * Protect Identifiers + * + * This function adds backticks if appropriate based on db type + * + * @access private + * @param mixed the item to escape + * @return mixed the item with backticks + */ + function protect_identifiers($item, $prefix_single = FALSE) + { + return $this->_protect_identifiers($item, $prefix_single); + } + + // -------------------------------------------------------------------- + + /** + * Protect Identifiers + * + * This function is used extensively by the Active Record class, and by + * a couple functions in this class. + * It takes a column or table name (optionally with an alias) and inserts + * the table prefix onto it. Some logic is necessary in order to deal with + * column names that include the path. Consider a query like this: + * + * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table + * + * Or a query with aliasing: + * + * SELECT m.member_id, m.member_name FROM members AS m + * + * Since the column name can include up to four segments (host, DB, table, column) + * or also have an alias prefix, we need to do a bit of work to figure this out and + * insert the table prefix (if it exists) in the proper position, and escape only + * the correct identifiers. + * + * @access private + * @param string + * @param bool + * @param mixed + * @param bool + * @return string + */ + function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE) + { + if ( ! is_bool($protect_identifiers)) + { + $protect_identifiers = $this->_protect_identifiers; + } + + if (is_array($item)) + { + $escaped_array = array(); + + foreach ($item as $k => $v) + { + $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v); + } + + return $escaped_array; + } + + // Convert tabs or multiple spaces into single spaces + $item = preg_replace('/[\t ]+/', ' ', $item); + + // If the item has an alias declaration we remove it and set it aside. + // Basically we remove everything to the right of the first space + if (strpos($item, ' ') !== FALSE) + { + $alias = strstr($item, ' '); + $item = substr($item, 0, - strlen($alias)); + } + else + { + $alias = ''; + } + + // This is basically a bug fix for queries that use MAX, MIN, etc. + // If a parenthesis is found we know that we do not need to + // escape the data or add a prefix. There's probably a more graceful + // way to deal with this, but I'm not thinking of it -- Rick + if (strpos($item, '(') !== FALSE) + { + return $item.$alias; + } + + // Break the string apart if it contains periods, then insert the table prefix + // in the correct location, assuming the period doesn't indicate that we're dealing + // with an alias. While we're at it, we will escape the components + if (strpos($item, '.') !== FALSE) + { + $parts = explode('.', $item); + + // Does the first segment of the exploded item match + // one of the aliases previously identified? If so, + // we have nothing more to do other than escape the item + if (in_array($parts[0], $this->ar_aliased_tables)) + { + if ($protect_identifiers === TRUE) + { + foreach ($parts as $key => $val) + { + if ( ! in_array($val, $this->_reserved_identifiers)) + { + $parts[$key] = $this->_escape_identifiers($val); + } + } + + $item = implode('.', $parts); + } + return $item.$alias; + } + + // Is there a table prefix defined in the config file? If not, no need to do anything + if ($this->dbprefix != '') + { + // We now add the table prefix based on some logic. + // Do we have 4 segments (hostname.database.table.column)? + // If so, we add the table prefix to the column name in the 3rd segment. + if (isset($parts[3])) + { + $i = 2; + } + // Do we have 3 segments (database.table.column)? + // If so, we add the table prefix to the column name in 2nd position + elseif (isset($parts[2])) + { + $i = 1; + } + // Do we have 2 segments (table.column)? + // If so, we add the table prefix to the column name in 1st segment + else + { + $i = 0; + } + + // This flag is set when the supplied $item does not contain a field name. + // This can happen when this function is being called from a JOIN. + if ($field_exists == FALSE) + { + $i++; + } + + // Verify table prefix and replace if necessary + if ($this->swap_pre != '' && strncmp($parts[$i], $this->swap_pre, strlen($this->swap_pre)) === 0) + { + $parts[$i] = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $parts[$i]); + } + + // We only add the table prefix if it does not already exist + if (substr($parts[$i], 0, strlen($this->dbprefix)) != $this->dbprefix) + { + $parts[$i] = $this->dbprefix.$parts[$i]; + } + + // Put the parts back together + $item = implode('.', $parts); + } + + if ($protect_identifiers === TRUE) + { + $item = $this->_escape_identifiers($item); + } + + return $item.$alias; + } + + // Is there a table prefix? If not, no need to insert it + if ($this->dbprefix != '') + { + // Verify table prefix and replace if necessary + if ($this->swap_pre != '' && strncmp($item, $this->swap_pre, strlen($this->swap_pre)) === 0) + { + $item = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $item); + } + + // Do we prefix an item with no segments? + if ($prefix_single == TRUE AND substr($item, 0, strlen($this->dbprefix)) != $this->dbprefix) + { + $item = $this->dbprefix.$item; + } + } + + if ($protect_identifiers === TRUE AND ! in_array($item, $this->_reserved_identifiers)) + { + $item = $this->_escape_identifiers($item); + } + + return $item.$alias; + } + + // -------------------------------------------------------------------- + + /** + * Dummy method that allows Active Record class to be disabled + * + * This function is used extensively by every db driver. + * + * @return void + */ + protected function _reset_select() + { + } + +} + +/* End of file DB_driver.php */ +/* Location: ./system/database/DB_driver.php */ \ No newline at end of file diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php new file mode 100644 index 0000000..6bc4041 --- /dev/null +++ b/system/database/DB_forge.php @@ -0,0 +1,382 @@ +db + $CI =& get_instance(); + $this->db =& $CI->db; + log_message('debug', "Database Forge Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Create database + * + * @access public + * @param string the database name + * @return bool + */ + function create_database($db_name) + { + $sql = $this->_create_database($db_name); + + if (is_bool($sql)) + { + return $sql; + } + + return $this->db->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access public + * @param string the database name + * @return bool + */ + function drop_database($db_name) + { + $sql = $this->_drop_database($db_name); + + if (is_bool($sql)) + { + return $sql; + } + + return $this->db->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Add Key + * + * @access public + * @param string key + * @param string type + * @return void + */ + function add_key($key = '', $primary = FALSE) + { + if (is_array($key)) + { + foreach ($key as $one) + { + $this->add_key($one, $primary); + } + + return; + } + + if ($key == '') + { + show_error('Key information is required for that operation.'); + } + + if ($primary === TRUE) + { + $this->primary_keys[] = $key; + } + else + { + $this->keys[] = $key; + } + } + + // -------------------------------------------------------------------- + + /** + * Add Field + * + * @access public + * @param string collation + * @return void + */ + function add_field($field = '') + { + if ($field == '') + { + show_error('Field information is required.'); + } + + if (is_string($field)) + { + if ($field == 'id') + { + $this->add_field(array( + 'id' => array( + 'type' => 'INT', + 'constraint' => 9, + 'auto_increment' => TRUE + ) + )); + $this->add_key('id', TRUE); + } + else + { + if (strpos($field, ' ') === FALSE) + { + show_error('Field information is required for that operation.'); + } + + $this->fields[] = $field; + } + } + + if (is_array($field)) + { + $this->fields = array_merge($this->fields, $field); + } + + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access public + * @param string the table name + * @return bool + */ + function create_table($table = '', $if_not_exists = FALSE) + { + if ($table == '') + { + show_error('A table name is required for that operation.'); + } + + if (count($this->fields) == 0) + { + show_error('Field information is required.'); + } + + $sql = $this->_create_table($this->db->dbprefix.$table, $this->fields, $this->primary_keys, $this->keys, $if_not_exists); + + $this->_reset(); + return $this->db->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access public + * @param string the table name + * @return bool + */ + function drop_table($table_name) + { + $sql = $this->_drop_table($this->db->dbprefix.$table_name); + + if (is_bool($sql)) + { + return $sql; + } + + return $this->db->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Rename Table + * + * @access public + * @param string the old table name + * @param string the new table name + * @return bool + */ + function rename_table($table_name, $new_table_name) + { + if ($table_name == '' OR $new_table_name == '') + { + show_error('A table name is required for that operation.'); + } + + $sql = $this->_rename_table($this->db->dbprefix.$table_name, $this->db->dbprefix.$new_table_name); + return $this->db->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Column Add + * + * @access public + * @param string the table name + * @param string the column name + * @param string the column definition + * @return bool + */ + function add_column($table = '', $field = array(), $after_field = '') + { + if ($table == '') + { + show_error('A table name is required for that operation.'); + } + + // add field info into field array, but we can only do one at a time + // so we cycle through + + foreach ($field as $k => $v) + { + $this->add_field(array($k => $field[$k])); + + if (count($this->fields) == 0) + { + show_error('Field information is required.'); + } + + $sql = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->fields, $after_field); + + $this->_reset(); + + if ($this->db->query($sql) === FALSE) + { + return FALSE; + } + } + + return TRUE; + + } + + // -------------------------------------------------------------------- + + /** + * Column Drop + * + * @access public + * @param string the table name + * @param string the column name + * @return bool + */ + function drop_column($table = '', $column_name = '') + { + + if ($table == '') + { + show_error('A table name is required for that operation.'); + } + + if ($column_name == '') + { + show_error('A column name is required for that operation.'); + } + + $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name); + + return $this->db->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Column Modify + * + * @access public + * @param string the table name + * @param string the column name + * @param string the column definition + * @return bool + */ + function modify_column($table = '', $field = array()) + { + if ($table == '') + { + show_error('A table name is required for that operation.'); + } + + // add field info into field array, but we can only do one at a time + // so we cycle through + + foreach ($field as $k => $v) + { + // If no name provided, use the current name + if ( ! isset($field[$k]['name'])) + { + $field[$k]['name'] = $k; + } + + $this->add_field(array($k => $field[$k])); + + if (count($this->fields) == 0) + { + show_error('Field information is required.'); + } + + $sql = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->fields); + + $this->_reset(); + + if ($this->db->query($sql) === FALSE) + { + return FALSE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Reset + * + * Resets table creation vars + * + * @access private + * @return void + */ + function _reset() + { + $this->fields = array(); + $this->keys = array(); + $this->primary_keys = array(); + } + +} + +/* End of file DB_forge.php */ +/* Location: ./system/database/DB_forge.php */ \ No newline at end of file diff --git a/system/database/DB_result.php b/system/database/DB_result.php new file mode 100644 index 0000000..48d66c8 --- /dev/null +++ b/system/database/DB_result.php @@ -0,0 +1,410 @@ +result_array(); + else if ($type == 'object') return $this->result_object(); + else return $this->custom_result_object($type); + } + + // -------------------------------------------------------------------- + + /** + * Custom query result. + * + * @param class_name A string that represents the type of object you want back + * @return array of objects + */ + public function custom_result_object($class_name) + { + if (array_key_exists($class_name, $this->custom_result_object)) + { + return $this->custom_result_object[$class_name]; + } + + if ($this->result_id === FALSE OR $this->num_rows() == 0) + { + return array(); + } + + // add the data to the object + $this->_data_seek(0); + $result_object = array(); + + while ($row = $this->_fetch_object()) + { + $object = new $class_name(); + + foreach ($row as $key => $value) + { + $object->$key = $value; + } + + $result_object[] = $object; + } + + // return the array + return $this->custom_result_object[$class_name] = $result_object; + } + + // -------------------------------------------------------------------- + + /** + * Query result. "object" version. + * + * @access public + * @return object + */ + public function result_object() + { + if (count($this->result_object) > 0) + { + return $this->result_object; + } + + // In the event that query caching is on the result_id variable + // will return FALSE since there isn't a valid SQL resource so + // we'll simply return an empty array. + if ($this->result_id === FALSE OR $this->num_rows() == 0) + { + return array(); + } + + $this->_data_seek(0); + while ($row = $this->_fetch_object()) + { + $this->result_object[] = $row; + } + + return $this->result_object; + } + + // -------------------------------------------------------------------- + + /** + * Query result. "array" version. + * + * @access public + * @return array + */ + public function result_array() + { + if (count($this->result_array) > 0) + { + return $this->result_array; + } + + // In the event that query caching is on the result_id variable + // will return FALSE since there isn't a valid SQL resource so + // we'll simply return an empty array. + if ($this->result_id === FALSE OR $this->num_rows() == 0) + { + return array(); + } + + $this->_data_seek(0); + while ($row = $this->_fetch_assoc()) + { + $this->result_array[] = $row; + } + + return $this->result_array; + } + + // -------------------------------------------------------------------- + + /** + * Query result. Acts as a wrapper function for the following functions. + * + * @access public + * @param string + * @param string can be "object" or "array" + * @return mixed either a result object or array + */ + public function row($n = 0, $type = 'object') + { + if ( ! is_numeric($n)) + { + // We cache the row data for subsequent uses + if ( ! is_array($this->row_data)) + { + $this->row_data = $this->row_array(0); + } + + // array_key_exists() instead of isset() to allow for MySQL NULL values + if (array_key_exists($n, $this->row_data)) + { + return $this->row_data[$n]; + } + // reset the $n variable if the result was not achieved + $n = 0; + } + + if ($type == 'object') return $this->row_object($n); + else if ($type == 'array') return $this->row_array($n); + else return $this->custom_row_object($n, $type); + } + + // -------------------------------------------------------------------- + + /** + * Assigns an item into a particular column slot + * + * @access public + * @return object + */ + public function set_row($key, $value = NULL) + { + // We cache the row data for subsequent uses + if ( ! is_array($this->row_data)) + { + $this->row_data = $this->row_array(0); + } + + if (is_array($key)) + { + foreach ($key as $k => $v) + { + $this->row_data[$k] = $v; + } + + return; + } + + if ($key != '' AND ! is_null($value)) + { + $this->row_data[$key] = $value; + } + } + + // -------------------------------------------------------------------- + + /** + * Returns a single result row - custom object version + * + * @access public + * @return object + */ + public function custom_row_object($n, $type) + { + $result = $this->custom_result_object($type); + + if (count($result) == 0) + { + return $result; + } + + if ($n != $this->current_row AND isset($result[$n])) + { + $this->current_row = $n; + } + + return $result[$this->current_row]; + } + + /** + * Returns a single result row - object version + * + * @access public + * @return object + */ + public function row_object($n = 0) + { + $result = $this->result_object(); + + if (count($result) == 0) + { + return $result; + } + + if ($n != $this->current_row AND isset($result[$n])) + { + $this->current_row = $n; + } + + return $result[$this->current_row]; + } + + // -------------------------------------------------------------------- + + /** + * Returns a single result row - array version + * + * @access public + * @return array + */ + public function row_array($n = 0) + { + $result = $this->result_array(); + + if (count($result) == 0) + { + return $result; + } + + if ($n != $this->current_row AND isset($result[$n])) + { + $this->current_row = $n; + } + + return $result[$this->current_row]; + } + + + // -------------------------------------------------------------------- + + /** + * Returns the "first" row + * + * @access public + * @return object + */ + public function first_row($type = 'object') + { + $result = $this->result($type); + + if (count($result) == 0) + { + return $result; + } + return $result[0]; + } + + // -------------------------------------------------------------------- + + /** + * Returns the "last" row + * + * @access public + * @return object + */ + public function last_row($type = 'object') + { + $result = $this->result($type); + + if (count($result) == 0) + { + return $result; + } + return $result[count($result) -1]; + } + + // -------------------------------------------------------------------- + + /** + * Returns the "next" row + * + * @access public + * @return object + */ + public function next_row($type = 'object') + { + $result = $this->result($type); + + if (count($result) == 0) + { + return $result; + } + + if (isset($result[$this->current_row + 1])) + { + ++$this->current_row; + } + + return $result[$this->current_row]; + } + + // -------------------------------------------------------------------- + + /** + * Returns the "previous" row + * + * @access public + * @return object + */ + public function previous_row($type = 'object') + { + $result = $this->result($type); + + if (count($result) == 0) + { + return $result; + } + + if (isset($result[$this->current_row - 1])) + { + --$this->current_row; + } + return $result[$this->current_row]; + } + + // -------------------------------------------------------------------- + + /** + * The following functions are normally overloaded by the identically named + * methods in the platform-specific driver -- except when query caching + * is used. When caching is enabled we do not load the other driver. + * These functions are primarily here to prevent undefined function errors + * when a cached result object is in use. They are not otherwise fully + * operational due to the unavailability of the database resource IDs with + * cached results. + */ + public function num_rows() { return $this->num_rows; } + public function num_fields() { return 0; } + public function list_fields() { return array(); } + public function field_data() { return array(); } + public function free_result() { return TRUE; } + protected function _data_seek() { return TRUE; } + protected function _fetch_assoc() { return array(); } + protected function _fetch_object() { return array(); } + +} +// END DB_result class + +/* End of file DB_result.php */ +/* Location: ./system/database/DB_result.php */ diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php new file mode 100644 index 0000000..52196b7 --- /dev/null +++ b/system/database/DB_utility.php @@ -0,0 +1,414 @@ +db + $CI =& get_instance(); + $this->db =& $CI->db; + + log_message('debug', "Database Utility Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * List databases + * + * @access public + * @return bool + */ + function list_databases() + { + // Is there a cached result? + if (isset($this->data_cache['db_names'])) + { + return $this->data_cache['db_names']; + } + + $query = $this->db->query($this->_list_databases()); + $dbs = array(); + if ($query->num_rows() > 0) + { + foreach ($query->result_array() as $row) + { + $dbs[] = current($row); + } + } + + $this->data_cache['db_names'] = $dbs; + return $this->data_cache['db_names']; + } + + // -------------------------------------------------------------------- + + /** + * Determine if a particular database exists + * + * @access public + * @param string + * @return boolean + */ + function database_exists($database_name) + { + // Some databases won't have access to the list_databases() function, so + // this is intended to allow them to override with their own functions as + // defined in $driver_utility.php + if (method_exists($this, '_database_exists')) + { + return $this->_database_exists($database_name); + } + else + { + return ( ! in_array($database_name, $this->list_databases())) ? FALSE : TRUE; + } + } + + + // -------------------------------------------------------------------- + + /** + * Optimize Table + * + * @access public + * @param string the table name + * @return bool + */ + function optimize_table($table_name) + { + $sql = $this->_optimize_table($table_name); + + if (is_bool($sql)) + { + show_error('db_must_use_set'); + } + + $query = $this->db->query($sql); + $res = $query->result_array(); + + // Note: Due to a bug in current() that affects some versions + // of PHP we can not pass function call directly into it + return current($res); + } + + // -------------------------------------------------------------------- + + /** + * Optimize Database + * + * @access public + * @return array + */ + function optimize_database() + { + $result = array(); + foreach ($this->db->list_tables() as $table_name) + { + $sql = $this->_optimize_table($table_name); + + if (is_bool($sql)) + { + return $sql; + } + + $query = $this->db->query($sql); + + // Build the result array... + // Note: Due to a bug in current() that affects some versions + // of PHP we can not pass function call directly into it + $res = $query->result_array(); + $res = current($res); + $key = str_replace($this->db->database.'.', '', current($res)); + $keys = array_keys($res); + unset($res[$keys[0]]); + + $result[$key] = $res; + } + + return $result; + } + + // -------------------------------------------------------------------- + + /** + * Repair Table + * + * @access public + * @param string the table name + * @return bool + */ + function repair_table($table_name) + { + $sql = $this->_repair_table($table_name); + + if (is_bool($sql)) + { + return $sql; + } + + $query = $this->db->query($sql); + + // Note: Due to a bug in current() that affects some versions + // of PHP we can not pass function call directly into it + $res = $query->result_array(); + return current($res); + } + + // -------------------------------------------------------------------- + + /** + * Generate CSV from a query result object + * + * @access public + * @param object The query result object + * @param string The delimiter - comma by default + * @param string The newline character - \n by default + * @param string The enclosure - double quote by default + * @return string + */ + function csv_from_result($query, $delim = ",", $newline = "\n", $enclosure = '"') + { + if ( ! is_object($query) OR ! method_exists($query, 'list_fields')) + { + show_error('You must submit a valid result object'); + } + + $out = ''; + + // First generate the headings from the table column names + foreach ($query->list_fields() as $name) + { + $out .= $enclosure.str_replace($enclosure, $enclosure.$enclosure, $name).$enclosure.$delim; + } + + $out = rtrim($out); + $out .= $newline; + + // Next blast through the result array and build out the rows + foreach ($query->result_array() as $row) + { + foreach ($row as $item) + { + $out .= $enclosure.str_replace($enclosure, $enclosure.$enclosure, $item).$enclosure.$delim; + } + $out = rtrim($out); + $out .= $newline; + } + + return $out; + } + + // -------------------------------------------------------------------- + + /** + * Generate XML data from a query result object + * + * @access public + * @param object The query result object + * @param array Any preferences + * @return string + */ + function xml_from_result($query, $params = array()) + { + if ( ! is_object($query) OR ! method_exists($query, 'list_fields')) + { + show_error('You must submit a valid result object'); + } + + // Set our default values + foreach (array('root' => 'root', 'element' => 'element', 'newline' => "\n", 'tab' => "\t") as $key => $val) + { + if ( ! isset($params[$key])) + { + $params[$key] = $val; + } + } + + // Create variables for convenience + extract($params); + + // Load the xml helper + $CI =& get_instance(); + $CI->load->helper('xml'); + + // Generate the result + $xml = "<{$root}>".$newline; + foreach ($query->result_array() as $row) + { + $xml .= $tab."<{$element}>".$newline; + + foreach ($row as $key => $val) + { + $xml .= $tab.$tab."<{$key}>".xml_convert($val)."".$newline; + } + $xml .= $tab."".$newline; + } + $xml .= "".$newline; + + return $xml; + } + + // -------------------------------------------------------------------- + + /** + * Database Backup + * + * @access public + * @return void + */ + function backup($params = array()) + { + // If the parameters have not been submitted as an + // array then we know that it is simply the table + // name, which is a valid short cut. + if (is_string($params)) + { + $params = array('tables' => $params); + } + + // ------------------------------------------------------ + + // Set up our default preferences + $prefs = array( + 'tables' => array(), + 'ignore' => array(), + 'filename' => '', + 'format' => 'gzip', // gzip, zip, txt + 'add_drop' => TRUE, + 'add_insert' => TRUE, + 'newline' => "\n" + ); + + // Did the user submit any preferences? If so set them.... + if (count($params) > 0) + { + foreach ($prefs as $key => $val) + { + if (isset($params[$key])) + { + $prefs[$key] = $params[$key]; + } + } + } + + // ------------------------------------------------------ + + // Are we backing up a complete database or individual tables? + // If no table names were submitted we'll fetch the entire table list + if (count($prefs['tables']) == 0) + { + $prefs['tables'] = $this->db->list_tables(); + } + + // ------------------------------------------------------ + + // Validate the format + if ( ! in_array($prefs['format'], array('gzip', 'zip', 'txt'), TRUE)) + { + $prefs['format'] = 'txt'; + } + + // ------------------------------------------------------ + + // Is the encoder supported? If not, we'll either issue an + // error or use plain text depending on the debug settings + if (($prefs['format'] == 'gzip' AND ! @function_exists('gzencode')) + OR ($prefs['format'] == 'zip' AND ! @function_exists('gzcompress'))) + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_compression'); + } + + $prefs['format'] = 'txt'; + } + + // ------------------------------------------------------ + + // Set the filename if not provided - Only needed with Zip files + if ($prefs['filename'] == '' AND $prefs['format'] == 'zip') + { + $prefs['filename'] = (count($prefs['tables']) == 1) ? $prefs['tables'] : $this->db->database; + $prefs['filename'] .= '_'.date('Y-m-d_H-i', time()); + } + + // ------------------------------------------------------ + + // Was a Gzip file requested? + if ($prefs['format'] == 'gzip') + { + return gzencode($this->_backup($prefs)); + } + + // ------------------------------------------------------ + + // Was a text file requested? + if ($prefs['format'] == 'txt') + { + return $this->_backup($prefs); + } + + // ------------------------------------------------------ + + // Was a Zip file requested? + if ($prefs['format'] == 'zip') + { + // If they included the .zip file extension we'll remove it + if (preg_match("|.+?\.zip$|", $prefs['filename'])) + { + $prefs['filename'] = str_replace('.zip', '', $prefs['filename']); + } + + // Tack on the ".sql" file extension if needed + if ( ! preg_match("|.+?\.sql$|", $prefs['filename'])) + { + $prefs['filename'] .= '.sql'; + } + + // Load the Zip class and output it + + $CI =& get_instance(); + $CI->load->library('zip'); + $CI->zip->add_data($prefs['filename'], $this->_backup($prefs)); + return $CI->zip->get_zip(); + } + + } + +} + + +/* End of file DB_utility.php */ +/* Location: ./system/database/DB_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php new file mode 100644 index 0000000..d011404 --- /dev/null +++ b/system/database/drivers/cubrid/cubrid_driver.php @@ -0,0 +1,792 @@ +port == '') + { + $this->port = self::DEFAULT_PORT; + } + + $conn = cubrid_connect($this->hostname, $this->port, $this->database, $this->username, $this->password); + + if ($conn) + { + // Check if a user wants to run queries in dry, i.e. run the + // queries but not commit them. + if (isset($this->auto_commit) && ! $this->auto_commit) + { + cubrid_set_autocommit($conn, CUBRID_AUTOCOMMIT_FALSE); + } + else + { + cubrid_set_autocommit($conn, CUBRID_AUTOCOMMIT_TRUE); + $this->auto_commit = TRUE; + } + } + + return $conn; + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * In CUBRID persistent DB connection is supported natively in CUBRID + * engine which can be configured in the CUBRID Broker configuration + * file by setting the CCI_PCONNECT parameter to ON. In that case, all + * connections established between the client application and the + * server will become persistent. This is calling the same + * @cubrid_connect function will establish persisten connection + * considering that the CCI_PCONNECT is ON. + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + return $this->db_connect(); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + if (cubrid_ping($this->conn_id) === FALSE) + { + $this->conn_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + // In CUBRID there is no need to select a database as the database + // is chosen at the connection time. + // So, to determine if the database is "selected", all we have to + // do is ping the server and return that value. + return cubrid_ping($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // In CUBRID, there is no need to set charset or collation. + // This is why returning true will allow the application continue + // its normal process. + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + // To obtain the CUBRID Server version, no need to run the SQL query. + // CUBRID PHP API provides a function to determin this value. + // This is why we also need to add 'cubrid' value to the list of + // $driver_version_exceptions array in DB_driver class in + // version() function. + return cubrid_get_server_info($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return @cubrid_query($sql, $this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + // No need to prepare + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + if (cubrid_get_autocommit($this->conn_id)) + { + cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_FALSE); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + cubrid_commit($this->conn_id); + + if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id)) + { + cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + cubrid_rollback($this->conn_id); + + if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id)) + { + cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + if (function_exists('cubrid_real_escape_string') AND is_resource($this->conn_id)) + { + $str = cubrid_real_escape_string($str, $this->conn_id); + } + else + { + $str = addslashes($str); + } + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @cubrid_affected_rows($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id() + { + return @cubrid_insert_id($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified table + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * List table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SHOW TABLES"; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'"; + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT * FROM ".$table." LIMIT 1"; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + return cubrid_error($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return cubrid_errno($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return '('.implode(', ', $tables).')'; + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (\"".implode('", "', $keys)."\") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + + /** + * Replace statement + * + * Generates a platform-specific replace string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _replace($table, $keys, $values) + { + return "REPLACE INTO ".$table." (\"".implode('", "', $keys)."\") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (\"".implode('", "', $keys)."\") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = sprintf('"%s" = %s', $key, $val); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + // -------------------------------------------------------------------- + + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @return string + */ + function _update_batch($table, $values, $index, $where = NULL) + { + $ids = array(); + $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field != $index) + { + $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $sql = "UPDATE ".$table." SET "; + $cases = ''; + + foreach ($final as $k => $v) + { + $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) + { + $cases .= $row."\n"; + } + + $cases .= 'ELSE '.$k.' END, '; + } + + $sql .= substr($cases, 0, -2); + + $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + + return $sql; + } + + // -------------------------------------------------------------------- + + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return "TRUNCATE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + if ($offset == 0) + { + $offset = ''; + } + else + { + $offset .= ", "; + } + + return $sql."LIMIT ".$offset.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @cubrid_close($conn_id); + } + +} + + +/* End of file cubrid_driver.php */ +/* Location: ./system/database/drivers/cubrid/cubrid_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php new file mode 100644 index 0000000..bab03f7 --- /dev/null +++ b/system/database/drivers/cubrid/cubrid_forge.php @@ -0,0 +1,288 @@ +$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t\"" . $this->db->_protect_identifiers($field) . "\""; + + if (array_key_exists('NAME', $attributes)) + { + $sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' '; + } + + if (array_key_exists('TYPE', $attributes)) + { + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + switch ($attributes['TYPE']) + { + case 'decimal': + case 'float': + case 'numeric': + $sql .= '('.implode(',', $attributes['CONSTRAINT']).')'; + break; + case 'enum': // As of version 8.4.0 CUBRID does not support + // enum data type. + break; + case 'set': + $sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")'; + break; + default: + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + } + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + //$sql .= ' UNSIGNED'; + // As of version 8.4.0 CUBRID does not support UNSIGNED INTEGER data type. + // Will be supported in the next release as a part of MySQL Compatibility. + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + + if (array_key_exists('UNIQUE', $attributes) && $attributes['UNIQUE'] === TRUE) + { + $sql .= ' UNIQUE'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param mixed the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + //$sql .= 'IF NOT EXISTS '; + // As of version 8.4.0 CUBRID does not support this SQL syntax. + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + + $sql .= $this->_process_fields($fields); + + // If there is a PK defined + if (count($primary_keys) > 0) + { + $key_name = "pk_" . $table . "_" . + $this->db->_protect_identifiers(implode('_', $primary_keys)); + + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tCONSTRAINT " . $key_name . " PRIMARY KEY(" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key_name = $this->db->_protect_identifiers(implode('_', $key)); + $key = $this->db->_protect_identifiers($key); + } + else + { + $key_name = $this->db->_protect_identifiers($key); + $key = array($key_name); + } + + $sql .= ",\n\tKEY \"{$key_name}\" (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n);"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return string + */ + function _drop_table($table) + { + return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param array fields + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $fields, $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type "; + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql.$this->db->_protect_identifiers($fields); + } + + $sql .= $this->_process_fields($fields); + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'RENAME TABLE '.$this->db->_protect_identifiers($table_name)." AS ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + +} + +/* End of file cubrid_forge.php */ +/* Location: ./system/database/drivers/cubrid/cubrid_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/cubrid/cubrid_result.php b/system/database/drivers/cubrid/cubrid_result.php new file mode 100644 index 0000000..6f0c2b5 --- /dev/null +++ b/system/database/drivers/cubrid/cubrid_result.php @@ -0,0 +1,202 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @cubrid_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + return cubrid_column_names($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + + $tablePrimaryKeys = array(); + + while ($field = cubrid_fetch_field($this->result_id)) + { + $F = new stdClass(); + $F->name = $field->name; + $F->type = $field->type; + $F->default = $field->def; + $F->max_length = $field->max_length; + + // At this moment primary_key property is not returned when + // cubrid_fetch_field is called. The following code will + // provide a patch for it. primary_key property will be added + // in the next release. + + // TODO: later version of CUBRID will provide primary_key + // property. + // When PK is defined in CUBRID, an index is automatically + // created in the db_index system table in the form of + // pk_tblname_fieldname. So the following will count how many + // columns are there which satisfy this format. + // The query will search for exact single columns, thus + // compound PK is not supported. + $res = cubrid_query($this->conn_id, + "SELECT COUNT(*) FROM db_index WHERE class_name = '" . $field->table . + "' AND is_primary_key = 'YES' AND index_name = 'pk_" . + $field->table . "_" . $field->name . "'" + ); + + if ($res) + { + $row = cubrid_fetch_array($res, CUBRID_NUM); + $F->primary_key = ($row[0] > 0 ? 1 : null); + } + else + { + $F->primary_key = null; + } + + if (is_resource($res)) + { + cubrid_close_request($res); + $this->result_id = FALSE; + } + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if(is_resource($this->result_id) || + get_resource_type($this->result_id) == "Unknown" && + preg_match('/Resource id #/', strval($this->result_id))) + { + cubrid_close_request($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return cubrid_data_seek($this->result_id, $n); + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return cubrid_fetch_assoc($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return cubrid_fetch_object($this->result_id); + } + +} + + +/* End of file cubrid_result.php */ +/* Location: ./system/database/drivers/cubrid/cubrid_result.php */ \ No newline at end of file diff --git a/system/database/drivers/cubrid/cubrid_utility.php b/system/database/drivers/cubrid/cubrid_utility.php new file mode 100644 index 0000000..cd16d1e --- /dev/null +++ b/system/database/drivers/cubrid/cubrid_utility.php @@ -0,0 +1,108 @@ +conn_id) + { + return "SELECT '" . $this->database . "'"; + } + else + { + return FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Optimize table query + * + * Generates a platform-specific query so that a table can be optimized + * + * @access private + * @param string the table name + * @return object + * @link http://www.cubrid.org/manual/840/en/Optimize%20Database + */ + function _optimize_table($table) + { + // No SQL based support in CUBRID as of version 8.4.0. Database or + // table optimization can be performed using CUBRID Manager + // database administration tool. See the link above for more info. + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Repair table query + * + * Generates a platform-specific query so that a table can be repaired + * + * @access private + * @param string the table name + * @return object + * @link http://www.cubrid.org/manual/840/en/Checking%20Database%20Consistency + */ + function _repair_table($table) + { + // Not supported in CUBRID as of version 8.4.0. Database or + // table consistency can be checked using CUBRID Manager + // database administration tool. See the link above for more info. + return FALSE; + } + + // -------------------------------------------------------------------- + /** + * CUBRID Export + * + * @access private + * @param array Preferences + * @return mixed + */ + function _backup($params = array()) + { + // No SQL based support in CUBRID as of version 8.4.0. Database or + // table backup can be performed using CUBRID Manager + // database administration tool. + return $this->db->display_error('db_unsuported_feature'); + } +} + +/* End of file cubrid_utility.php */ +/* Location: ./system/database/drivers/cubrid/cubrid_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/cubrid/index.html b/system/database/drivers/cubrid/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/cubrid/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/index.html b/system/database/drivers/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/mssql/index.html b/system/database/drivers/mssql/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/mssql/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php new file mode 100644 index 0000000..b39bd93 --- /dev/null +++ b/system/database/drivers/mssql/mssql_driver.php @@ -0,0 +1,667 @@ +port != '') + { + $this->hostname .= ','.$this->port; + } + + return @mssql_connect($this->hostname, $this->username, $this->password); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + if ($this->port != '') + { + $this->hostname .= ','.$this->port; + } + + return @mssql_pconnect($this->hostname, $this->username, $this->password); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + // not implemented in MSSQL + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + // Note: The brackets are required in the event that the DB name + // contains reserved characters + return @mssql_select_db('['.$this->database.']', $this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return @mssql_query($sql, $this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + $this->simple_query('BEGIN TRAN'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $this->simple_query('COMMIT TRAN'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $this->simple_query('ROLLBACK TRAN'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + // Escape single quotes + $str = str_replace("'", "''", remove_invisible_characters($str)); + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace( + array($this->_like_escape_chr, '%', '_'), + array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'), + $str + ); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @mssql_rows_affected($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * Returns the last id created in the Identity column. + * + * @access public + * @return integer + */ + function insert_id() + { + $ver = self::_parse_major_version($this->version()); + $sql = ($ver >= 8 ? "SELECT SCOPE_IDENTITY() AS last_id" : "SELECT @@IDENTITY AS last_id"); + $query = $this->query($sql); + $row = $query->row(); + return $row->last_id; + } + + // -------------------------------------------------------------------- + + /** + * Parse major version + * + * Grabs the major version number from the + * database server version string passed in. + * + * @access private + * @param string $version + * @return int16 major version number + */ + function _parse_major_version($version) + { + preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $version, $ver_info); + return $ver_info[1]; // return the major version b/c that's all we're interested in. + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + return "SELECT @@VERSION AS ver"; + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * List table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + + // for future compatibility + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + return FALSE; // not currently supported + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * List column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access private + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'"; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT TOP 1 * FROM ".$table; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + return mssql_get_last_message(); + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + // Are error numbers supported? + return ''; + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return implode(', ', $tables); + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return "TRUNCATE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + $i = $limit + $offset; + + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql); + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @mssql_close($conn_id); + } + +} + + + +/* End of file mssql_driver.php */ +/* Location: ./system/database/drivers/mssql/mssql_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php new file mode 100644 index 0000000..70b20ec --- /dev/null +++ b/system/database/drivers/mssql/mssql_forge.php @@ -0,0 +1,248 @@ +db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param array the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n)"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + // I think this syntax will work, but can find little documentation on renaming tables in MSSQL + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + +} + +/* End of file mssql_forge.php */ +/* Location: ./system/database/drivers/mssql/mssql_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php new file mode 100644 index 0000000..2897ca5 --- /dev/null +++ b/system/database/drivers/mssql/mssql_result.php @@ -0,0 +1,169 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @mssql_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + $field_names = array(); + while ($field = mssql_fetch_field($this->result_id)) + { + $field_names[] = $field->name; + } + + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + while ($field = mssql_fetch_field($this->result_id)) + { + $F = new stdClass(); + $F->name = $field->name; + $F->type = $field->type; + $F->max_length = $field->max_length; + $F->primary_key = 0; + $F->default = ''; + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_resource($this->result_id)) + { + mssql_free_result($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return mssql_data_seek($this->result_id, $n); + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return mssql_fetch_assoc($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return mssql_fetch_object($this->result_id); + } + +} + + +/* End of file mssql_result.php */ +/* Location: ./system/database/drivers/mssql/mssql_result.php */ \ No newline at end of file diff --git a/system/database/drivers/mssql/mssql_utility.php b/system/database/drivers/mssql/mssql_utility.php new file mode 100644 index 0000000..48ecbc7 --- /dev/null +++ b/system/database/drivers/mssql/mssql_utility.php @@ -0,0 +1,88 @@ +db->display_error('db_unsuported_feature'); + } + +} + +/* End of file mssql_utility.php */ +/* Location: ./system/database/drivers/mssql/mssql_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/mysql/index.html b/system/database/drivers/mysql/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/mysql/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php new file mode 100644 index 0000000..f87cfea --- /dev/null +++ b/system/database/drivers/mysql/mysql_driver.php @@ -0,0 +1,779 @@ +port != '') + { + $this->hostname .= ':'.$this->port; + } + + return @mysql_connect($this->hostname, $this->username, $this->password, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + if ($this->port != '') + { + $this->hostname .= ':'.$this->port; + } + + return @mysql_pconnect($this->hostname, $this->username, $this->password); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + if (mysql_ping($this->conn_id) === FALSE) + { + $this->conn_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + return @mysql_select_db($this->database, $this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + if ( ! isset($this->use_set_names)) + { + // mysql_set_charset() requires PHP >= 5.2.3 and MySQL >= 5.0.7, use SET NAMES as fallback + $this->use_set_names = (version_compare(PHP_VERSION, '5.2.3', '>=') && version_compare(mysql_get_server_info(), '5.0.7', '>=')) ? FALSE : TRUE; + } + + if ($this->use_set_names === TRUE) + { + return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id); + } + else + { + return @mysql_set_charset($charset, $this->conn_id); + } + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + return "SELECT version() AS ver"; + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return @mysql_query($sql, $this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + // "DELETE FROM TABLE" returns 0 affected rows This hack modifies + // the query so that it returns the number of affected rows + if ($this->delete_hack === TRUE) + { + if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql)) + { + $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql); + } + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + $this->simple_query('SET AUTOCOMMIT=0'); + $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $this->simple_query('COMMIT'); + $this->simple_query('SET AUTOCOMMIT=1'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $this->simple_query('ROLLBACK'); + $this->simple_query('SET AUTOCOMMIT=1'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + if (function_exists('mysql_real_escape_string') AND is_resource($this->conn_id)) + { + $str = mysql_real_escape_string($str, $this->conn_id); + } + elseif (function_exists('mysql_escape_string')) + { + $str = mysql_escape_string($str); + } + else + { + $str = addslashes($str); + } + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @mysql_affected_rows($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id() + { + return @mysql_insert_id($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * List table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'"; + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "DESCRIBE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + return mysql_error($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return mysql_errno($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return '('.implode(', ', $tables).')'; + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + + /** + * Replace statement + * + * Generates a platform-specific replace string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _replace($table, $keys, $values) + { + return "REPLACE INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key . ' = ' . $val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + // -------------------------------------------------------------------- + + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @return string + */ + function _update_batch($table, $values, $index, $where = NULL) + { + $ids = array(); + $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field != $index) + { + $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $sql = "UPDATE ".$table." SET "; + $cases = ''; + + foreach ($final as $k => $v) + { + $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) + { + $cases .= $row."\n"; + } + + $cases .= 'ELSE '.$k.' END, '; + } + + $sql .= substr($cases, 0, -2); + + $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + + return $sql; + } + + // -------------------------------------------------------------------- + + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return "TRUNCATE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + if ($offset == 0) + { + $offset = ''; + } + else + { + $offset .= ", "; + } + + return $sql."LIMIT ".$offset.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @mysql_close($conn_id); + } + +} + + +/* End of file mysql_driver.php */ +/* Location: ./system/database/drivers/mysql/mysql_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php new file mode 100644 index 0000000..c1cae13 --- /dev/null +++ b/system/database/drivers/mysql/mysql_forge.php @@ -0,0 +1,273 @@ +$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + if (array_key_exists('NAME', $attributes)) + { + $sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' '; + } + + if (array_key_exists('TYPE', $attributes)) + { + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + switch ($attributes['TYPE']) + { + case 'decimal': + case 'float': + case 'numeric': + $sql .= '('.implode(',', $attributes['CONSTRAINT']).')'; + break; + + case 'enum': + case 'set': + $sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")'; + break; + + default: + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + } + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param mixed the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + + $sql .= $this->_process_fields($fields); + + if (count($primary_keys) > 0) + { + $key_name = $this->db->_protect_identifiers(implode('_', $primary_keys)); + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY ".$key_name." (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key_name = $this->db->_protect_identifiers(implode('_', $key)); + $key = $this->db->_protect_identifiers($key); + } + else + { + $key_name = $this->db->_protect_identifiers($key); + $key = array($key_name); + } + + $sql .= ",\n\tKEY {$key_name} (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n) DEFAULT CHARACTER SET {$this->db->char_set} COLLATE {$this->db->dbcollat};"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return string + */ + function _drop_table($table) + { + return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param array fields + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $fields, $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type "; + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql.$this->db->_protect_identifiers($fields); + } + + $sql .= $this->_process_fields($fields); + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + +} + +/* End of file mysql_forge.php */ +/* Location: ./system/database/drivers/mysql/mysql_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php new file mode 100644 index 0000000..e1a6e93 --- /dev/null +++ b/system/database/drivers/mysql/mysql_result.php @@ -0,0 +1,174 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @mysql_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + $field_names = array(); + while ($field = mysql_fetch_field($this->result_id)) + { + $field_names[] = $field->name; + } + + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + while ($field = mysql_fetch_object($this->result_id)) + { + preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches); + + $type = (array_key_exists(1, $matches)) ? $matches[1] : NULL; + $length = (array_key_exists(2, $matches)) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL; + + $F = new stdClass(); + $F->name = $field->Field; + $F->type = $type; + $F->default = $field->Default; + $F->max_length = $length; + $F->primary_key = ( $field->Key == 'PRI' ? 1 : 0 ); + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_resource($this->result_id)) + { + mysql_free_result($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return mysql_data_seek($this->result_id, $n); + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return mysql_fetch_assoc($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return mysql_fetch_object($this->result_id); + } + +} + + +/* End of file mysql_result.php */ +/* Location: ./system/database/drivers/mysql/mysql_result.php */ \ No newline at end of file diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php new file mode 100644 index 0000000..48c4d63 --- /dev/null +++ b/system/database/drivers/mysql/mysql_utility.php @@ -0,0 +1,210 @@ +db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Repair table query + * + * Generates a platform-specific query so that a table can be repaired + * + * @access private + * @param string the table name + * @return object + */ + function _repair_table($table) + { + return "REPAIR TABLE ".$this->db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + /** + * MySQL Export + * + * @access private + * @param array Preferences + * @return mixed + */ + function _backup($params = array()) + { + if (count($params) == 0) + { + return FALSE; + } + + // Extract the prefs for simplicity + extract($params); + + // Build the output + $output = ''; + foreach ((array)$tables as $table) + { + // Is the table in the "ignore" list? + if (in_array($table, (array)$ignore, TRUE)) + { + continue; + } + + // Get the table schema + $query = $this->db->query("SHOW CREATE TABLE `".$this->db->database.'`.`'.$table.'`'); + + // No result means the table name was invalid + if ($query === FALSE) + { + continue; + } + + // Write out the table schema + $output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline; + + if ($add_drop == TRUE) + { + $output .= 'DROP TABLE IF EXISTS '.$table.';'.$newline.$newline; + } + + $i = 0; + $result = $query->result_array(); + foreach ($result[0] as $val) + { + if ($i++ % 2) + { + $output .= $val.';'.$newline.$newline; + } + } + + // If inserts are not needed we're done... + if ($add_insert == FALSE) + { + continue; + } + + // Grab all the data from the current table + $query = $this->db->query("SELECT * FROM $table"); + + if ($query->num_rows() == 0) + { + continue; + } + + // Fetch the field names and determine if the field is an + // integer type. We use this info to decide whether to + // surround the data with quotes or not + + $i = 0; + $field_str = ''; + $is_int = array(); + while ($field = mysql_fetch_field($query->result_id)) + { + // Most versions of MySQL store timestamp as a string + $is_int[$i] = (in_array( + strtolower(mysql_field_type($query->result_id, $i)), + array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'), + TRUE) + ) ? TRUE : FALSE; + + // Create a string of field names + $field_str .= '`'.$field->name.'`, '; + $i++; + } + + // Trim off the end comma + $field_str = preg_replace( "/, $/" , "" , $field_str); + + + // Build the insert string + foreach ($query->result_array() as $row) + { + $val_str = ''; + + $i = 0; + foreach ($row as $v) + { + // Is the value NULL? + if ($v === NULL) + { + $val_str .= 'NULL'; + } + else + { + // Escape the data if it's not an integer + if ($is_int[$i] == FALSE) + { + $val_str .= $this->db->escape($v); + } + else + { + $val_str .= $v; + } + } + + // Append a comma + $val_str .= ', '; + $i++; + } + + // Remove the comma at the end of the string + $val_str = preg_replace( "/, $/" , "" , $val_str); + + // Build the INSERT string + $output .= 'INSERT INTO '.$table.' ('.$field_str.') VALUES ('.$val_str.');'.$newline; + } + + $output .= $newline.$newline; + } + + return $output; + } +} + +/* End of file mysql_utility.php */ +/* Location: ./system/database/drivers/mysql/mysql_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/mysqli/index.html b/system/database/drivers/mysqli/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/mysqli/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php new file mode 100644 index 0000000..d3200f3 --- /dev/null +++ b/system/database/drivers/mysqli/mysqli_driver.php @@ -0,0 +1,776 @@ +port != '') + { + return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database, $this->port); + } + else + { + return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database); + } + + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + return $this->db_connect(); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + if (mysqli_ping($this->conn_id) === FALSE) + { + $this->conn_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + return @mysqli_select_db($this->conn_id, $this->database); + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access private + * @param string + * @param string + * @return resource + */ + function _db_set_charset($charset, $collation) + { + if ( ! isset($this->use_set_names)) + { + // mysqli_set_charset() requires MySQL >= 5.0.7, use SET NAMES as fallback + $this->use_set_names = (version_compare(mysqli_get_server_info($this->conn_id), '5.0.7', '>=')) ? FALSE : TRUE; + } + + if ($this->use_set_names === TRUE) + { + return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'"); + } + else + { + return @mysqli_set_charset($this->conn_id, $charset); + } + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + return "SELECT version() AS ver"; + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + $result = @mysqli_query($this->conn_id, $sql); + return $result; + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + // "DELETE FROM TABLE" returns 0 affected rows This hack modifies + // the query so that it returns the number of affected rows + if ($this->delete_hack === TRUE) + { + if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql)) + { + $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql); + } + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + $this->simple_query('SET AUTOCOMMIT=0'); + $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $this->simple_query('COMMIT'); + $this->simple_query('SET AUTOCOMMIT=1'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $this->simple_query('ROLLBACK'); + $this->simple_query('SET AUTOCOMMIT=1'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + if (function_exists('mysqli_real_escape_string') AND is_object($this->conn_id)) + { + $str = mysqli_real_escape_string($this->conn_id, $str); + } + elseif (function_exists('mysql_escape_string')) + { + $str = mysql_escape_string($str); + } + else + { + $str = addslashes($str); + } + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @mysqli_affected_rows($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id() + { + return @mysqli_insert_id($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * List table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'"; + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "DESCRIBE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + return mysqli_error($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return mysqli_errno($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return '('.implode(', ', $tables).')'; + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + + /** + * Replace statement + * + * Generates a platform-specific replace string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _replace($table, $keys, $values) + { + return "REPLACE INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @return string + */ + function _update_batch($table, $values, $index, $where = NULL) + { + $ids = array(); + $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field != $index) + { + $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $sql = "UPDATE ".$table." SET "; + $cases = ''; + + foreach ($final as $k => $v) + { + $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) + { + $cases .= $row."\n"; + } + + $cases .= 'ELSE '.$k.' END, '; + } + + $sql .= substr($cases, 0, -2); + + $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return "TRUNCATE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + $sql .= "LIMIT ".$limit; + + if ($offset > 0) + { + $sql .= " OFFSET ".$offset; + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @mysqli_close($conn_id); + } + + +} + + +/* End of file mysqli_driver.php */ +/* Location: ./system/database/drivers/mysqli/mysqli_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php new file mode 100644 index 0000000..2605494 --- /dev/null +++ b/system/database/drivers/mysqli/mysqli_forge.php @@ -0,0 +1,258 @@ +$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + if (array_key_exists('NAME', $attributes)) + { + $sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' '; + } + + if (array_key_exists('TYPE', $attributes)) + { + $sql .= ' '.$attributes['TYPE']; + } + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param mixed the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + + $sql .= $this->_process_fields($fields); + + if (count($primary_keys) > 0) + { + $key_name = $this->db->_protect_identifiers(implode('_', $primary_keys)); + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY ".$key_name." (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key_name = $this->db->_protect_identifiers(implode('_', $key)); + $key = $this->db->_protect_identifiers($key); + } + else + { + $key_name = $this->db->_protect_identifiers($key); + $key = array($key_name); + } + + $sql .= ",\n\tKEY {$key_name} (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n) DEFAULT CHARACTER SET {$this->db->char_set} COLLATE {$this->db->dbcollat};"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return string + */ + function _drop_table($table) + { + return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param array fields + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $fields, $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type "; + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql.$this->db->_protect_identifiers($fields); + } + + $sql .= $this->_process_fields($fields); + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + +} + +/* End of file mysqli_forge.php */ +/* Location: ./system/database/drivers/mysqli/mysqli_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php new file mode 100644 index 0000000..124d4e5 --- /dev/null +++ b/system/database/drivers/mysqli/mysqli_result.php @@ -0,0 +1,174 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @mysqli_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + $field_names = array(); + while ($field = mysqli_fetch_field($this->result_id)) + { + $field_names[] = $field->name; + } + + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + while ($field = mysqli_fetch_object($this->result_id)) + { + preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches); + + $type = (array_key_exists(1, $matches)) ? $matches[1] : NULL; + $length = (array_key_exists(2, $matches)) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL; + + $F = new stdClass(); + $F->name = $field->Field; + $F->type = $type; + $F->default = $field->Default; + $F->max_length = $length; + $F->primary_key = ( $field->Key == 'PRI' ? 1 : 0 ); + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_object($this->result_id)) + { + mysqli_free_result($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return mysqli_data_seek($this->result_id, $n); + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return mysqli_fetch_assoc($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return mysqli_fetch_object($this->result_id); + } + +} + + +/* End of file mysqli_result.php */ +/* Location: ./system/database/drivers/mysqli/mysqli_result.php */ \ No newline at end of file diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php new file mode 100644 index 0000000..e17889b --- /dev/null +++ b/system/database/drivers/mysqli/mysqli_utility.php @@ -0,0 +1,87 @@ +db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Repair table query + * + * Generates a platform-specific query so that a table can be repaired + * + * @access private + * @param string the table name + * @return object + */ + function _repair_table($table) + { + return "REPAIR TABLE ".$this->db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * MySQLi Export + * + * @access private + * @param array Preferences + * @return mixed + */ + function _backup($params = array()) + { + // Currently unsupported + return $this->db->display_error('db_unsuported_feature'); + } +} + +/* End of file mysqli_utility.php */ +/* Location: ./system/database/drivers/mysqli/mysqli_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/oci8/index.html b/system/database/drivers/oci8/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/oci8/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php new file mode 100644 index 0000000..930177e --- /dev/null +++ b/system/database/drivers/oci8/oci8_driver.php @@ -0,0 +1,808 @@ +username, $this->password, $this->hostname, $this->char_set); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + public function db_pconnect() + { + return @oci_pconnect($this->username, $this->password, $this->hostname, $this->char_set); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + public function reconnect() + { + // not implemented in oracle + return; + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + public function db_select() + { + // Not in Oracle - schemas are actually usernames + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + public function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access protected + * @return string + */ + protected function _version() + { + return oci_server_version($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access protected called by the base class + * @param string an SQL query + * @return resource + */ + protected function _execute($sql) + { + // oracle must parse the query before it is run. All of the actions with + // the query are based on the statement id returned by ociparse + $this->stmt_id = FALSE; + $this->_set_stmt_id($sql); + oci_set_prefetch($this->stmt_id, 1000); + return @oci_execute($this->stmt_id, $this->_commit); + } + + /** + * Generate a statement ID + * + * @access private + * @param string an SQL query + * @return none + */ + private function _set_stmt_id($sql) + { + if ( ! is_resource($this->stmt_id)) + { + $this->stmt_id = oci_parse($this->conn_id, $this->_prep_query($sql)); + } + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + private function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * getCursor. Returns a cursor from the datbase + * + * @access public + * @return cursor id + */ + public function get_cursor() + { + $this->curs_id = oci_new_cursor($this->conn_id); + return $this->curs_id; + } + + // -------------------------------------------------------------------- + + /** + * Stored Procedure. Executes a stored procedure + * + * @access public + * @param package package stored procedure is in + * @param procedure stored procedure to execute + * @param params array of parameters + * @return array + * + * params array keys + * + * KEY OPTIONAL NOTES + * name no the name of the parameter should be in : format + * value no the value of the parameter. If this is an OUT or IN OUT parameter, + * this should be a reference to a variable + * type yes the type of the parameter + * length yes the max size of the parameter + */ + public function stored_procedure($package, $procedure, $params) + { + if ($package == '' OR $procedure == '' OR ! is_array($params)) + { + if ($this->db_debug) + { + log_message('error', 'Invalid query: '.$package.'.'.$procedure); + return $this->display_error('db_invalid_query'); + } + return FALSE; + } + + // build the query string + $sql = "begin $package.$procedure("; + + $have_cursor = FALSE; + foreach ($params as $param) + { + $sql .= $param['name'] . ","; + + if (array_key_exists('type', $param) && ($param['type'] === OCI_B_CURSOR)) + { + $have_cursor = TRUE; + } + } + $sql = trim($sql, ",") . "); end;"; + + $this->stmt_id = FALSE; + $this->_set_stmt_id($sql); + $this->_bind_params($params); + $this->query($sql, FALSE, $have_cursor); + } + + // -------------------------------------------------------------------- + + /** + * Bind parameters + * + * @access private + * @return none + */ + private function _bind_params($params) + { + if ( ! is_array($params) OR ! is_resource($this->stmt_id)) + { + return; + } + + foreach ($params as $param) + { + foreach (array('name', 'value', 'type', 'length') as $val) + { + if ( ! isset($param[$val])) + { + $param[$val] = ''; + } + } + + oci_bind_by_name($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']); + } + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + public function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + $this->_commit = OCI_DEFAULT; + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + public function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $ret = oci_commit($this->conn_id); + $this->_commit = OCI_COMMIT_ON_SUCCESS; + return $ret; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + public function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $ret = oci_rollback($this->conn_id); + $this->_commit = OCI_COMMIT_ON_SUCCESS; + return $ret; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + public function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + $str = remove_invisible_characters($str); + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace( array('%', '_', $this->_like_escape_chr), + array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), + $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + public function affected_rows() + { + return @oci_num_rows($this->stmt_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + public function insert_id() + { + // not supported in oracle + return $this->display_error('db_unsupported_function'); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + public function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query == FALSE) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access protected + * @param boolean + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = "SELECT TABLE_NAME FROM ALL_TABLES"; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + $sql .= " WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access protected + * @param string the table name + * @return string + */ + protected function _list_columns($table = '') + { + return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'"; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + protected function _field_data($table) + { + return "SELECT * FROM ".$table." where rownum = 1"; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access protected + * @return string + */ + protected function _error_message() + { + // If the error was during connection, no conn_id should be passed + $error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error(); + return $error['message']; + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access protected + * @return integer + */ + protected function _error_number() + { + // Same as _error_message() + $error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error(); + return $error['code']; + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access protected + * @param string + * @return string + */ + protected function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access protected + * @param type + * @return type + */ + protected function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return implode(', ', $tables); + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + protected function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access protected + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + protected function _insert_batch($table, $keys, $values) + { + $keys = implode(', ', $keys); + $sql = "INSERT ALL\n"; + + for ($i = 0, $c = count($values); $i < $c; $i++) + { + $sql .= ' INTO ' . $table . ' (' . $keys . ') VALUES ' . $values[$i] . "\n"; + } + + $sql .= 'SELECT * FROM dual'; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access protected + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access protected + * @param string the table name + * @return string + */ + protected function _truncate($table) + { + return "TRUNCATE TABLE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access protected + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + protected function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access protected + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + protected function _limit($sql, $limit, $offset) + { + $limit = $offset + $limit; + $newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)"; + + if ($offset != 0) + { + $newsql .= " WHERE rnum >= $offset"; + } + + // remember that we used limits + $this->limit_used = TRUE; + + return $newsql; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access protected + * @param resource + * @return void + */ + protected function _close($conn_id) + { + @oci_close($conn_id); + } + + +} + + + +/* End of file oci8_driver.php */ +/* Location: ./system/database/drivers/oci8/oci8_driver.php */ diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php new file mode 100644 index 0000000..3cd1758 --- /dev/null +++ b/system/database/drivers/oci8/oci8_forge.php @@ -0,0 +1,248 @@ +db->_escape_identifiers($table)." ("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + $sql .= ",\n\tUNIQUE COLUMNS (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n)"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return bool + */ + function _drop_table($table) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + + +} + +/* End of file oci8_forge.php */ +/* Location: ./system/database/drivers/oci8/oci8_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php new file mode 100644 index 0000000..3421278 --- /dev/null +++ b/system/database/drivers/oci8/oci8_result.php @@ -0,0 +1,217 @@ +num_rows === 0 && count($this->result_array()) > 0) + { + $this->num_rows = count($this->result_array()); + @oci_execute($this->stmt_id); + + if ($this->curs_id) + { + @oci_execute($this->curs_id); + } + } + + return $this->num_rows; + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + public function num_fields() + { + $count = @oci_num_fields($this->stmt_id); + + // if we used a limit we subtract it + if ($this->limit_used) + { + $count = $count - 1; + } + + return $count; + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + public function list_fields() + { + $field_names = array(); + for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++) + { + $field_names[] = oci_field_name($this->stmt_id, $c); + } + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + public function field_data() + { + $retval = array(); + for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++) + { + $F = new stdClass(); + $F->name = oci_field_name($this->stmt_id, $c); + $F->type = oci_field_type($this->stmt_id, $c); + $F->max_length = oci_field_size($this->stmt_id, $c); + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + public function free_result() + { + if (is_resource($this->result_id)) + { + oci_free_statement($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access protected + * @return array + */ + protected function _fetch_assoc() + { + $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; + return oci_fetch_assoc($id); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access protected + * @return object + */ + protected function _fetch_object() + { + $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; + return @oci_fetch_object($id); + } + + // -------------------------------------------------------------------- + + /** + * Query result. "array" version. + * + * @access public + * @return array + */ + public function result_array() + { + if (count($this->result_array) > 0) + { + return $this->result_array; + } + + $row = NULL; + while ($row = $this->_fetch_assoc()) + { + $this->result_array[] = $row; + } + + return $this->result_array; + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access protected + * @return array + */ + protected function _data_seek($n = 0) + { + return FALSE; // Not needed + } + +} + + +/* End of file oci8_result.php */ +/* Location: ./system/database/drivers/oci8/oci8_result.php */ diff --git a/system/database/drivers/oci8/oci8_utility.php b/system/database/drivers/oci8/oci8_utility.php new file mode 100644 index 0000000..854b467 --- /dev/null +++ b/system/database/drivers/oci8/oci8_utility.php @@ -0,0 +1,87 @@ +db->display_error('db_unsuported_feature'); + } +} + +/* End of file oci8_utility.php */ +/* Location: ./system/database/drivers/oci8/oci8_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/odbc/index.html b/system/database/drivers/odbc/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/odbc/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php new file mode 100644 index 0000000..bcd7937 --- /dev/null +++ b/system/database/drivers/odbc/odbc_driver.php @@ -0,0 +1,637 @@ +_random_keyword = ' RND('.time().')'; // database specific random keyword + } + + /** + * Non-persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_connect() + { + return @odbc_connect($this->hostname, $this->username, $this->password); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + return @odbc_pconnect($this->hostname, $this->username, $this->password); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + // not implemented in odbc + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + // Not needed for ODBC + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + return "SELECT version() AS ver"; + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return @odbc_exec($this->conn_id, $sql); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + return odbc_autocommit($this->conn_id, FALSE); + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $ret = odbc_commit($this->conn_id); + odbc_autocommit($this->conn_id, TRUE); + return $ret; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $ret = odbc_rollback($this->conn_id); + odbc_autocommit($this->conn_id, TRUE); + return $ret; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + // ODBC doesn't require escaping + $str = remove_invisible_characters($str); + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace( array('%', '_', $this->_like_escape_chr), + array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), + $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @odbc_num_rows($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id() + { + return @odbc_insert_id($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SHOW TABLES FROM `".$this->database."`"; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + return FALSE; // not currently supported + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SHOW COLUMNS FROM ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT TOP 1 FROM ".$table; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + return odbc_errormsg($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return odbc_error($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return '('.implode(', ', $tables).')'; + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return $this->_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + // Does ODBC doesn't use the LIMIT clause? + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @odbc_close($conn_id); + } + + +} + + + +/* End of file odbc_driver.php */ +/* Location: ./system/database/drivers/odbc/odbc_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php new file mode 100644 index 0000000..3ec86b4 --- /dev/null +++ b/system/database/drivers/odbc/odbc_forge.php @@ -0,0 +1,266 @@ +db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + // ODBC has no "drop database" command since it's + // designed to connect to an existing database + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param array the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n)"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return bool + */ + function _drop_table($table) + { + // Not a supported ODBC feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + + +} + +/* End of file odbc_forge.php */ +/* Location: ./system/database/drivers/odbc/odbc_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php new file mode 100644 index 0000000..5d64a46 --- /dev/null +++ b/system/database/drivers/odbc/odbc_result.php @@ -0,0 +1,228 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @odbc_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + $field_names = array(); + for ($i = 0; $i < $this->num_fields(); $i++) + { + $field_names[] = odbc_field_name($this->result_id, $i); + } + + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + for ($i = 0; $i < $this->num_fields(); $i++) + { + $F = new stdClass(); + $F->name = odbc_field_name($this->result_id, $i); + $F->type = odbc_field_type($this->result_id, $i); + $F->max_length = odbc_field_len($this->result_id, $i); + $F->primary_key = 0; + $F->default = ''; + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_resource($this->result_id)) + { + odbc_free_result($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + if (function_exists('odbc_fetch_object')) + { + return odbc_fetch_array($this->result_id); + } + else + { + return $this->_odbc_fetch_array($this->result_id); + } + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + if (function_exists('odbc_fetch_object')) + { + return odbc_fetch_object($this->result_id); + } + else + { + return $this->_odbc_fetch_object($this->result_id); + } + } + + + /** + * Result - object + * + * subsititutes the odbc_fetch_object function when + * not available (odbc_fetch_object requires unixODBC) + * + * @access private + * @return object + */ + function _odbc_fetch_object(& $odbc_result) { + $rs = array(); + $rs_obj = FALSE; + if (odbc_fetch_into($odbc_result, $rs)) { + foreach ($rs as $k=>$v) { + $field_name= odbc_field_name($odbc_result, $k+1); + $rs_obj->$field_name = $v; + } + } + return $rs_obj; + } + + + /** + * Result - array + * + * subsititutes the odbc_fetch_array function when + * not available (odbc_fetch_array requires unixODBC) + * + * @access private + * @return array + */ + function _odbc_fetch_array(& $odbc_result) { + $rs = array(); + $rs_assoc = FALSE; + if (odbc_fetch_into($odbc_result, $rs)) { + $rs_assoc=array(); + foreach ($rs as $k=>$v) { + $field_name= odbc_field_name($odbc_result, $k+1); + $rs_assoc[$field_name] = $v; + } + } + return $rs_assoc; + } + +} + + +/* End of file odbc_result.php */ +/* Location: ./system/database/drivers/odbc/odbc_result.php */ \ No newline at end of file diff --git a/system/database/drivers/odbc/odbc_utility.php b/system/database/drivers/odbc/odbc_utility.php new file mode 100644 index 0000000..d335bed --- /dev/null +++ b/system/database/drivers/odbc/odbc_utility.php @@ -0,0 +1,103 @@ +db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Optimize table query + * + * Generates a platform-specific query so that a table can be optimized + * + * @access private + * @param string the table name + * @return object + */ + function _optimize_table($table) + { + // Not a supported ODBC feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Repair table query + * + * Generates a platform-specific query so that a table can be repaired + * + * @access private + * @param string the table name + * @return object + */ + function _repair_table($table) + { + // Not a supported ODBC feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * ODBC Export + * + * @access private + * @param array Preferences + * @return mixed + */ + function _backup($params = array()) + { + // Currently unsupported + return $this->db->display_error('db_unsuported_feature'); + } + +} + +/* End of file odbc_utility.php */ +/* Location: ./system/database/drivers/odbc/odbc_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/pdo/index.html b/system/database/drivers/pdo/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/pdo/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php new file mode 100644 index 0000000..1ecc90a --- /dev/null +++ b/system/database/drivers/pdo/pdo_driver.php @@ -0,0 +1,812 @@ +hostname, 'mysql') !== FALSE) + { + $this->_like_escape_str = ''; + $this->_like_escape_chr = ''; + + //Prior to this version, the charset can't be set in the dsn + if(is_php('5.3.6')) + { + $this->hostname .= ";charset={$this->char_set}"; + } + + //Set the charset with the connection options + $this->options['PDO::MYSQL_ATTR_INIT_COMMAND'] = "SET NAMES {$this->char_set}"; + } + elseif (strpos($this->hostname, 'odbc') !== FALSE) + { + $this->_like_escape_str = " {escape '%s'} "; + $this->_like_escape_chr = '!'; + } + else + { + $this->_like_escape_str = " ESCAPE '%s' "; + $this->_like_escape_chr = '!'; + } + + empty($this->database) OR $this->hostname .= ';dbname='.$this->database; + + $this->trans_enabled = FALSE; + + $this->_random_keyword = ' RND('.time().')'; // database specific random keyword + } + + /** + * Non-persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_connect() + { + $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT; + + return new PDO($this->hostname, $this->username, $this->password, $this->options); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT; + $this->options['PDO::ATTR_PERSISTENT'] = TRUE; + + return new PDO($this->hostname, $this->username, $this->password, $this->options); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + // Not needed for PDO + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + return $this->conn_id->getAttribute(PDO::ATTR_CLIENT_VERSION); + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return object + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + $result_id = $this->conn_id->prepare($sql); + $result_id->execute(); + + if (is_object($result_id)) + { + if (is_numeric(stripos($sql, 'SELECT'))) + { + $this->affect_rows = count($result_id->fetchAll()); + $result_id->execute(); + } + else + { + $this->affect_rows = $result_id->rowCount(); + } + } + else + { + $this->affect_rows = 0; + } + + return $result_id; + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = (bool) ($test_mode === TRUE); + + return $this->conn_id->beginTransaction(); + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $ret = $this->conn->commit(); + return $ret; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $ret = $this->conn_id->rollBack(); + return $ret; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + //Escape the string + $str = $this->conn_id->quote($str); + + //If there are duplicated quotes, trim them away + if (strpos($str, "'") === 0) + { + $str = substr($str, 1, -1); + } + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace( array('%', '_', $this->_like_escape_chr), + array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), + $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return $this->affect_rows; + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id($name=NULL) + { + //Convenience method for postgres insertid + if (strpos($this->hostname, 'pgsql') !== FALSE) + { + $v = $this->_version(); + + $table = func_num_args() > 0 ? func_get_arg(0) : NULL; + + if ($table == NULL && $v >= '8.1') + { + $sql='SELECT LASTVAL() as ins_id'; + } + $query = $this->query($sql); + $row = $query->row(); + return $row->ins_id; + } + else + { + return $this->conn_id->lastInsertId($name); + } + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SHOW TABLES FROM `".$this->database."`"; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + return FALSE; // not currently supported + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SHOW COLUMNS FROM ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT TOP 1 FROM ".$table; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + $error_array = $this->conn_id->errorInfo(); + return $error_array[2]; + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return $this->conn_id->errorCode(); + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return (count($tables) == 1) ? $tables[0] : '('.implode(', ', $tables).')'; + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @return string + */ + function _update_batch($table, $values, $index, $where = NULL) + { + $ids = array(); + $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field != $index) + { + $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $sql = "UPDATE ".$table." SET "; + $cases = ''; + + foreach ($final as $k => $v) + { + $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) + { + $cases .= $row."\n"; + } + + $cases .= 'ELSE '.$k.' END, '; + } + + $sql .= substr($cases, 0, -2); + + $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + + return $sql; + } + + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return $this->_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + if (strpos($this->hostname, 'cubrid') !== FALSE || strpos($this->hostname, 'sqlite') !== FALSE) + { + if ($offset == 0) + { + $offset = ''; + } + else + { + $offset .= ", "; + } + + return $sql."LIMIT ".$offset.$limit; + } + else + { + $sql .= "LIMIT ".$limit; + + if ($offset > 0) + { + $sql .= " OFFSET ".$offset; + } + + return $sql; + } + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + $this->conn_id = null; + } + + +} + + + +/* End of file pdo_driver.php */ +/* Location: ./system/database/drivers/pdo/pdo_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php new file mode 100644 index 0000000..9a78220 --- /dev/null +++ b/system/database/drivers/pdo/pdo_forge.php @@ -0,0 +1,266 @@ +db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + // PDO has no "drop database" command since it's + // designed to connect to an existing database + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param array the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n)"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return bool + */ + function _drop_table($table) + { + // Not a supported PDO feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + + +} + +/* End of file pdo_forge.php */ +/* Location: ./system/database/drivers/pdo/pdo_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php new file mode 100644 index 0000000..44fdd6d --- /dev/null +++ b/system/database/drivers/pdo/pdo_result.php @@ -0,0 +1,183 @@ +num_rows)) + { + return $this->num_rows; + } + elseif (($this->num_rows = $this->result_id->rowCount()) > 0) + { + return $this->num_rows; + } + + $this->num_rows = count($this->result_id->fetchAll()); + $this->result_id->execute(); + return $this->num_rows; + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return $this->result_id->columnCount(); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $data = array(); + + try + { + for($i = 0; $i < $this->num_fields(); $i++) + { + $data[] = $this->result_id->getColumnMeta($i); + } + + return $data; + } + catch (Exception $e) + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_object($this->result_id)) + { + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return $this->result_id->fetch(PDO::FETCH_ASSOC); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return $this->result_id->fetchObject(); + } + +} + + +/* End of file pdo_result.php */ +/* Location: ./system/database/drivers/pdo/pdo_result.php */ \ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_utility.php b/system/database/drivers/pdo/pdo_utility.php new file mode 100644 index 0000000..88ce033 --- /dev/null +++ b/system/database/drivers/pdo/pdo_utility.php @@ -0,0 +1,103 @@ +db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Optimize table query + * + * Generates a platform-specific query so that a table can be optimized + * + * @access private + * @param string the table name + * @return object + */ + function _optimize_table($table) + { + // Not a supported PDO feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Repair table query + * + * Generates a platform-specific query so that a table can be repaired + * + * @access private + * @param string the table name + * @return object + */ + function _repair_table($table) + { + // Not a supported PDO feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * PDO Export + * + * @access private + * @param array Preferences + * @return mixed + */ + function _backup($params = array()) + { + // Currently unsupported + return $this->db->display_error('db_unsuported_feature'); + } + +} + +/* End of file pdo_utility.php */ +/* Location: ./system/database/drivers/pdo/pdo_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/postgre/index.html b/system/database/drivers/postgre/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/postgre/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php new file mode 100644 index 0000000..5367f97 --- /dev/null +++ b/system/database/drivers/postgre/postgre_driver.php @@ -0,0 +1,703 @@ + 'host', + 'port' => 'port', + 'database' => 'dbname', + 'username' => 'user', + 'password' => 'password' + ); + + $connect_string = ""; + foreach ($components as $key => $val) + { + if (isset($this->$key) && $this->$key != '') + { + $connect_string .= " $val=".$this->$key; + } + } + return trim($connect_string); + } + + // -------------------------------------------------------------------- + + /** + * Non-persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_connect() + { + return @pg_connect($this->_connect_string()); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + return @pg_pconnect($this->_connect_string()); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + if (pg_ping($this->conn_id) === FALSE) + { + $this->conn_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + // Not needed for Postgre so we'll return TRUE + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + return "SELECT version() AS ver"; + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return @pg_query($this->conn_id, $sql); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + return @pg_exec($this->conn_id, "begin"); + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + return @pg_exec($this->conn_id, "commit"); + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + return @pg_exec($this->conn_id, "rollback"); + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + $str = pg_escape_string($str); + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace( array('%', '_', $this->_like_escape_chr), + array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), + $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @pg_affected_rows($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id() + { + $v = $this->_version(); + $v = $v['server']; + + $table = func_num_args() > 0 ? func_get_arg(0) : NULL; + $column = func_num_args() > 1 ? func_get_arg(1) : NULL; + + if ($table == NULL && $v >= '8.1') + { + $sql='SELECT LASTVAL() as ins_id'; + } + elseif ($table != NULL && $column != NULL && $v >= '8.0') + { + $sql = sprintf("SELECT pg_get_serial_sequence('%s','%s') as seq", $table, $column); + $query = $this->query($sql); + $row = $query->row(); + $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $row->seq); + } + elseif ($table != NULL) + { + // seq_name passed in table parameter + $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $table); + } + else + { + return pg_last_oid($this->result_id); + } + $query = $this->query($sql); + $row = $query->row(); + return $row->ins_id; + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + $sql .= " AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$table."'"; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT * FROM ".$table." LIMIT 1"; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + return pg_last_error($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return ''; + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return implode(', ', $tables); + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return "TRUNCATE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + $sql .= "LIMIT ".$limit; + + if ($offset > 0) + { + $sql .= " OFFSET ".$offset; + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @pg_close($conn_id); + } + + +} + + +/* End of file postgre_driver.php */ +/* Location: ./system/database/drivers/postgre/postgre_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php new file mode 100644 index 0000000..91a1c68 --- /dev/null +++ b/system/database/drivers/postgre/postgre_forge.php @@ -0,0 +1,299 @@ +db->table_exists($table)) + { + return "SELECT * FROM $table"; // Needs to return innocous but valid SQL statement + } + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $is_unsigned = (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE); + + // Convert datatypes to be PostgreSQL-compatible + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + break; + case 'SMALLINT': + $attributes['TYPE'] = ($is_unsigned) ? 'INTEGER' : 'SMALLINT'; + break; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + break; + case 'INT': + $attributes['TYPE'] = ($is_unsigned) ? 'BIGINT' : 'INTEGER'; + break; + case 'BIGINT': + $attributes['TYPE'] = ($is_unsigned) ? 'NUMERIC' : 'BIGINT'; + break; + case 'DOUBLE': + $attributes['TYPE'] = 'DOUBLE PRECISION'; + break; + case 'DATETIME': + $attributes['TYPE'] = 'TIMESTAMP'; + break; + case 'LONGTEXT': + $attributes['TYPE'] = 'TEXT'; + break; + case 'BLOB': + $attributes['TYPE'] = 'BYTEA'; + break; + } + + // If this is an auto-incrementing primary key, use the serial data type instead + if (in_array($field, $primary_keys) && array_key_exists('AUTO_INCREMENT', $attributes) + && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' SERIAL'; + } + else + { + $sql .= ' '.$attributes['TYPE']; + } + + // Modified to prevent constraints with integer data types + if (array_key_exists('CONSTRAINT', $attributes) && strpos($attributes['TYPE'], 'INT') === false) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + // Added new attribute to create unqite fields. Also works with MySQL + if (array_key_exists('UNIQUE', $attributes) && $attributes['UNIQUE'] === TRUE) + { + $sql .= ' UNIQUE'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + // Something seems to break when passing an array to _protect_identifiers() + foreach ($primary_keys as $index => $key) + { + $primary_keys[$index] = $this->db->_protect_identifiers($key); + } + + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + $sql .= "\n);"; + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + foreach ($key as $field) + { + $sql .= "CREATE INDEX " . $table . "_" . str_replace(array('"', "'"), '', $field) . "_index ON $table ($field); "; + } + } + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return bool + */ + function _drop_table($table) + { + return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table)." CASCADE"; + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + + +} + +/* End of file postgre_forge.php */ +/* Location: ./system/database/drivers/postgre/postgre_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php new file mode 100644 index 0000000..e9a1d16 --- /dev/null +++ b/system/database/drivers/postgre/postgre_result.php @@ -0,0 +1,169 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @pg_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + $field_names = array(); + for ($i = 0; $i < $this->num_fields(); $i++) + { + $field_names[] = pg_field_name($this->result_id, $i); + } + + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + for ($i = 0; $i < $this->num_fields(); $i++) + { + $F = new stdClass(); + $F->name = pg_field_name($this->result_id, $i); + $F->type = pg_field_type($this->result_id, $i); + $F->max_length = pg_field_size($this->result_id, $i); + $F->primary_key = 0; + $F->default = ''; + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_resource($this->result_id)) + { + pg_free_result($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return pg_result_seek($this->result_id, $n); + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return pg_fetch_assoc($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return pg_fetch_object($this->result_id); + } + +} + + +/* End of file postgre_result.php */ +/* Location: ./system/database/drivers/postgre/postgre_result.php */ \ No newline at end of file diff --git a/system/database/drivers/postgre/postgre_utility.php b/system/database/drivers/postgre/postgre_utility.php new file mode 100644 index 0000000..741c52e --- /dev/null +++ b/system/database/drivers/postgre/postgre_utility.php @@ -0,0 +1,88 @@ +db->display_error('db_unsuported_feature'); + } +} + + +/* End of file postgre_utility.php */ +/* Location: ./system/database/drivers/postgre/postgre_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlite/index.html b/system/database/drivers/sqlite/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/sqlite/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php new file mode 100644 index 0000000..0cc898b --- /dev/null +++ b/system/database/drivers/sqlite/sqlite_driver.php @@ -0,0 +1,658 @@ +database, FILE_WRITE_MODE, $error)) + { + log_message('error', $error); + + if ($this->db_debug) + { + $this->display_error($error, '', TRUE); + } + + return FALSE; + } + + return $conn_id; + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + if ( ! $conn_id = @sqlite_popen($this->database, FILE_WRITE_MODE, $error)) + { + log_message('error', $error); + + if ($this->db_debug) + { + $this->display_error($error, '', TRUE); + } + + return FALSE; + } + + return $conn_id; + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + // not implemented in SQLite + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + return sqlite_libversion(); + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return @sqlite_query($this->conn_id, $sql); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + $this->simple_query('BEGIN TRANSACTION'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $this->simple_query('COMMIT'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $this->simple_query('ROLLBACK'); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + $str = sqlite_escape_string($str); + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace( array('%', '_', $this->_like_escape_chr), + array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), + $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return sqlite_changes($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id() + { + return @sqlite_last_insert_rowid($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * List table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SELECT name from sqlite_master WHERE type='table'"; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + $sql .= " AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + } + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + // Not supported + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT * FROM ".$table." LIMIT 1"; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + return sqlite_error_string(sqlite_last_error($this->conn_id)); + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return sqlite_last_error($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return '('.implode(', ', $tables).')'; + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return $this->_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + if ($offset == 0) + { + $offset = ''; + } + else + { + $offset .= ", "; + } + + return $sql."LIMIT ".$offset.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @sqlite_close($conn_id); + } + + +} + + +/* End of file sqlite_driver.php */ +/* Location: ./system/database/drivers/sqlite/sqlite_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php new file mode 100644 index 0000000..5690408 --- /dev/null +++ b/system/database/drivers/sqlite/sqlite_forge.php @@ -0,0 +1,265 @@ +db->database) OR ! @unlink($this->db->database)) + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unable_to_drop'); + } + return FALSE; + } + return TRUE; + } + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param array the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + // IF NOT EXISTS added to SQLite in 3.3.0 + if ($if_not_exists === TRUE && version_compare($this->db->_version(), '3.3.0', '>=') === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)."("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + $sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n)"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * Unsupported feature in SQLite + * + * @access private + * @return bool + */ + function _drop_table($table) + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return array(); + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + // SQLite does not support dropping columns + // http://www.sqlite.org/omitted.html + // http://www.sqlite.org/faq.html#q11 + return FALSE; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } +} + +/* End of file sqlite_forge.php */ +/* Location: ./system/database/drivers/sqlite/sqlite_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php new file mode 100644 index 0000000..7bd30db --- /dev/null +++ b/system/database/drivers/sqlite/sqlite_result.php @@ -0,0 +1,179 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @sqlite_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + $field_names = array(); + for ($i = 0; $i < $this->num_fields(); $i++) + { + $field_names[] = sqlite_field_name($this->result_id, $i); + } + + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + for ($i = 0; $i < $this->num_fields(); $i++) + { + $F = new stdClass(); + $F->name = sqlite_field_name($this->result_id, $i); + $F->type = 'varchar'; + $F->max_length = 0; + $F->primary_key = 0; + $F->default = ''; + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + // Not implemented in SQLite + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return sqlite_seek($this->result_id, $n); + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return sqlite_fetch_array($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + if (function_exists('sqlite_fetch_object')) + { + return sqlite_fetch_object($this->result_id); + } + else + { + $arr = sqlite_fetch_array($this->result_id, SQLITE_ASSOC); + if (is_array($arr)) + { + $obj = (object) $arr; + return $obj; + } else { + return NULL; + } + } + } + +} + + +/* End of file sqlite_result.php */ +/* Location: ./system/database/drivers/sqlite/sqlite_result.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlite/sqlite_utility.php b/system/database/drivers/sqlite/sqlite_utility.php new file mode 100644 index 0000000..508023e --- /dev/null +++ b/system/database/drivers/sqlite/sqlite_utility.php @@ -0,0 +1,96 @@ +db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return array(); + } + + // -------------------------------------------------------------------- + + /** + * Optimize table query + * + * Is optimization even supported in SQLite? + * + * @access private + * @param string the table name + * @return object + */ + function _optimize_table($table) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Repair table query + * + * Are table repairs even supported in SQLite? + * + * @access private + * @param string the table name + * @return object + */ + function _repair_table($table) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * SQLite Export + * + * @access private + * @param array Preferences + * @return mixed + */ + function _backup($params = array()) + { + // Currently unsupported + return $this->db->display_error('db_unsuported_feature'); + } +} + +/* End of file sqlite_utility.php */ +/* Location: ./system/database/drivers/sqlite/sqlite_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlsrv/index.html b/system/database/drivers/sqlsrv/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/drivers/sqlsrv/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php new file mode 100644 index 0000000..400fd31 --- /dev/null +++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php @@ -0,0 +1,599 @@ +char_set)) ? 'UTF-8' : $this->char_set; + + $connection = array( + 'UID' => empty($this->username) ? '' : $this->username, + 'PWD' => empty($this->password) ? '' : $this->password, + 'Database' => $this->database, + 'ConnectionPooling' => $pooling ? 1 : 0, + 'CharacterSet' => $character_set, + 'ReturnDatesAsStrings' => 1 + ); + + // If the username and password are both empty, assume this is a + // 'Windows Authentication Mode' connection. + if(empty($connection['UID']) && empty($connection['PWD'])) { + unset($connection['UID'], $connection['PWD']); + } + + return sqlsrv_connect($this->hostname, $connection); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + $this->db_connect(TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + // not implemented in MSSQL + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + return $this->_execute('USE ' . $this->database); + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return sqlsrv_query($this->conn_id, $sql, null, array( + 'Scrollable' => SQLSRV_CURSOR_STATIC, + 'SendStreamParamsAtExec' => true + )); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + return sqlsrv_begin_transaction($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + return sqlsrv_commit($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + return sqlsrv_rollback($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + // Escape single quotes + return str_replace("'", "''", $str); + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @sqlrv_rows_affected($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * Returns the last id created in the Identity column. + * + * @access public + * @return integer + */ + function insert_id() + { + return $this->query('select @@IDENTITY as insert_id')->row('insert_id'); + } + + // -------------------------------------------------------------------- + + /** + * Parse major version + * + * Grabs the major version number from the + * database server version string passed in. + * + * @access private + * @param string $version + * @return int16 major version number + */ + function _parse_major_version($version) + { + preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $version, $ver_info); + return $ver_info[1]; // return the major version b/c that's all we're interested in. + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + $info = sqlsrv_server_info($this->conn_id); + return sprintf("select '%s' as ver", $info['SQLServerVersion']); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + return '0'; + + $query = $this->query("SELECT COUNT(*) AS numrows FROM " . $this->dbprefix . $table); + + if ($query->num_rows() == 0) + return '0'; + + $row = $query->row(); + $this->_reset_select(); + return $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * List table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + return "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + } + + // -------------------------------------------------------------------- + + /** + * List column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access private + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$this->_escape_table($table)."'"; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT TOP 1 * FROM " . $this->_escape_table($table); + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + $error = array_shift(sqlsrv_errors()); + return !empty($error['message']) ? $error['message'] : null; + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + $error = array_shift(sqlsrv_errors()); + return isset($error['SQLSTATE']) ? $error['SQLSTATE'] : null; + } + + // -------------------------------------------------------------------- + + /** + * Escape Table Name + * + * This function adds backticks if the table name has a period + * in it. Some DBs will get cranky unless periods are escaped + * + * @access private + * @param string the table name + * @return string + */ + function _escape_table($table) + { + return $table; + } + + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + return $item; + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return implode(', ', $tables); + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where) + { + foreach($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + return "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr)." WHERE ".implode(" ", $where); + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return "TRUNCATE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where) + { + return "DELETE FROM ".$this->_escape_table($table)." WHERE ".implode(" ", $where); + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + $i = $limit + $offset; + + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql); + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @sqlsrv_close($conn_id); + } + +} + + + +/* End of file mssql_driver.php */ +/* Location: ./system/database/drivers/mssql/mssql_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php new file mode 100644 index 0000000..cc88ec5 --- /dev/null +++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php @@ -0,0 +1,248 @@ +db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param array the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n)"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + // I think this syntax will work, but can find little documentation on renaming tables in MSSQL + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + +} + +/* End of file mssql_forge.php */ +/* Location: ./system/database/drivers/mssql/mssql_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php new file mode 100644 index 0000000..bf0abd1 --- /dev/null +++ b/system/database/drivers/sqlsrv/sqlsrv_result.php @@ -0,0 +1,169 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @sqlsrv_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + $field_names = array(); + foreach(sqlsrv_field_metadata($this->result_id) as $offset => $field) + { + $field_names[] = $field['Name']; + } + + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + foreach(sqlsrv_field_metadata($this->result_id) as $offset => $field) + { + $F = new stdClass(); + $F->name = $field['Name']; + $F->type = $field['Type']; + $F->max_length = $field['Size']; + $F->primary_key = 0; + $F->default = ''; + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_resource($this->result_id)) + { + sqlsrv_free_stmt($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + // Not implemented + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return sqlsrv_fetch_array($this->result_id, SQLSRV_FETCH_ASSOC); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return sqlsrv_fetch_object($this->result_id); + } + +} + + +/* End of file mssql_result.php */ +/* Location: ./system/database/drivers/mssql/mssql_result.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlsrv/sqlsrv_utility.php b/system/database/drivers/sqlsrv/sqlsrv_utility.php new file mode 100644 index 0000000..13a1850 --- /dev/null +++ b/system/database/drivers/sqlsrv/sqlsrv_utility.php @@ -0,0 +1,88 @@ +db->display_error('db_unsuported_feature'); + } + +} + +/* End of file mssql_utility.php */ +/* Location: ./system/database/drivers/mssql/mssql_utility.php */ \ No newline at end of file diff --git a/system/database/index.html b/system/database/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/database/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/fonts/index.html b/system/fonts/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/fonts/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/fonts/texb.ttf b/system/fonts/texb.ttf new file mode 100644 index 0000000..383c88b Binary files /dev/null and b/system/fonts/texb.ttf differ diff --git a/system/helpers/array_helper.php b/system/helpers/array_helper.php new file mode 100644 index 0000000..075a31f --- /dev/null +++ b/system/helpers/array_helper.php @@ -0,0 +1,119 @@ + '', 'img_path' => '', 'img_url' => '', 'img_width' => '150', 'img_height' => '30', 'font_path' => '', 'expiration' => 7200); + + foreach ($defaults as $key => $val) + { + if ( ! is_array($data)) + { + if ( ! isset($$key) OR $$key == '') + { + $$key = $val; + } + } + else + { + $$key = ( ! isset($data[$key])) ? $val : $data[$key]; + } + } + + if ($img_path == '' OR $img_url == '') + { + return FALSE; + } + + if ( ! @is_dir($img_path)) + { + return FALSE; + } + + if ( ! is_writable($img_path)) + { + return FALSE; + } + + if ( ! extension_loaded('gd')) + { + return FALSE; + } + + // ----------------------------------- + // Remove old images + // ----------------------------------- + + list($usec, $sec) = explode(" ", microtime()); + $now = ((float)$usec + (float)$sec); + + $current_dir = @opendir($img_path); + + while ($filename = @readdir($current_dir)) + { + if ($filename != "." and $filename != ".." and $filename != "index.html") + { + $name = str_replace(".jpg", "", $filename); + + if (($name + $expiration) < $now) + { + @unlink($img_path.$filename); + } + } + } + + @closedir($current_dir); + + // ----------------------------------- + // Do we have a "word" yet? + // ----------------------------------- + + if ($word == '') + { + $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $str = ''; + for ($i = 0; $i < 8; $i++) + { + $str .= substr($pool, mt_rand(0, strlen($pool) -1), 1); + } + + $word = $str; + } + + // ----------------------------------- + // Determine angle and position + // ----------------------------------- + + $length = strlen($word); + $angle = ($length >= 6) ? rand(-($length-6), ($length-6)) : 0; + $x_axis = rand(6, (360/$length)-16); + $y_axis = ($angle >= 0 ) ? rand($img_height, $img_width) : rand(6, $img_height); + + // ----------------------------------- + // Create image + // ----------------------------------- + + // PHP.net recommends imagecreatetruecolor(), but it isn't always available + if (function_exists('imagecreatetruecolor')) + { + $im = imagecreatetruecolor($img_width, $img_height); + } + else + { + $im = imagecreate($img_width, $img_height); + } + + // ----------------------------------- + // Assign colors + // ----------------------------------- + + $bg_color = imagecolorallocate ($im, 255, 255, 255); + $border_color = imagecolorallocate ($im, 153, 102, 102); + $text_color = imagecolorallocate ($im, 204, 153, 153); + $grid_color = imagecolorallocate($im, 255, 182, 182); + $shadow_color = imagecolorallocate($im, 255, 240, 240); + + // ----------------------------------- + // Create the rectangle + // ----------------------------------- + + ImageFilledRectangle($im, 0, 0, $img_width, $img_height, $bg_color); + + // ----------------------------------- + // Create the spiral pattern + // ----------------------------------- + + $theta = 1; + $thetac = 7; + $radius = 16; + $circles = 20; + $points = 32; + + for ($i = 0; $i < ($circles * $points) - 1; $i++) + { + $theta = $theta + $thetac; + $rad = $radius * ($i / $points ); + $x = ($rad * cos($theta)) + $x_axis; + $y = ($rad * sin($theta)) + $y_axis; + $theta = $theta + $thetac; + $rad1 = $radius * (($i + 1) / $points); + $x1 = ($rad1 * cos($theta)) + $x_axis; + $y1 = ($rad1 * sin($theta )) + $y_axis; + imageline($im, $x, $y, $x1, $y1, $grid_color); + $theta = $theta - $thetac; + } + + // ----------------------------------- + // Write the text + // ----------------------------------- + + $use_font = ($font_path != '' AND file_exists($font_path) AND function_exists('imagettftext')) ? TRUE : FALSE; + + if ($use_font == FALSE) + { + $font_size = 5; + $x = rand(0, $img_width/($length/3)); + $y = 0; + } + else + { + $font_size = 16; + $x = rand(0, $img_width/($length/1.5)); + $y = $font_size+2; + } + + for ($i = 0; $i < strlen($word); $i++) + { + if ($use_font == FALSE) + { + $y = rand(0 , $img_height/2); + imagestring($im, $font_size, $x, $y, substr($word, $i, 1), $text_color); + $x += ($font_size*2); + } + else + { + $y = rand($img_height/2, $img_height-3); + imagettftext($im, $font_size, $angle, $x, $y, $text_color, $font_path, substr($word, $i, 1)); + $x += $font_size; + } + } + + + // ----------------------------------- + // Create the border + // ----------------------------------- + + imagerectangle($im, 0, 0, $img_width-1, $img_height-1, $border_color); + + // ----------------------------------- + // Generate the image + // ----------------------------------- + + $img_name = $now.'.jpg'; + + ImageJPEG($im, $img_path.$img_name); + + $img = "\""; + + ImageDestroy($im); + + return array('word' => $word, 'time' => $now, 'image' => $img); + } +} + +// ------------------------------------------------------------------------ + +/* End of file captcha_helper.php */ +/* Location: ./system/heleprs/captcha_helper.php */ \ No newline at end of file diff --git a/system/helpers/cookie_helper.php b/system/helpers/cookie_helper.php new file mode 100644 index 0000000..7cee028 --- /dev/null +++ b/system/helpers/cookie_helper.php @@ -0,0 +1,103 @@ +input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure); + } +} + +// -------------------------------------------------------------------- + +/** + * Fetch an item from the COOKIE array + * + * @access public + * @param string + * @param bool + * @return mixed + */ +if ( ! function_exists('get_cookie')) +{ + function get_cookie($index = '', $xss_clean = FALSE) + { + $CI =& get_instance(); + + $prefix = ''; + + if ( ! isset($_COOKIE[$index]) && config_item('cookie_prefix') != '') + { + $prefix = config_item('cookie_prefix'); + } + + return $CI->input->cookie($prefix.$index, $xss_clean); + } +} + +// -------------------------------------------------------------------- + +/** + * Delete a COOKIE + * + * @param mixed + * @param string the cookie domain. Usually: .yourdomain.com + * @param string the cookie path + * @param string the cookie prefix + * @return void + */ +if ( ! function_exists('delete_cookie')) +{ + function delete_cookie($name = '', $domain = '', $path = '/', $prefix = '') + { + set_cookie($name, '', '', $domain, $path, $prefix); + } +} + + +/* End of file cookie_helper.php */ +/* Location: ./system/helpers/cookie_helper.php */ \ No newline at end of file diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php new file mode 100644 index 0000000..0aeb7fa --- /dev/null +++ b/system/helpers/date_helper.php @@ -0,0 +1,611 @@ +config->item('time_reference')) == 'gmt') + { + $now = time(); + $system_time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now)); + + if (strlen($system_time) < 10) + { + $system_time = time(); + log_message('error', 'The Date class could not set a proper GMT timestamp so the local time() value was used.'); + } + + return $system_time; + } + else + { + return time(); + } + } +} + +// ------------------------------------------------------------------------ + +/** + * Convert MySQL Style Datecodes + * + * This function is identical to PHPs date() function, + * except that it allows date codes to be formatted using + * the MySQL style, where each code letter is preceded + * with a percent sign: %Y %m %d etc... + * + * The benefit of doing dates this way is that you don't + * have to worry about escaping your text letters that + * match the date codes. + * + * @access public + * @param string + * @param integer + * @return integer + */ +if ( ! function_exists('mdate')) +{ + function mdate($datestr = '', $time = '') + { + if ($datestr == '') + return ''; + + if ($time == '') + $time = now(); + + $datestr = str_replace('%\\', '', preg_replace("/([a-z]+?){1}/i", "\\\\\\1", $datestr)); + return date($datestr, $time); + } +} + +// ------------------------------------------------------------------------ + +/** + * Standard Date + * + * Returns a date formatted according to the submitted standard. + * + * @access public + * @param string the chosen format + * @param integer Unix timestamp + * @return string + */ +if ( ! function_exists('standard_date')) +{ + function standard_date($fmt = 'DATE_RFC822', $time = '') + { + $formats = array( + 'DATE_ATOM' => '%Y-%m-%dT%H:%i:%s%Q', + 'DATE_COOKIE' => '%l, %d-%M-%y %H:%i:%s UTC', + 'DATE_ISO8601' => '%Y-%m-%dT%H:%i:%s%Q', + 'DATE_RFC822' => '%D, %d %M %y %H:%i:%s %O', + 'DATE_RFC850' => '%l, %d-%M-%y %H:%i:%s UTC', + 'DATE_RFC1036' => '%D, %d %M %y %H:%i:%s %O', + 'DATE_RFC1123' => '%D, %d %M %Y %H:%i:%s %O', + 'DATE_RSS' => '%D, %d %M %Y %H:%i:%s %O', + 'DATE_W3C' => '%Y-%m-%dT%H:%i:%s%Q' + ); + + if ( ! isset($formats[$fmt])) + { + return FALSE; + } + + return mdate($formats[$fmt], $time); + } +} + +// ------------------------------------------------------------------------ + +/** + * Timespan + * + * Returns a span of seconds in this format: + * 10 days 14 hours 36 minutes 47 seconds + * + * @access public + * @param integer a number of seconds + * @param integer Unix timestamp + * @return integer + */ +if ( ! function_exists('timespan')) +{ + function timespan($seconds = 1, $time = '') + { + $CI =& get_instance(); + $CI->lang->load('date'); + + if ( ! is_numeric($seconds)) + { + $seconds = 1; + } + + if ( ! is_numeric($time)) + { + $time = time(); + } + + if ($time <= $seconds) + { + $seconds = 1; + } + else + { + $seconds = $time - $seconds; + } + + $str = ''; + $years = floor($seconds / 31536000); + + if ($years > 0) + { + $str .= $years.' '.$CI->lang->line((($years > 1) ? 'date_years' : 'date_year')).', '; + } + + $seconds -= $years * 31536000; + $months = floor($seconds / 2628000); + + if ($years > 0 OR $months > 0) + { + if ($months > 0) + { + $str .= $months.' '.$CI->lang->line((($months > 1) ? 'date_months' : 'date_month')).', '; + } + + $seconds -= $months * 2628000; + } + + $weeks = floor($seconds / 604800); + + if ($years > 0 OR $months > 0 OR $weeks > 0) + { + if ($weeks > 0) + { + $str .= $weeks.' '.$CI->lang->line((($weeks > 1) ? 'date_weeks' : 'date_week')).', '; + } + + $seconds -= $weeks * 604800; + } + + $days = floor($seconds / 86400); + + if ($months > 0 OR $weeks > 0 OR $days > 0) + { + if ($days > 0) + { + $str .= $days.' '.$CI->lang->line((($days > 1) ? 'date_days' : 'date_day')).', '; + } + + $seconds -= $days * 86400; + } + + $hours = floor($seconds / 3600); + + if ($days > 0 OR $hours > 0) + { + if ($hours > 0) + { + $str .= $hours.' '.$CI->lang->line((($hours > 1) ? 'date_hours' : 'date_hour')).', '; + } + + $seconds -= $hours * 3600; + } + + $minutes = floor($seconds / 60); + + if ($days > 0 OR $hours > 0 OR $minutes > 0) + { + if ($minutes > 0) + { + $str .= $minutes.' '.$CI->lang->line((($minutes > 1) ? 'date_minutes' : 'date_minute')).', '; + } + + $seconds -= $minutes * 60; + } + + if ($str == '') + { + $str .= $seconds.' '.$CI->lang->line((($seconds > 1) ? 'date_seconds' : 'date_second')).', '; + } + + return substr(trim($str), 0, -1); + } +} + +// ------------------------------------------------------------------------ + +/** + * Number of days in a month + * + * Takes a month/year as input and returns the number of days + * for the given month/year. Takes leap years into consideration. + * + * @access public + * @param integer a numeric month + * @param integer a numeric year + * @return integer + */ +if ( ! function_exists('days_in_month')) +{ + function days_in_month($month = 0, $year = '') + { + if ($month < 1 OR $month > 12) + { + return 0; + } + + if ( ! is_numeric($year) OR strlen($year) != 4) + { + $year = date('Y'); + } + + if ($month == 2) + { + if ($year % 400 == 0 OR ($year % 4 == 0 AND $year % 100 != 0)) + { + return 29; + } + } + + $days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); + return $days_in_month[$month - 1]; + } +} + +// ------------------------------------------------------------------------ + +/** + * Converts a local Unix timestamp to GMT + * + * @access public + * @param integer Unix timestamp + * @return integer + */ +if ( ! function_exists('local_to_gmt')) +{ + function local_to_gmt($time = '') + { + if ($time == '') + $time = time(); + + return mktime( gmdate("H", $time), gmdate("i", $time), gmdate("s", $time), gmdate("m", $time), gmdate("d", $time), gmdate("Y", $time)); + } +} + +// ------------------------------------------------------------------------ + +/** + * Converts GMT time to a localized value + * + * Takes a Unix timestamp (in GMT) as input, and returns + * at the local value based on the timezone and DST setting + * submitted + * + * @access public + * @param integer Unix timestamp + * @param string timezone + * @param bool whether DST is active + * @return integer + */ +if ( ! function_exists('gmt_to_local')) +{ + function gmt_to_local($time = '', $timezone = 'UTC', $dst = FALSE) + { + if ($time == '') + { + return now(); + } + + $time += timezones($timezone) * 3600; + + if ($dst == TRUE) + { + $time += 3600; + } + + return $time; + } +} + +// ------------------------------------------------------------------------ + +/** + * Converts a MySQL Timestamp to Unix + * + * @access public + * @param integer Unix timestamp + * @return integer + */ +if ( ! function_exists('mysql_to_unix')) +{ + function mysql_to_unix($time = '') + { + // We'll remove certain characters for backward compatibility + // since the formatting changed with MySQL 4.1 + // YYYY-MM-DD HH:MM:SS + + $time = str_replace('-', '', $time); + $time = str_replace(':', '', $time); + $time = str_replace(' ', '', $time); + + // YYYYMMDDHHMMSS + return mktime( + substr($time, 8, 2), + substr($time, 10, 2), + substr($time, 12, 2), + substr($time, 4, 2), + substr($time, 6, 2), + substr($time, 0, 4) + ); + } +} + +// ------------------------------------------------------------------------ + +/** + * Unix to "Human" + * + * Formats Unix timestamp to the following prototype: 2006-08-21 11:35 PM + * + * @access public + * @param integer Unix timestamp + * @param bool whether to show seconds + * @param string format: us or euro + * @return string + */ +if ( ! function_exists('unix_to_human')) +{ + function unix_to_human($time = '', $seconds = FALSE, $fmt = 'us') + { + $r = date('Y', $time).'-'.date('m', $time).'-'.date('d', $time).' '; + + if ($fmt == 'us') + { + $r .= date('h', $time).':'.date('i', $time); + } + else + { + $r .= date('H', $time).':'.date('i', $time); + } + + if ($seconds) + { + $r .= ':'.date('s', $time); + } + + if ($fmt == 'us') + { + $r .= ' '.date('A', $time); + } + + return $r; + } +} + +// ------------------------------------------------------------------------ + +/** + * Convert "human" date to GMT + * + * Reverses the above process + * + * @access public + * @param string format: us or euro + * @return integer + */ +if ( ! function_exists('human_to_unix')) +{ + function human_to_unix($datestr = '') + { + if ($datestr == '') + { + return FALSE; + } + + $datestr = trim($datestr); + $datestr = preg_replace("/\040+/", ' ', $datestr); + + if ( ! preg_match('/^[0-9]{2,4}\-[0-9]{1,2}\-[0-9]{1,2}\s[0-9]{1,2}:[0-9]{1,2}(?::[0-9]{1,2})?(?:\s[AP]M)?$/i', $datestr)) + { + return FALSE; + } + + $split = explode(' ', $datestr); + + $ex = explode("-", $split['0']); + + $year = (strlen($ex['0']) == 2) ? '20'.$ex['0'] : $ex['0']; + $month = (strlen($ex['1']) == 1) ? '0'.$ex['1'] : $ex['1']; + $day = (strlen($ex['2']) == 1) ? '0'.$ex['2'] : $ex['2']; + + $ex = explode(":", $split['1']); + + $hour = (strlen($ex['0']) == 1) ? '0'.$ex['0'] : $ex['0']; + $min = (strlen($ex['1']) == 1) ? '0'.$ex['1'] : $ex['1']; + + if (isset($ex['2']) && preg_match('/[0-9]{1,2}/', $ex['2'])) + { + $sec = (strlen($ex['2']) == 1) ? '0'.$ex['2'] : $ex['2']; + } + else + { + // Unless specified, seconds get set to zero. + $sec = '00'; + } + + if (isset($split['2'])) + { + $ampm = strtolower($split['2']); + + if (substr($ampm, 0, 1) == 'p' AND $hour < 12) + $hour = $hour + 12; + + if (substr($ampm, 0, 1) == 'a' AND $hour == 12) + $hour = '00'; + + if (strlen($hour) == 1) + $hour = '0'.$hour; + } + + return mktime($hour, $min, $sec, $month, $day, $year); + } +} + +// ------------------------------------------------------------------------ + +/** + * Timezone Menu + * + * Generates a drop-down menu of timezones. + * + * @access public + * @param string timezone + * @param string classname + * @param string menu name + * @return string + */ +if ( ! function_exists('timezone_menu')) +{ + function timezone_menu($default = 'UTC', $class = "", $name = 'timezones') + { + $CI =& get_instance(); + $CI->lang->load('date'); + + if ($default == 'GMT') + $default = 'UTC'; + + $menu = '"; + + return $menu; + } +} + +// ------------------------------------------------------------------------ + +/** + * Timezones + * + * Returns an array of timezones. This is a helper function + * for various other ones in this library + * + * @access public + * @param string timezone + * @return string + */ +if ( ! function_exists('timezones')) +{ + function timezones($tz = '') + { + // Note: Don't change the order of these even though + // some items appear to be in the wrong order + + $zones = array( + 'UM12' => -12, + 'UM11' => -11, + 'UM10' => -10, + 'UM95' => -9.5, + 'UM9' => -9, + 'UM8' => -8, + 'UM7' => -7, + 'UM6' => -6, + 'UM5' => -5, + 'UM45' => -4.5, + 'UM4' => -4, + 'UM35' => -3.5, + 'UM3' => -3, + 'UM2' => -2, + 'UM1' => -1, + 'UTC' => 0, + 'UP1' => +1, + 'UP2' => +2, + 'UP3' => +3, + 'UP35' => +3.5, + 'UP4' => +4, + 'UP45' => +4.5, + 'UP5' => +5, + 'UP55' => +5.5, + 'UP575' => +5.75, + 'UP6' => +6, + 'UP65' => +6.5, + 'UP7' => +7, + 'UP8' => +8, + 'UP875' => +8.75, + 'UP9' => +9, + 'UP95' => +9.5, + 'UP10' => +10, + 'UP105' => +10.5, + 'UP11' => +11, + 'UP115' => +11.5, + 'UP12' => +12, + 'UP1275' => +12.75, + 'UP13' => +13, + 'UP14' => +14 + ); + + if ($tz == '') + { + return $zones; + } + + if ($tz == 'GMT') + $tz = 'UTC'; + + return ( ! isset($zones[$tz])) ? 0 : $zones[$tz]; + } +} + + +/* End of file date_helper.php */ +/* Location: ./system/helpers/date_helper.php */ \ No newline at end of file diff --git a/system/helpers/directory_helper.php b/system/helpers/directory_helper.php new file mode 100644 index 0000000..38347fa --- /dev/null +++ b/system/helpers/directory_helper.php @@ -0,0 +1,80 @@ + 0) && @is_dir($source_dir.$file)) + { + $filedata[$file] = directory_map($source_dir.$file.DIRECTORY_SEPARATOR, $new_depth, $hidden); + } + else + { + $filedata[] = $file; + } + } + + closedir($fp); + return $filedata; + } + + return FALSE; + } +} + + +/* End of file directory_helper.php */ +/* Location: ./system/helpers/directory_helper.php */ \ No newline at end of file diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php new file mode 100644 index 0000000..1145688 --- /dev/null +++ b/system/helpers/download_helper.php @@ -0,0 +1,107 @@ + 0) + { + $data =& fread($fp, filesize($file)); + } + + flock($fp, LOCK_UN); + fclose($fp); + + return $data; + } +} + +// ------------------------------------------------------------------------ + +/** + * Write File + * + * Writes data to the file specified in the path. + * Creates a new file if non-existent. + * + * @access public + * @param string path to file + * @param string file data + * @return bool + */ +if ( ! function_exists('write_file')) +{ + function write_file($path, $data, $mode = FOPEN_WRITE_CREATE_DESTRUCTIVE) + { + if ( ! $fp = @fopen($path, $mode)) + { + return FALSE; + } + + flock($fp, LOCK_EX); + fwrite($fp, $data); + flock($fp, LOCK_UN); + fclose($fp); + + return TRUE; + } +} + +// ------------------------------------------------------------------------ + +/** + * Delete Files + * + * Deletes all files contained in the supplied directory path. + * Files must be writable or owned by the system in order to be deleted. + * If the second parameter is set to TRUE, any directories contained + * within the supplied base directory will be nuked as well. + * + * @access public + * @param string path to file + * @param bool whether to delete any directories found in the path + * @return bool + */ +if ( ! function_exists('delete_files')) +{ + function delete_files($path, $del_dir = FALSE, $level = 0) + { + // Trim the trailing slash + $path = rtrim($path, DIRECTORY_SEPARATOR); + + if ( ! $current_dir = @opendir($path)) + { + return FALSE; + } + + while (FALSE !== ($filename = @readdir($current_dir))) + { + if ($filename != "." and $filename != "..") + { + if (is_dir($path.DIRECTORY_SEPARATOR.$filename)) + { + // Ignore empty folders + if (substr($filename, 0, 1) != '.') + { + delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $level + 1); + } + } + else + { + unlink($path.DIRECTORY_SEPARATOR.$filename); + } + } + } + @closedir($current_dir); + + if ($del_dir == TRUE AND $level > 0) + { + return @rmdir($path); + } + + return TRUE; + } +} + +// ------------------------------------------------------------------------ + +/** + * Get Filenames + * + * Reads the specified directory and builds an array containing the filenames. + * Any sub-folders contained within the specified path are read as well. + * + * @access public + * @param string path to source + * @param bool whether to include the path as part of the filename + * @param bool internal variable to determine recursion status - do not use in calls + * @return array + */ +if ( ! function_exists('get_filenames')) +{ + function get_filenames($source_dir, $include_path = FALSE, $_recursion = FALSE) + { + static $_filedata = array(); + + if ($fp = @opendir($source_dir)) + { + // reset the array and make sure $source_dir has a trailing slash on the initial call + if ($_recursion === FALSE) + { + $_filedata = array(); + $source_dir = rtrim(realpath($source_dir), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + } + + while (FALSE !== ($file = readdir($fp))) + { + if (@is_dir($source_dir.$file) && strncmp($file, '.', 1) !== 0) + { + get_filenames($source_dir.$file.DIRECTORY_SEPARATOR, $include_path, TRUE); + } + elseif (strncmp($file, '.', 1) !== 0) + { + $_filedata[] = ($include_path == TRUE) ? $source_dir.$file : $file; + } + } + return $_filedata; + } + else + { + return FALSE; + } + } +} + +// -------------------------------------------------------------------- + +/** + * Get Directory File Information + * + * Reads the specified directory and builds an array containing the filenames, + * filesize, dates, and permissions + * + * Any sub-folders contained within the specified path are read as well. + * + * @access public + * @param string path to source + * @param bool Look only at the top level directory specified? + * @param bool internal variable to determine recursion status - do not use in calls + * @return array + */ +if ( ! function_exists('get_dir_file_info')) +{ + function get_dir_file_info($source_dir, $top_level_only = TRUE, $_recursion = FALSE) + { + static $_filedata = array(); + $relative_path = $source_dir; + + if ($fp = @opendir($source_dir)) + { + // reset the array and make sure $source_dir has a trailing slash on the initial call + if ($_recursion === FALSE) + { + $_filedata = array(); + $source_dir = rtrim(realpath($source_dir), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + } + + // foreach (scandir($source_dir, 1) as $file) // In addition to being PHP5+, scandir() is simply not as fast + while (FALSE !== ($file = readdir($fp))) + { + if (@is_dir($source_dir.$file) AND strncmp($file, '.', 1) !== 0 AND $top_level_only === FALSE) + { + get_dir_file_info($source_dir.$file.DIRECTORY_SEPARATOR, $top_level_only, TRUE); + } + elseif (strncmp($file, '.', 1) !== 0) + { + $_filedata[$file] = get_file_info($source_dir.$file); + $_filedata[$file]['relative_path'] = $relative_path; + } + } + + return $_filedata; + } + else + { + return FALSE; + } + } +} + +// -------------------------------------------------------------------- + +/** +* Get File Info +* +* Given a file and path, returns the name, path, size, date modified +* Second parameter allows you to explicitly declare what information you want returned +* Options are: name, server_path, size, date, readable, writable, executable, fileperms +* Returns FALSE if the file cannot be found. +* +* @access public +* @param string path to file +* @param mixed array or comma separated string of information returned +* @return array +*/ +if ( ! function_exists('get_file_info')) +{ + function get_file_info($file, $returned_values = array('name', 'server_path', 'size', 'date')) + { + + if ( ! file_exists($file)) + { + return FALSE; + } + + if (is_string($returned_values)) + { + $returned_values = explode(',', $returned_values); + } + + foreach ($returned_values as $key) + { + switch ($key) + { + case 'name': + $fileinfo['name'] = substr(strrchr($file, DIRECTORY_SEPARATOR), 1); + break; + case 'server_path': + $fileinfo['server_path'] = $file; + break; + case 'size': + $fileinfo['size'] = filesize($file); + break; + case 'date': + $fileinfo['date'] = filemtime($file); + break; + case 'readable': + $fileinfo['readable'] = is_readable($file); + break; + case 'writable': + // There are known problems using is_weritable on IIS. It may not be reliable - consider fileperms() + $fileinfo['writable'] = is_writable($file); + break; + case 'executable': + $fileinfo['executable'] = is_executable($file); + break; + case 'fileperms': + $fileinfo['fileperms'] = fileperms($file); + break; + } + } + + return $fileinfo; + } +} + +// -------------------------------------------------------------------- + +/** + * Get Mime by Extension + * + * Translates a file extension into a mime type based on config/mimes.php. + * Returns FALSE if it can't determine the type, or open the mime config file + * + * Note: this is NOT an accurate way of determining file mime types, and is here strictly as a convenience + * It should NOT be trusted, and should certainly NOT be used for security + * + * @access public + * @param string path to file + * @return mixed + */ +if ( ! function_exists('get_mime_by_extension')) +{ + function get_mime_by_extension($file) + { + $extension = strtolower(substr(strrchr($file, '.'), 1)); + + global $mimes; + + if ( ! is_array($mimes)) + { + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'); + } + elseif (is_file(APPPATH.'config/mimes.php')) + { + include(APPPATH.'config/mimes.php'); + } + + if ( ! is_array($mimes)) + { + return FALSE; + } + } + + if (array_key_exists($extension, $mimes)) + { + if (is_array($mimes[$extension])) + { + // Multiple mime types, just give the first one + return current($mimes[$extension]); + } + else + { + return $mimes[$extension]; + } + } + else + { + return FALSE; + } + } +} + +// -------------------------------------------------------------------- + +/** + * Symbolic Permissions + * + * Takes a numeric value representing a file's permissions and returns + * standard symbolic notation representing that value + * + * @access public + * @param int + * @return string + */ +if ( ! function_exists('symbolic_permissions')) +{ + function symbolic_permissions($perms) + { + if (($perms & 0xC000) == 0xC000) + { + $symbolic = 's'; // Socket + } + elseif (($perms & 0xA000) == 0xA000) + { + $symbolic = 'l'; // Symbolic Link + } + elseif (($perms & 0x8000) == 0x8000) + { + $symbolic = '-'; // Regular + } + elseif (($perms & 0x6000) == 0x6000) + { + $symbolic = 'b'; // Block special + } + elseif (($perms & 0x4000) == 0x4000) + { + $symbolic = 'd'; // Directory + } + elseif (($perms & 0x2000) == 0x2000) + { + $symbolic = 'c'; // Character special + } + elseif (($perms & 0x1000) == 0x1000) + { + $symbolic = 'p'; // FIFO pipe + } + else + { + $symbolic = 'u'; // Unknown + } + + // Owner + $symbolic .= (($perms & 0x0100) ? 'r' : '-'); + $symbolic .= (($perms & 0x0080) ? 'w' : '-'); + $symbolic .= (($perms & 0x0040) ? (($perms & 0x0800) ? 's' : 'x' ) : (($perms & 0x0800) ? 'S' : '-')); + + // Group + $symbolic .= (($perms & 0x0020) ? 'r' : '-'); + $symbolic .= (($perms & 0x0010) ? 'w' : '-'); + $symbolic .= (($perms & 0x0008) ? (($perms & 0x0400) ? 's' : 'x' ) : (($perms & 0x0400) ? 'S' : '-')); + + // World + $symbolic .= (($perms & 0x0004) ? 'r' : '-'); + $symbolic .= (($perms & 0x0002) ? 'w' : '-'); + $symbolic .= (($perms & 0x0001) ? (($perms & 0x0200) ? 't' : 'x' ) : (($perms & 0x0200) ? 'T' : '-')); + + return $symbolic; + } +} + +// -------------------------------------------------------------------- + +/** + * Octal Permissions + * + * Takes a numeric value representing a file's permissions and returns + * a three character string representing the file's octal permissions + * + * @access public + * @param int + * @return string + */ +if ( ! function_exists('octal_permissions')) +{ + function octal_permissions($perms) + { + return substr(sprintf('%o', $perms), -3); + } +} + + +/* End of file file_helper.php */ +/* Location: ./system/helpers/file_helper.php */ \ No newline at end of file diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php new file mode 100644 index 0000000..8733ae0 --- /dev/null +++ b/system/helpers/form_helper.php @@ -0,0 +1,1054 @@ +config->site_url($action); + } + + // If no action is provided then set to the current url + $action OR $action = $CI->config->site_url($CI->uri->uri_string()); + + $form = '
    config->item('csrf_protection') === TRUE AND ! (strpos($action, $CI->config->base_url()) === FALSE OR strpos($form, 'method="get"'))) + { + $hidden[$CI->security->get_csrf_token_name()] = $CI->security->get_csrf_hash(); + } + + if (is_array($hidden) AND count($hidden) > 0) + { + $form .= sprintf("
    %s
    ", form_hidden($hidden)); + } + + return $form; + } +} + +// ------------------------------------------------------------------------ + +/** + * Form Declaration - Multipart type + * + * Creates the opening portion of the form, but with "multipart/form-data". + * + * @access public + * @param string the URI segments of the form destination + * @param array a key/value pair of attributes + * @param array a key/value pair hidden data + * @return string + */ +if ( ! function_exists('form_open_multipart')) +{ + function form_open_multipart($action = '', $attributes = array(), $hidden = array()) + { + if (is_string($attributes)) + { + $attributes .= ' enctype="multipart/form-data"'; + } + else + { + $attributes['enctype'] = 'multipart/form-data'; + } + + return form_open($action, $attributes, $hidden); + } +} + +// ------------------------------------------------------------------------ + +/** + * Hidden Input Field + * + * Generates hidden fields. You can pass a simple key/value string or an associative + * array with multiple values. + * + * @access public + * @param mixed + * @param string + * @return string + */ +if ( ! function_exists('form_hidden')) +{ + function form_hidden($name, $value = '', $recursing = FALSE) + { + static $form; + + if ($recursing === FALSE) + { + $form = "\n"; + } + + if (is_array($name)) + { + foreach ($name as $key => $val) + { + form_hidden($key, $val, TRUE); + } + return $form; + } + + if ( ! is_array($value)) + { + $form .= ''."\n"; + } + else + { + foreach ($value as $k => $v) + { + $k = (is_int($k)) ? '' : $k; + form_hidden($name.'['.$k.']', $v, TRUE); + } + } + + return $form; + } +} + +// ------------------------------------------------------------------------ + +/** + * Text Input Field + * + * @access public + * @param mixed + * @param string + * @param string + * @return string + */ +if ( ! function_exists('form_input')) +{ + function form_input($data = '', $value = '', $extra = '') + { + $defaults = array('type' => 'text', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value); + + return ""; + } +} + +// ------------------------------------------------------------------------ + +/** + * Password Field + * + * Identical to the input function but adds the "password" type + * + * @access public + * @param mixed + * @param string + * @param string + * @return string + */ +if ( ! function_exists('form_password')) +{ + function form_password($data = '', $value = '', $extra = '') + { + if ( ! is_array($data)) + { + $data = array('name' => $data); + } + + $data['type'] = 'password'; + return form_input($data, $value, $extra); + } +} + +// ------------------------------------------------------------------------ + +/** + * Upload Field + * + * Identical to the input function but adds the "file" type + * + * @access public + * @param mixed + * @param string + * @param string + * @return string + */ +if ( ! function_exists('form_upload')) +{ + function form_upload($data = '', $value = '', $extra = '') + { + if ( ! is_array($data)) + { + $data = array('name' => $data); + } + + $data['type'] = 'file'; + return form_input($data, $value, $extra); + } +} + +// ------------------------------------------------------------------------ + +/** + * Textarea field + * + * @access public + * @param mixed + * @param string + * @param string + * @return string + */ +if ( ! function_exists('form_textarea')) +{ + function form_textarea($data = '', $value = '', $extra = '') + { + $defaults = array('name' => (( ! is_array($data)) ? $data : ''), 'cols' => '40', 'rows' => '10'); + + if ( ! is_array($data) OR ! isset($data['value'])) + { + $val = $value; + } + else + { + $val = $data['value']; + unset($data['value']); // textareas don't use the value attribute + } + + $name = (is_array($data)) ? $data['name'] : $data; + return ""; + } +} + +// ------------------------------------------------------------------------ + +/** + * Multi-select menu + * + * @access public + * @param string + * @param array + * @param mixed + * @param string + * @return type + */ +if ( ! function_exists('form_multiselect')) +{ + function form_multiselect($name = '', $options = array(), $selected = array(), $extra = '') + { + if ( ! strpos($extra, 'multiple')) + { + $extra .= ' multiple="multiple"'; + } + + return form_dropdown($name, $options, $selected, $extra); + } +} + +// -------------------------------------------------------------------- + +/** + * Drop-down Menu + * + * @access public + * @param string + * @param array + * @param string + * @param string + * @return string + */ +if ( ! function_exists('form_dropdown')) +{ + function form_dropdown($name = '', $options = array(), $selected = array(), $extra = '') + { + if ( ! is_array($selected)) + { + $selected = array($selected); + } + + // If no selected state was submitted we will attempt to set it automatically + if (count($selected) === 0) + { + // If the form name appears in the $_POST array we have a winner! + if (isset($_POST[$name])) + { + $selected = array($_POST[$name]); + } + } + + if ($extra != '') $extra = ' '.$extra; + + $multiple = (count($selected) > 1 && strpos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : ''; + + $form = ''; + + return $form; + } +} + +// ------------------------------------------------------------------------ + +/** + * Checkbox Field + * + * @access public + * @param mixed + * @param string + * @param bool + * @param string + * @return string + */ +if ( ! function_exists('form_checkbox')) +{ + function form_checkbox($data = '', $value = '', $checked = FALSE, $extra = '') + { + $defaults = array('type' => 'checkbox', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value); + + if (is_array($data) AND array_key_exists('checked', $data)) + { + $checked = $data['checked']; + + if ($checked == FALSE) + { + unset($data['checked']); + } + else + { + $data['checked'] = 'checked'; + } + } + + if ($checked == TRUE) + { + $defaults['checked'] = 'checked'; + } + else + { + unset($defaults['checked']); + } + + return ""; + } +} + +// ------------------------------------------------------------------------ + +/** + * Radio Button + * + * @access public + * @param mixed + * @param string + * @param bool + * @param string + * @return string + */ +if ( ! function_exists('form_radio')) +{ + function form_radio($data = '', $value = '', $checked = FALSE, $extra = '') + { + if ( ! is_array($data)) + { + $data = array('name' => $data); + } + + $data['type'] = 'radio'; + return form_checkbox($data, $value, $checked, $extra); + } +} + +// ------------------------------------------------------------------------ + +/** + * Submit Button + * + * @access public + * @param mixed + * @param string + * @param string + * @return string + */ +if ( ! function_exists('form_submit')) +{ + function form_submit($data = '', $value = '', $extra = '') + { + $defaults = array('type' => 'submit', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value); + + return ""; + } +} + +// ------------------------------------------------------------------------ + +/** + * Reset Button + * + * @access public + * @param mixed + * @param string + * @param string + * @return string + */ +if ( ! function_exists('form_reset')) +{ + function form_reset($data = '', $value = '', $extra = '') + { + $defaults = array('type' => 'reset', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value); + + return ""; + } +} + +// ------------------------------------------------------------------------ + +/** + * Form Button + * + * @access public + * @param mixed + * @param string + * @param string + * @return string + */ +if ( ! function_exists('form_button')) +{ + function form_button($data = '', $content = '', $extra = '') + { + $defaults = array('name' => (( ! is_array($data)) ? $data : ''), 'type' => 'button'); + + if ( is_array($data) AND isset($data['content'])) + { + $content = $data['content']; + unset($data['content']); // content is not an attribute + } + + return ""; + } +} + +// ------------------------------------------------------------------------ + +/** + * Form Label Tag + * + * @access public + * @param string The text to appear onscreen + * @param string The id the label applies to + * @param string Additional attributes + * @return string + */ +if ( ! function_exists('form_label')) +{ + function form_label($label_text = '', $id = '', $attributes = array()) + { + + $label = ' 0) + { + foreach ($attributes as $key => $val) + { + $label .= ' '.$key.'="'.$val.'"'; + } + } + + $label .= ">$label_text"; + + return $label; + } +} + +// ------------------------------------------------------------------------ +/** + * Fieldset Tag + * + * Used to produce
    text. To close fieldset + * use form_fieldset_close() + * + * @access public + * @param string The legend text + * @param string Additional attributes + * @return string + */ +if ( ! function_exists('form_fieldset')) +{ + function form_fieldset($legend_text = '', $attributes = array()) + { + $fieldset = "".$extra; + } +} + +// ------------------------------------------------------------------------ + +/** + * Form Close Tag + * + * @access public + * @param string + * @return string + */ +if ( ! function_exists('form_close')) +{ + function form_close($extra = '') + { + return "".$extra; + } +} + +// ------------------------------------------------------------------------ + +/** + * Form Prep + * + * Formats text so that it can be safely placed in a form field in the event it has HTML tags. + * + * @access public + * @param string + * @return string + */ +if ( ! function_exists('form_prep')) +{ + function form_prep($str = '', $field_name = '') + { + static $prepped_fields = array(); + + // if the field name is an array we do this recursively + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = form_prep($val); + } + + return $str; + } + + if ($str === '') + { + return ''; + } + + // we've already prepped a field with this name + // @todo need to figure out a way to namespace this so + // that we know the *exact* field and not just one with + // the same name + if (isset($prepped_fields[$field_name])) + { + return $str; + } + + $str = htmlspecialchars($str); + + // In case htmlspecialchars misses these. + $str = str_replace(array("'", '"'), array("'", """), $str); + + if ($field_name != '') + { + $prepped_fields[$field_name] = $field_name; + } + + return $str; + } +} + +// ------------------------------------------------------------------------ + +/** + * Form Value + * + * Grabs a value from the POST array for the specified field so you can + * re-populate an input field or textarea. If Form Validation + * is active it retrieves the info from the validation class + * + * @access public + * @param string + * @return mixed + */ +if ( ! function_exists('set_value')) +{ + function set_value($field = '', $default = '') + { + if (FALSE === ($OBJ =& _get_validation_object())) + { + if ( ! isset($_POST[$field])) + { + return $default; + } + + return form_prep($_POST[$field], $field); + } + + return form_prep($OBJ->set_value($field, $default), $field); + } +} + +// ------------------------------------------------------------------------ + +/** + * Set Select + * + * Let's you set the selected value of a
    ', + 'heading_row_start' => '', + 'heading_previous_cell' => '', + 'heading_title_cell' => '', + 'heading_next_cell' => '', + 'heading_row_end' => '', + 'week_row_start' => '', + 'week_day_cell' => '', + 'week_row_end' => '', + 'cal_row_start' => '', + 'cal_cell_start' => '', + 'cal_cell_end_today' => '', + 'cal_row_end' => '', + 'table_close' => '
    <<{heading}>>
    {week_day}
    ', + 'cal_cell_start_today' => '', + 'cal_cell_content' => '{day}', + 'cal_cell_content_today' => '{day}', + 'cal_cell_no_content' => '{day}', + 'cal_cell_no_content_today' => '{day}', + 'cal_cell_blank' => ' ', + 'cal_cell_end' => '
    ' + ); + } + + // -------------------------------------------------------------------- + + /** + * Parse Template + * + * Harvests the data within the template {pseudo-variables} + * used to display the calendar + * + * @access public + * @return void + */ + function parse_template() + { + $this->temp = $this->default_template(); + + if ($this->template == '') + { + return; + } + + $today = array('cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today'); + + foreach (array('table_open', 'table_close', 'heading_row_start', 'heading_previous_cell', 'heading_title_cell', 'heading_next_cell', 'heading_row_end', 'week_row_start', 'week_day_cell', 'week_row_end', 'cal_row_start', 'cal_cell_start', 'cal_cell_content', 'cal_cell_no_content', 'cal_cell_blank', 'cal_cell_end', 'cal_row_end', 'cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today') as $val) + { + if (preg_match("/\{".$val."\}(.*?)\{\/".$val."\}/si", $this->template, $match)) + { + $this->temp[$val] = $match['1']; + } + else + { + if (in_array($val, $today, TRUE)) + { + $this->temp[$val] = $this->temp[str_replace('_today', '', $val)]; + } + } + } + } + +} + +// END CI_Calendar class + +/* End of file Calendar.php */ +/* Location: ./system/libraries/Calendar.php */ \ No newline at end of file diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php new file mode 100644 index 0000000..da47b5a --- /dev/null +++ b/system/libraries/Cart.php @@ -0,0 +1,552 @@ +CI =& get_instance(); + + // Are any config settings being passed manually? If so, set them + $config = array(); + if (count($params) > 0) + { + foreach ($params as $key => $val) + { + $config[$key] = $val; + } + } + + // Load the Sessions class + $this->CI->load->library('session', $config); + + // Grab the shopping cart array from the session table, if it exists + if ($this->CI->session->userdata('cart_contents') !== FALSE) + { + $this->_cart_contents = $this->CI->session->userdata('cart_contents'); + } + else + { + // No cart exists so we'll set some base values + $this->_cart_contents['cart_total'] = 0; + $this->_cart_contents['total_items'] = 0; + } + + log_message('debug', "Cart Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Insert items into the cart and save it to the session table + * + * @access public + * @param array + * @return bool + */ + function insert($items = array()) + { + // Was any cart data passed? No? Bah... + if ( ! is_array($items) OR count($items) == 0) + { + log_message('error', 'The insert method must be passed an array containing data.'); + return FALSE; + } + + // You can either insert a single product using a one-dimensional array, + // or multiple products using a multi-dimensional one. The way we + // determine the array type is by looking for a required array key named "id" + // at the top level. If it's not found, we will assume it's a multi-dimensional array. + + $save_cart = FALSE; + if (isset($items['id'])) + { + if (($rowid = $this->_insert($items))) + { + $save_cart = TRUE; + } + } + else + { + foreach ($items as $val) + { + if (is_array($val) AND isset($val['id'])) + { + if ($this->_insert($val)) + { + $save_cart = TRUE; + } + } + } + } + + // Save the cart data if the insert was successful + if ($save_cart == TRUE) + { + $this->_save_cart(); + return isset($rowid) ? $rowid : TRUE; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Insert + * + * @access private + * @param array + * @return bool + */ + function _insert($items = array()) + { + // Was any cart data passed? No? Bah... + if ( ! is_array($items) OR count($items) == 0) + { + log_message('error', 'The insert method must be passed an array containing data.'); + return FALSE; + } + + // -------------------------------------------------------------------- + + // Does the $items array contain an id, quantity, price, and name? These are required + if ( ! isset($items['id']) OR ! isset($items['qty']) OR ! isset($items['price']) OR ! isset($items['name'])) + { + log_message('error', 'The cart array must contain a product ID, quantity, price, and name.'); + return FALSE; + } + + // -------------------------------------------------------------------- + + // Prep the quantity. It can only be a number. Duh... + $items['qty'] = trim(preg_replace('/([^0-9])/i', '', $items['qty'])); + // Trim any leading zeros + $items['qty'] = trim(preg_replace('/(^[0]+)/i', '', $items['qty'])); + + // If the quantity is zero or blank there's nothing for us to do + if ( ! is_numeric($items['qty']) OR $items['qty'] == 0) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + // Validate the product ID. It can only be alpha-numeric, dashes, underscores or periods + // Not totally sure we should impose this rule, but it seems prudent to standardize IDs. + // Note: These can be user-specified by setting the $this->product_id_rules variable. + if ( ! preg_match("/^[".$this->product_id_rules."]+$/i", $items['id'])) + { + log_message('error', 'Invalid product ID. The product ID can only contain alpha-numeric characters, dashes, and underscores'); + return FALSE; + } + + // -------------------------------------------------------------------- + + // Validate the product name. It can only be alpha-numeric, dashes, underscores, colons or periods. + // Note: These can be user-specified by setting the $this->product_name_rules variable. + if ( ! preg_match("/^[".$this->product_name_rules."]+$/i", $items['name'])) + { + log_message('error', 'An invalid name was submitted as the product name: '.$items['name'].' The name can only contain alpha-numeric characters, dashes, underscores, colons, and spaces'); + return FALSE; + } + + // -------------------------------------------------------------------- + + // Prep the price. Remove anything that isn't a number or decimal point. + $items['price'] = trim(preg_replace('/([^0-9\.])/i', '', $items['price'])); + // Trim any leading zeros + $items['price'] = trim(preg_replace('/(^[0]+)/i', '', $items['price'])); + + // Is the price a valid number? + if ( ! is_numeric($items['price'])) + { + log_message('error', 'An invalid price was submitted for product ID: '.$items['id']); + return FALSE; + } + + // -------------------------------------------------------------------- + + // We now need to create a unique identifier for the item being inserted into the cart. + // Every time something is added to the cart it is stored in the master cart array. + // Each row in the cart array, however, must have a unique index that identifies not only + // a particular product, but makes it possible to store identical products with different options. + // For example, what if someone buys two identical t-shirts (same product ID), but in + // different sizes? The product ID (and other attributes, like the name) will be identical for + // both sizes because it's the same shirt. The only difference will be the size. + // Internally, we need to treat identical submissions, but with different options, as a unique product. + // Our solution is to convert the options array to a string and MD5 it along with the product ID. + // This becomes the unique "row ID" + if (isset($items['options']) AND count($items['options']) > 0) + { + $rowid = md5($items['id'].implode('', $items['options'])); + } + else + { + // No options were submitted so we simply MD5 the product ID. + // Technically, we don't need to MD5 the ID in this case, but it makes + // sense to standardize the format of array indexes for both conditions + $rowid = md5($items['id']); + } + + // -------------------------------------------------------------------- + + // Now that we have our unique "row ID", we'll add our cart items to the master array + + // let's unset this first, just to make sure our index contains only the data from this submission + unset($this->_cart_contents[$rowid]); + + // Create a new index with our new row ID + $this->_cart_contents[$rowid]['rowid'] = $rowid; + + // And add the new items to the cart array + foreach ($items as $key => $val) + { + $this->_cart_contents[$rowid][$key] = $val; + } + + // Woot! + return $rowid; + } + + // -------------------------------------------------------------------- + + /** + * Update the cart + * + * This function permits the quantity of a given item to be changed. + * Typically it is called from the "view cart" page if a user makes + * changes to the quantity before checkout. That array must contain the + * product ID and quantity for each item. + * + * @access public + * @param array + * @param string + * @return bool + */ + function update($items = array()) + { + // Was any cart data passed? + if ( ! is_array($items) OR count($items) == 0) + { + return FALSE; + } + + // You can either update a single product using a one-dimensional array, + // or multiple products using a multi-dimensional one. The way we + // determine the array type is by looking for a required array key named "id". + // If it's not found we assume it's a multi-dimensional array + $save_cart = FALSE; + if (isset($items['rowid']) AND isset($items['qty'])) + { + if ($this->_update($items) == TRUE) + { + $save_cart = TRUE; + } + } + else + { + foreach ($items as $val) + { + if (is_array($val) AND isset($val['rowid']) AND isset($val['qty'])) + { + if ($this->_update($val) == TRUE) + { + $save_cart = TRUE; + } + } + } + } + + // Save the cart data if the insert was successful + if ($save_cart == TRUE) + { + $this->_save_cart(); + return TRUE; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Update the cart + * + * This function permits the quantity of a given item to be changed. + * Typically it is called from the "view cart" page if a user makes + * changes to the quantity before checkout. That array must contain the + * product ID and quantity for each item. + * + * @access private + * @param array + * @return bool + */ + function _update($items = array()) + { + // Without these array indexes there is nothing we can do + if ( ! isset($items['qty']) OR ! isset($items['rowid']) OR ! isset($this->_cart_contents[$items['rowid']])) + { + return FALSE; + } + + // Prep the quantity + $items['qty'] = preg_replace('/([^0-9])/i', '', $items['qty']); + + // Is the quantity a number? + if ( ! is_numeric($items['qty'])) + { + return FALSE; + } + + // Is the new quantity different than what is already saved in the cart? + // If it's the same there's nothing to do + if ($this->_cart_contents[$items['rowid']]['qty'] == $items['qty']) + { + return FALSE; + } + + // Is the quantity zero? If so we will remove the item from the cart. + // If the quantity is greater than zero we are updating + if ($items['qty'] == 0) + { + unset($this->_cart_contents[$items['rowid']]); + } + else + { + $this->_cart_contents[$items['rowid']]['qty'] = $items['qty']; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Save the cart array to the session DB + * + * @access private + * @return bool + */ + function _save_cart() + { + // Unset these so our total can be calculated correctly below + unset($this->_cart_contents['total_items']); + unset($this->_cart_contents['cart_total']); + + // Lets add up the individual prices and set the cart sub-total + $total = 0; + $items = 0; + foreach ($this->_cart_contents as $key => $val) + { + // We make sure the array contains the proper indexes + if ( ! is_array($val) OR ! isset($val['price']) OR ! isset($val['qty'])) + { + continue; + } + + $total += ($val['price'] * $val['qty']); + $items += $val['qty']; + + // Set the subtotal + $this->_cart_contents[$key]['subtotal'] = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']); + } + + // Set the cart total and total items. + $this->_cart_contents['total_items'] = $items; + $this->_cart_contents['cart_total'] = $total; + + // Is our cart empty? If so we delete it from the session + if (count($this->_cart_contents) <= 2) + { + $this->CI->session->unset_userdata('cart_contents'); + + // Nothing more to do... coffee time! + return FALSE; + } + + // If we made it this far it means that our cart has data. + // Let's pass it to the Session class so it can be stored + $this->CI->session->set_userdata(array('cart_contents' => $this->_cart_contents)); + + // Woot! + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Cart Total + * + * @access public + * @return integer + */ + function total() + { + return $this->_cart_contents['cart_total']; + } + + // -------------------------------------------------------------------- + + /** + * Total Items + * + * Returns the total item count + * + * @access public + * @return integer + */ + function total_items() + { + return $this->_cart_contents['total_items']; + } + + // -------------------------------------------------------------------- + + /** + * Cart Contents + * + * Returns the entire cart array + * + * @access public + * @return array + */ + function contents() + { + $cart = $this->_cart_contents; + + // Remove these so they don't create a problem when showing the cart table + unset($cart['total_items']); + unset($cart['cart_total']); + + return $cart; + } + + // -------------------------------------------------------------------- + + /** + * Has options + * + * Returns TRUE if the rowid passed to this function correlates to an item + * that has options associated with it. + * + * @access public + * @return array + */ + function has_options($rowid = '') + { + if ( ! isset($this->_cart_contents[$rowid]['options']) OR count($this->_cart_contents[$rowid]['options']) === 0) + { + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Product options + * + * Returns the an array of options, for a particular product row ID + * + * @access public + * @return array + */ + function product_options($rowid = '') + { + if ( ! isset($this->_cart_contents[$rowid]['options'])) + { + return array(); + } + + return $this->_cart_contents[$rowid]['options']; + } + + // -------------------------------------------------------------------- + + /** + * Format Number + * + * Returns the supplied number with commas and a decimal point. + * + * @access public + * @return integer + */ + function format_number($n = '') + { + if ($n == '') + { + return ''; + } + + // Remove anything that isn't a number or decimal point. + $n = trim(preg_replace('/([^0-9\.])/i', '', $n)); + + return number_format($n, 2, '.', ','); + } + + // -------------------------------------------------------------------- + + /** + * Destroy the cart + * + * Empties the cart and kills the session + * + * @access public + * @return null + */ + function destroy() + { + unset($this->_cart_contents); + + $this->_cart_contents['cart_total'] = 0; + $this->_cart_contents['total_items'] = 0; + + $this->CI->session->unset_userdata('cart_contents'); + } + + +} +// END Cart Class + +/* End of file Cart.php */ +/* Location: ./system/libraries/Cart.php */ \ No newline at end of file diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php new file mode 100644 index 0000000..4912c4a --- /dev/null +++ b/system/libraries/Driver.php @@ -0,0 +1,229 @@ +lib_name)) + { + $this->lib_name = get_class($this); + } + + // The class will be prefixed with the parent lib + $child_class = $this->lib_name.'_'.$child; + + // Remove the CI_ prefix and lowercase + $lib_name = ucfirst(strtolower(str_replace('CI_', '', $this->lib_name))); + $driver_name = strtolower(str_replace('CI_', '', $child_class)); + + if (in_array($driver_name, array_map('strtolower', $this->valid_drivers))) + { + // check and see if the driver is in a separate file + if ( ! class_exists($child_class)) + { + // check application path first + foreach (get_instance()->load->get_package_paths(TRUE) as $path) + { + // loves me some nesting! + foreach (array(ucfirst($driver_name), $driver_name) as $class) + { + $filepath = $path.'libraries/'.$lib_name.'/drivers/'.$class.'.php'; + + if (file_exists($filepath)) + { + include_once $filepath; + break; + } + } + } + + // it's a valid driver, but the file simply can't be found + if ( ! class_exists($child_class)) + { + log_message('error', "Unable to load the requested driver: ".$child_class); + show_error("Unable to load the requested driver: ".$child_class); + } + } + + $obj = new $child_class; + $obj->decorate($this); + $this->$child = $obj; + return $this->$child; + } + + // The requested driver isn't valid! + log_message('error', "Invalid driver requested: ".$child_class); + show_error("Invalid driver requested: ".$child_class); + } + + // -------------------------------------------------------------------- + +} +// END CI_Driver_Library CLASS + + +/** + * CodeIgniter Driver Class + * + * This class enables you to create drivers for a Library based on the Driver Library. + * It handles the drivers' access to the parent library + * + * @package CodeIgniter + * @subpackage Libraries + * @category Libraries + * @author EllisLab Dev Team + * @link + */ +class CI_Driver { + protected $parent; + + private $methods = array(); + private $properties = array(); + + private static $reflections = array(); + + /** + * Decorate + * + * Decorates the child with the parent driver lib's methods and properties + * + * @param object + * @return void + */ + public function decorate($parent) + { + $this->parent = $parent; + + // Lock down attributes to what is defined in the class + // and speed up references in magic methods + + $class_name = get_class($parent); + + if ( ! isset(self::$reflections[$class_name])) + { + $r = new ReflectionObject($parent); + + foreach ($r->getMethods() as $method) + { + if ($method->isPublic()) + { + $this->methods[] = $method->getName(); + } + } + + foreach ($r->getProperties() as $prop) + { + if ($prop->isPublic()) + { + $this->properties[] = $prop->getName(); + } + } + + self::$reflections[$class_name] = array($this->methods, $this->properties); + } + else + { + list($this->methods, $this->properties) = self::$reflections[$class_name]; + } + } + + // -------------------------------------------------------------------- + + /** + * __call magic method + * + * Handles access to the parent driver library's methods + * + * @access public + * @param string + * @param array + * @return mixed + */ + public function __call($method, $args = array()) + { + if (in_array($method, $this->methods)) + { + return call_user_func_array(array($this->parent, $method), $args); + } + + $trace = debug_backtrace(); + _exception_handler(E_ERROR, "No such method '{$method}'", $trace[1]['file'], $trace[1]['line']); + exit; + } + + // -------------------------------------------------------------------- + + /** + * __get magic method + * + * Handles reading of the parent driver library's properties + * + * @param string + * @return mixed + */ + public function __get($var) + { + if (in_array($var, $this->properties)) + { + return $this->parent->$var; + } + } + + // -------------------------------------------------------------------- + + /** + * __set magic method + * + * Handles writing to the parent driver library's properties + * + * @param string + * @param array + * @return mixed + */ + public function __set($var, $val) + { + if (in_array($var, $this->properties)) + { + $this->parent->$var = $val; + } + } + + // -------------------------------------------------------------------- + +} +// END CI_Driver CLASS + +/* End of file Driver.php */ +/* Location: ./system/libraries/Driver.php */ \ No newline at end of file diff --git a/system/libraries/Email.php b/system/libraries/Email.php new file mode 100644 index 0000000..9ec40af --- /dev/null +++ b/system/libraries/Email.php @@ -0,0 +1,2092 @@ + 0) + { + $this->initialize($config); + } + else + { + $this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE; + $this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE; + } + + log_message('debug', "Email Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize preferences + * + * @access public + * @param array + * @return void + */ + public function initialize($config = array()) + { + foreach ($config as $key => $val) + { + if (isset($this->$key)) + { + $method = 'set_'.$key; + + if (method_exists($this, $method)) + { + $this->$method($val); + } + else + { + $this->$key = $val; + } + } + } + $this->clear(); + + $this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE; + $this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Initialize the Email Data + * + * @access public + * @return void + */ + public function clear($clear_attachments = FALSE) + { + $this->_subject = ""; + $this->_body = ""; + $this->_finalbody = ""; + $this->_header_str = ""; + $this->_replyto_flag = FALSE; + $this->_recipients = array(); + $this->_cc_array = array(); + $this->_bcc_array = array(); + $this->_headers = array(); + $this->_debug_msg = array(); + + $this->_set_header('User-Agent', $this->useragent); + $this->_set_header('Date', $this->_set_date()); + + if ($clear_attachments !== FALSE) + { + $this->_attach_name = array(); + $this->_attach_type = array(); + $this->_attach_disp = array(); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set FROM + * + * @access public + * @param string + * @param string + * @return void + */ + public function from($from, $name = '') + { + if (preg_match( '/\<(.*)\>/', $from, $match)) + { + $from = $match['1']; + } + + if ($this->validate) + { + $this->validate_email($this->_str_to_array($from)); + } + + // prepare the display name + if ($name != '') + { + // only use Q encoding if there are characters that would require it + if ( ! preg_match('/[\200-\377]/', $name)) + { + // add slashes for non-printing characters, slashes, and double quotes, and surround it in double quotes + $name = '"'.addcslashes($name, "\0..\37\177'\"\\").'"'; + } + else + { + $name = $this->_prep_q_encoding($name, TRUE); + } + } + + $this->_set_header('From', $name.' <'.$from.'>'); + $this->_set_header('Return-Path', '<'.$from.'>'); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Reply-to + * + * @access public + * @param string + * @param string + * @return void + */ + public function reply_to($replyto, $name = '') + { + if (preg_match( '/\<(.*)\>/', $replyto, $match)) + { + $replyto = $match['1']; + } + + if ($this->validate) + { + $this->validate_email($this->_str_to_array($replyto)); + } + + if ($name == '') + { + $name = $replyto; + } + + if (strncmp($name, '"', 1) != 0) + { + $name = '"'.$name.'"'; + } + + $this->_set_header('Reply-To', $name.' <'.$replyto.'>'); + $this->_replyto_flag = TRUE; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Recipients + * + * @access public + * @param string + * @return void + */ + public function to($to) + { + $to = $this->_str_to_array($to); + $to = $this->clean_email($to); + + if ($this->validate) + { + $this->validate_email($to); + } + + if ($this->_get_protocol() != 'mail') + { + $this->_set_header('To', implode(", ", $to)); + } + + switch ($this->_get_protocol()) + { + case 'smtp' : + $this->_recipients = $to; + break; + case 'sendmail' : + case 'mail' : + $this->_recipients = implode(", ", $to); + break; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set CC + * + * @access public + * @param string + * @return void + */ + public function cc($cc) + { + $cc = $this->_str_to_array($cc); + $cc = $this->clean_email($cc); + + if ($this->validate) + { + $this->validate_email($cc); + } + + $this->_set_header('Cc', implode(", ", $cc)); + + if ($this->_get_protocol() == "smtp") + { + $this->_cc_array = $cc; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set BCC + * + * @access public + * @param string + * @param string + * @return void + */ + public function bcc($bcc, $limit = '') + { + if ($limit != '' && is_numeric($limit)) + { + $this->bcc_batch_mode = TRUE; + $this->bcc_batch_size = $limit; + } + + $bcc = $this->_str_to_array($bcc); + $bcc = $this->clean_email($bcc); + + if ($this->validate) + { + $this->validate_email($bcc); + } + + if (($this->_get_protocol() == "smtp") OR ($this->bcc_batch_mode && count($bcc) > $this->bcc_batch_size)) + { + $this->_bcc_array = $bcc; + } + else + { + $this->_set_header('Bcc', implode(", ", $bcc)); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Email Subject + * + * @access public + * @param string + * @return void + */ + public function subject($subject) + { + $subject = $this->_prep_q_encoding($subject); + $this->_set_header('Subject', $subject); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Body + * + * @access public + * @param string + * @return void + */ + public function message($body) + { + $this->_body = rtrim(str_replace("\r", "", $body)); + + /* strip slashes only if magic quotes is ON + if we do it with magic quotes OFF, it strips real, user-inputted chars. + + NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and + it will probably not exist in future versions at all. + */ + if ( ! is_php('5.4') && get_magic_quotes_gpc()) + { + $this->_body = stripslashes($this->_body); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Assign file attachments + * + * @access public + * @param string + * @return void + */ + public function attach($filename, $disposition = 'attachment') + { + $this->_attach_name[] = $filename; + $this->_attach_type[] = $this->_mime_types(pathinfo($filename, PATHINFO_EXTENSION)); + $this->_attach_disp[] = $disposition; // Can also be 'inline' Not sure if it matters + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Add a Header Item + * + * @access protected + * @param string + * @param string + * @return void + */ + protected function _set_header($header, $value) + { + $this->_headers[$header] = $value; + } + + // -------------------------------------------------------------------- + + /** + * Convert a String to an Array + * + * @access protected + * @param string + * @return array + */ + protected function _str_to_array($email) + { + if ( ! is_array($email)) + { + if (strpos($email, ',') !== FALSE) + { + $email = preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY); + } + else + { + $email = trim($email); + settype($email, "array"); + } + } + return $email; + } + + // -------------------------------------------------------------------- + + /** + * Set Multipart Value + * + * @access public + * @param string + * @return void + */ + public function set_alt_message($str = '') + { + $this->alt_message = $str; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Mailtype + * + * @access public + * @param string + * @return void + */ + public function set_mailtype($type = 'text') + { + $this->mailtype = ($type == 'html') ? 'html' : 'text'; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Wordwrap + * + * @access public + * @param string + * @return void + */ + public function set_wordwrap($wordwrap = TRUE) + { + $this->wordwrap = ($wordwrap === FALSE) ? FALSE : TRUE; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Protocol + * + * @access public + * @param string + * @return void + */ + public function set_protocol($protocol = 'mail') + { + $this->protocol = ( ! in_array($protocol, $this->_protocols, TRUE)) ? 'mail' : strtolower($protocol); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Priority + * + * @access public + * @param integer + * @return void + */ + public function set_priority($n = 3) + { + if ( ! is_numeric($n)) + { + $this->priority = 3; + return; + } + + if ($n < 1 OR $n > 5) + { + $this->priority = 3; + return; + } + + $this->priority = $n; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Newline Character + * + * @access public + * @param string + * @return void + */ + public function set_newline($newline = "\n") + { + if ($newline != "\n" AND $newline != "\r\n" AND $newline != "\r") + { + $this->newline = "\n"; + return; + } + + $this->newline = $newline; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set CRLF + * + * @access public + * @param string + * @return void + */ + public function set_crlf($crlf = "\n") + { + if ($crlf != "\n" AND $crlf != "\r\n" AND $crlf != "\r") + { + $this->crlf = "\n"; + return; + } + + $this->crlf = $crlf; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Message Boundary + * + * @access protected + * @return void + */ + protected function _set_boundaries() + { + $this->_alt_boundary = "B_ALT_".uniqid(''); // multipart/alternative + $this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary + } + + // -------------------------------------------------------------------- + + /** + * Get the Message ID + * + * @access protected + * @return string + */ + protected function _get_message_id() + { + $from = $this->_headers['Return-Path']; + $from = str_replace(">", "", $from); + $from = str_replace("<", "", $from); + + return "<".uniqid('').strstr($from, '@').">"; + } + + // -------------------------------------------------------------------- + + /** + * Get Mail Protocol + * + * @access protected + * @param bool + * @return string + */ + protected function _get_protocol($return = TRUE) + { + $this->protocol = strtolower($this->protocol); + $this->protocol = ( ! in_array($this->protocol, $this->_protocols, TRUE)) ? 'mail' : $this->protocol; + + if ($return == TRUE) + { + return $this->protocol; + } + } + + // -------------------------------------------------------------------- + + /** + * Get Mail Encoding + * + * @access protected + * @param bool + * @return string + */ + protected function _get_encoding($return = TRUE) + { + $this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '8bit' : $this->_encoding; + + foreach ($this->_base_charsets as $charset) + { + if (strncmp($charset, $this->charset, strlen($charset)) == 0) + { + $this->_encoding = '7bit'; + } + } + + if ($return == TRUE) + { + return $this->_encoding; + } + } + + // -------------------------------------------------------------------- + + /** + * Get content type (text/html/attachment) + * + * @access protected + * @return string + */ + protected function _get_content_type() + { + if ($this->mailtype == 'html' && count($this->_attach_name) == 0) + { + return 'html'; + } + elseif ($this->mailtype == 'html' && count($this->_attach_name) > 0) + { + return 'html-attach'; + } + elseif ($this->mailtype == 'text' && count($this->_attach_name) > 0) + { + return 'plain-attach'; + } + else + { + return 'plain'; + } + } + + // -------------------------------------------------------------------- + + /** + * Set RFC 822 Date + * + * @access protected + * @return string + */ + protected function _set_date() + { + $timezone = date("Z"); + $operator = (strncmp($timezone, '-', 1) == 0) ? '-' : '+'; + $timezone = abs($timezone); + $timezone = floor($timezone/3600) * 100 + ($timezone % 3600 ) / 60; + + return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone); + } + + // -------------------------------------------------------------------- + + /** + * Mime message + * + * @access protected + * @return string + */ + protected function _get_mime_message() + { + return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format."; + } + + // -------------------------------------------------------------------- + + /** + * Validate Email Address + * + * @access public + * @param string + * @return bool + */ + public function validate_email($email) + { + if ( ! is_array($email)) + { + $this->_set_error_message('lang:email_must_be_array'); + return FALSE; + } + + foreach ($email as $val) + { + if ( ! $this->valid_email($val)) + { + $this->_set_error_message('lang:email_invalid_address', $val); + return FALSE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Email Validation + * + * @access public + * @param string + * @return bool + */ + public function valid_email($address) + { + return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Clean Extended Email Address: Joe Smith + * + * @access public + * @param string + * @return string + */ + public function clean_email($email) + { + if ( ! is_array($email)) + { + if (preg_match('/\<(.*)\>/', $email, $match)) + { + return $match['1']; + } + else + { + return $email; + } + } + + $clean_email = array(); + + foreach ($email as $addy) + { + if (preg_match( '/\<(.*)\>/', $addy, $match)) + { + $clean_email[] = $match['1']; + } + else + { + $clean_email[] = $addy; + } + } + + return $clean_email; + } + + // -------------------------------------------------------------------- + + /** + * Build alternative plain text message + * + * This public function provides the raw message for use + * in plain-text headers of HTML-formatted emails. + * If the user hasn't specified his own alternative message + * it creates one by stripping the HTML + * + * @access protected + * @return string + */ + protected function _get_alt_message() + { + if ($this->alt_message != "") + { + return $this->word_wrap($this->alt_message, '76'); + } + + if (preg_match('/\(.*)\<\/body\>/si', $this->_body, $match)) + { + $body = $match['1']; + } + else + { + $body = $this->_body; + } + + $body = trim(strip_tags($body)); + $body = preg_replace( '# '.$msg."\n"; + + flock($fp, LOCK_EX); + fwrite($fp, $message); + flock($fp, LOCK_UN); + fclose($fp); + + @chmod($filepath, FILE_WRITE_MODE); + return TRUE; + } + +} +// END Log Class + +/* End of file Log.php */ +/* Location: ./system/libraries/Log.php */ \ No newline at end of file diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php new file mode 100644 index 0000000..df2dd7c --- /dev/null +++ b/system/libraries/Migration.php @@ -0,0 +1,328 @@ + $val) + { + $this->{'_' . $key} = $val; + } + + log_message('debug', 'Migrations class initialized'); + + // Are they trying to use migrations while it is disabled? + if ($this->_migration_enabled !== TRUE) + { + show_error('Migrations has been loaded but is disabled or set up incorrectly.'); + } + + // If not set, set it + $this->_migration_path == '' AND $this->_migration_path = APPPATH . 'migrations/'; + + // Add trailing slash if not set + $this->_migration_path = rtrim($this->_migration_path, '/').'/'; + + // Load migration language + $this->lang->load('migration'); + + // They'll probably be using dbforge + $this->load->dbforge(); + + // If the migrations table is missing, make it + if ( ! $this->db->table_exists('migrations')) + { + $this->dbforge->add_field(array( + 'version' => array('type' => 'INT', 'constraint' => 3), + )); + + $this->dbforge->create_table('migrations', TRUE); + + $this->db->insert('migrations', array('version' => 0)); + } + } + + // -------------------------------------------------------------------- + + /** + * Migrate to a schema version + * + * Calls each migration step required to get to the schema version of + * choice + * + * @param int Target schema version + * @return mixed TRUE if already latest, FALSE if failed, int if upgraded + */ + public function version($target_version) + { + $start = $current_version = $this->_get_version(); + $stop = $target_version; + + if ($target_version > $current_version) + { + // Moving Up + ++$start; + ++$stop; + $step = 1; + } + else + { + // Moving Down + $step = -1; + } + + $method = ($step === 1) ? 'up' : 'down'; + $migrations = array(); + + // We now prepare to actually DO the migrations + // But first let's make sure that everything is the way it should be + for ($i = $start; $i != $stop; $i += $step) + { + $f = glob(sprintf($this->_migration_path . '%03d_*.php', $i)); + + // Only one migration per step is permitted + if (count($f) > 1) + { + $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $i); + return FALSE; + } + + // Migration step not found + if (count($f) == 0) + { + // If trying to migrate up to a version greater than the last + // existing one, migrate to the last one. + if ($step == 1) + { + break; + } + + // If trying to migrate down but we're missing a step, + // something must definitely be wrong. + $this->_error_string = sprintf($this->lang->line('migration_not_found'), $i); + return FALSE; + } + + $file = basename($f[0]); + $name = basename($f[0], '.php'); + + // Filename validations + if (preg_match('/^\d{3}_(\w+)$/', $name, $match)) + { + $match[1] = strtolower($match[1]); + + // Cannot repeat a migration at different steps + if (in_array($match[1], $migrations)) + { + $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $match[1]); + return FALSE; + } + + include $f[0]; + $class = 'Migration_' . ucfirst($match[1]); + + if ( ! class_exists($class)) + { + $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); + return FALSE; + } + + if ( ! is_callable(array($class, $method))) + { + $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); + return FALSE; + } + + $migrations[] = $match[1]; + } + else + { + $this->_error_string = sprintf($this->lang->line('migration_invalid_filename'), $file); + return FALSE; + } + } + + log_message('debug', 'Current migration: ' . $current_version); + + $version = $i + ($step == 1 ? -1 : 0); + + // If there is nothing to do so quit + if ($migrations === array()) + { + return TRUE; + } + + log_message('debug', 'Migrating from ' . $method . ' to version ' . $version); + + // Loop through the migrations + foreach ($migrations AS $migration) + { + // Run the migration class + $class = 'Migration_' . ucfirst(strtolower($migration)); + call_user_func(array(new $class, $method)); + + $current_version += $step; + $this->_update_version($current_version); + } + + log_message('debug', 'Finished migrating to '.$current_version); + + return $current_version; + } + + // -------------------------------------------------------------------- + + /** + * Set's the schema to the latest migration + * + * @return mixed true if already latest, false if failed, int if upgraded + */ + public function latest() + { + if ( ! $migrations = $this->find_migrations()) + { + $this->_error_string = $this->line->lang('migration_none_found'); + return false; + } + + $last_migration = basename(end($migrations)); + + // Calculate the last migration step from existing migration + // filenames and procceed to the standard version migration + return $this->version((int) substr($last_migration, 0, 3)); + } + + // -------------------------------------------------------------------- + + /** + * Set's the schema to the migration version set in config + * + * @return mixed true if already current, false if failed, int if upgraded + */ + public function current() + { + return $this->version($this->_migration_version); + } + + // -------------------------------------------------------------------- + + /** + * Error string + * + * @return string Error message returned as a string + */ + public function error_string() + { + return $this->_error_string; + } + + // -------------------------------------------------------------------- + + /** + * Set's the schema to the latest migration + * + * @return mixed true if already latest, false if failed, int if upgraded + */ + protected function find_migrations() + { + // Load all *_*.php files in the migrations path + $files = glob($this->_migration_path . '*_*.php'); + $file_count = count($files); + + for ($i = 0; $i < $file_count; $i++) + { + // Mark wrongly formatted files as false for later filtering + $name = basename($files[$i], '.php'); + if ( ! preg_match('/^\d{3}_(\w+)$/', $name)) + { + $files[$i] = FALSE; + } + } + + sort($files); + return $files; + } + + // -------------------------------------------------------------------- + + /** + * Retrieves current schema version + * + * @return int Current Migration + */ + protected function _get_version() + { + $row = $this->db->get('migrations')->row(); + return $row ? $row->version : 0; + } + + // -------------------------------------------------------------------- + + /** + * Stores the current schema version + * + * @param int Migration reached + * @return bool + */ + protected function _update_version($migrations) + { + return $this->db->update('migrations', array( + 'version' => $migrations + )); + } + + // -------------------------------------------------------------------- + + /** + * Enable the use of CI super-global + * + * @param mixed $var + * @return mixed + */ + public function __get($var) + { + return get_instance()->$var; + } +} + +/* End of file Migration.php */ +/* Location: ./system/libraries/Migration.php */ \ No newline at end of file diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php new file mode 100644 index 0000000..cdaacf2 --- /dev/null +++ b/system/libraries/Pagination.php @@ -0,0 +1,340 @@ +'; + var $cur_tag_close = ''; + var $next_tag_open = ' '; + var $next_tag_close = ' '; + var $prev_tag_open = ' '; + var $prev_tag_close = ''; + var $num_tag_open = ' '; + var $num_tag_close = ''; + var $page_query_string = FALSE; + var $query_string_segment = 'per_page'; + var $display_pages = TRUE; + var $anchor_class = ''; + + /** + * Constructor + * + * @access public + * @param array initialization parameters + */ + public function __construct($params = array()) + { + if (count($params) > 0) + { + $this->initialize($params); + } + + if ($this->anchor_class != '') + { + $this->anchor_class = 'class="'.$this->anchor_class.'" '; + } + + log_message('debug', "Pagination Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize Preferences + * + * @access public + * @param array initialization parameters + * @return void + */ + function initialize($params = array()) + { + if (count($params) > 0) + { + foreach ($params as $key => $val) + { + if (isset($this->$key)) + { + $this->$key = $val; + } + } + } + } + + // -------------------------------------------------------------------- + + /** + * Generate the pagination links + * + * @access public + * @return string + */ + function create_links() + { + // If our item count or per-page total is zero there is no need to continue. + if ($this->total_rows == 0 OR $this->per_page == 0) + { + return ''; + } + + // Calculate the total number of pages + $num_pages = ceil($this->total_rows / $this->per_page); + + // Is there only one page? Hm... nothing more to do here then. + if ($num_pages == 1) + { + return ''; + } + + // Set the base page index for starting page number + if ($this->use_page_numbers) + { + $base_page = 1; + } + else + { + $base_page = 0; + } + + // Determine the current page number. + $CI =& get_instance(); + + if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) + { + if ($CI->input->get($this->query_string_segment) != $base_page) + { + $this->cur_page = $CI->input->get($this->query_string_segment); + + // Prep the current page - no funny business! + $this->cur_page = (int) $this->cur_page; + } + } + else + { + if ($CI->uri->segment($this->uri_segment) != $base_page) + { + $this->cur_page = $CI->uri->segment($this->uri_segment); + + // Prep the current page - no funny business! + $this->cur_page = (int) $this->cur_page; + } + } + + // Set current page to 1 if using page numbers instead of offset + if ($this->use_page_numbers AND $this->cur_page == 0) + { + $this->cur_page = $base_page; + } + + $this->num_links = (int)$this->num_links; + + if ($this->num_links < 1) + { + show_error('Your number of links must be a positive number.'); + } + + if ( ! is_numeric($this->cur_page)) + { + $this->cur_page = $base_page; + } + + // Is the page number beyond the result range? + // If so we show the last page + if ($this->use_page_numbers) + { + if ($this->cur_page > $num_pages) + { + $this->cur_page = $num_pages; + } + } + else + { + if ($this->cur_page > $this->total_rows) + { + $this->cur_page = ($num_pages - 1) * $this->per_page; + } + } + + $uri_page_number = $this->cur_page; + + if ( ! $this->use_page_numbers) + { + $this->cur_page = floor(($this->cur_page/$this->per_page) + 1); + } + + // Calculate the start and end numbers. These determine + // which number to start and end the digit links with + $start = (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1; + $end = (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages; + + // Is pagination being used over GET or POST? If get, add a per_page query + // string. If post, add a trailing slash to the base URL if needed + if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) + { + $this->base_url = rtrim($this->base_url).'&'.$this->query_string_segment.'='; + } + else + { + $this->base_url = rtrim($this->base_url, '/') .'/'; + } + + // And here we go... + $output = ''; + + // Render the "First" link + if ($this->first_link !== FALSE AND $this->cur_page > ($this->num_links + 1)) + { + $first_url = ($this->first_url == '') ? $this->base_url : $this->first_url; + $output .= $this->first_tag_open.'anchor_class.'href="'.$first_url.'">'.$this->first_link.''.$this->first_tag_close; + } + + // Render the "previous" link + if ($this->prev_link !== FALSE AND $this->cur_page != 1) + { + if ($this->use_page_numbers) + { + $i = $uri_page_number - 1; + } + else + { + $i = $uri_page_number - $this->per_page; + } + + if ($i == 0 && $this->first_url != '') + { + $output .= $this->prev_tag_open.'anchor_class.'href="'.$this->first_url.'">'.$this->prev_link.''.$this->prev_tag_close; + } + else + { + $i = ($i == 0) ? '' : $this->prefix.$i.$this->suffix; + $output .= $this->prev_tag_open.'anchor_class.'href="'.$this->base_url.$i.'">'.$this->prev_link.''.$this->prev_tag_close; + } + + } + + // Render the pages + if ($this->display_pages !== FALSE) + { + // Write the digit links + for ($loop = $start -1; $loop <= $end; $loop++) + { + if ($this->use_page_numbers) + { + $i = $loop; + } + else + { + $i = ($loop * $this->per_page) - $this->per_page; + } + + if ($i >= $base_page) + { + if ($this->cur_page == $loop) + { + $output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page + } + else + { + $n = ($i == $base_page) ? '' : $i; + + if ($n == '' && $this->first_url != '') + { + $output .= $this->num_tag_open.'anchor_class.'href="'.$this->first_url.'">'.$loop.''.$this->num_tag_close; + } + else + { + $n = ($n == '') ? '' : $this->prefix.$n.$this->suffix; + + $output .= $this->num_tag_open.'anchor_class.'href="'.$this->base_url.$n.'">'.$loop.''.$this->num_tag_close; + } + } + } + } + } + + // Render the "next" link + if ($this->next_link !== FALSE AND $this->cur_page < $num_pages) + { + if ($this->use_page_numbers) + { + $i = $this->cur_page + 1; + } + else + { + $i = ($this->cur_page * $this->per_page); + } + + $output .= $this->next_tag_open.'anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->next_link.''.$this->next_tag_close; + } + + // Render the "Last" link + if ($this->last_link !== FALSE AND ($this->cur_page + $this->num_links) < $num_pages) + { + if ($this->use_page_numbers) + { + $i = $num_pages; + } + else + { + $i = (($num_pages * $this->per_page) - $this->per_page); + } + $output .= $this->last_tag_open.'anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->last_link.''.$this->last_tag_close; + } + + // Kill double slashes. Note: Sometimes we can end up with a double slash + // in the penultimate link so we'll kill all double slashes. + $output = preg_replace("#([^:])//+#", "\\1/", $output); + + // Add the wrapper HTML if exists + $output = $this->full_tag_open.$output.$this->full_tag_close; + + return $output; + } +} +// END Pagination Class + +/* End of file Pagination.php */ +/* Location: ./system/libraries/Pagination.php */ \ No newline at end of file diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php new file mode 100644 index 0000000..d223da0 --- /dev/null +++ b/system/libraries/Parser.php @@ -0,0 +1,212 @@ +load->view($template, $data, TRUE); + + return $this->_parse($template, $data, $return); + } + + // -------------------------------------------------------------------- + + /** + * Parse a String + * + * Parses pseudo-variables contained in the specified string, + * replacing them with the data in the second param + * + * @access public + * @param string + * @param array + * @param bool + * @return string + */ + function parse_string($template, $data, $return = FALSE) + { + return $this->_parse($template, $data, $return); + } + + // -------------------------------------------------------------------- + + /** + * Parse a template + * + * Parses pseudo-variables contained in the specified template, + * replacing them with the data in the second param + * + * @access public + * @param string + * @param array + * @param bool + * @return string + */ + function _parse($template, $data, $return = FALSE) + { + if ($template == '') + { + return FALSE; + } + + foreach ($data as $key => $val) + { + if (is_array($val)) + { + $template = $this->_parse_pair($key, $val, $template); + } + else + { + $template = $this->_parse_single($key, (string)$val, $template); + } + } + + if ($return == FALSE) + { + $CI =& get_instance(); + $CI->output->append_output($template); + } + + return $template; + } + + // -------------------------------------------------------------------- + + /** + * Set the left/right variable delimiters + * + * @access public + * @param string + * @param string + * @return void + */ + function set_delimiters($l = '{', $r = '}') + { + $this->l_delim = $l; + $this->r_delim = $r; + } + + // -------------------------------------------------------------------- + + /** + * Parse a single key/value + * + * @access private + * @param string + * @param string + * @param string + * @return string + */ + function _parse_single($key, $val, $string) + { + return str_replace($this->l_delim.$key.$this->r_delim, $val, $string); + } + + // -------------------------------------------------------------------- + + /** + * Parse a tag pair + * + * Parses tag pairs: {some_tag} string... {/some_tag} + * + * @access private + * @param string + * @param array + * @param string + * @return string + */ + function _parse_pair($variable, $data, $string) + { + if (FALSE === ($match = $this->_match_pair($string, $variable))) + { + return $string; + } + + $str = ''; + foreach ($data as $row) + { + $temp = $match['1']; + foreach ($row as $key => $val) + { + if ( ! is_array($val)) + { + $temp = $this->_parse_single($key, $val, $temp); + } + else + { + $temp = $this->_parse_pair($key, $val, $temp); + } + } + + $str .= $temp; + } + + return str_replace($match['0'], $str, $string); + } + + // -------------------------------------------------------------------- + + /** + * Matches a variable pair + * + * @access private + * @param string + * @param string + * @return mixed + */ + function _match_pair($string, $variable) + { + if ( ! preg_match("|" . preg_quote($this->l_delim) . $variable . preg_quote($this->r_delim) . "(.+?)". preg_quote($this->l_delim) . '/' . $variable . preg_quote($this->r_delim) . "|s", $string, $match)) + { + return FALSE; + } + + return $match; + } + +} +// END Parser Class + +/* End of file Parser.php */ +/* Location: ./system/libraries/Parser.php */ diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php new file mode 100644 index 0000000..882a82c --- /dev/null +++ b/system/libraries/Profiler.php @@ -0,0 +1,558 @@ +CI =& get_instance(); + $this->CI->load->language('profiler'); + + if (isset($config['query_toggle_count'])) + { + $this->_query_toggle_count = (int) $config['query_toggle_count']; + unset($config['query_toggle_count']); + } + + // default all sections to display + foreach ($this->_available_sections as $section) + { + if ( ! isset($config[$section])) + { + $this->_compile_{$section} = TRUE; + } + } + + $this->set_sections($config); + } + + // -------------------------------------------------------------------- + + /** + * Set Sections + * + * Sets the private _compile_* properties to enable/disable Profiler sections + * + * @param mixed + * @return void + */ + public function set_sections($config) + { + foreach ($config as $method => $enable) + { + if (in_array($method, $this->_available_sections)) + { + $this->_compile_{$method} = ($enable !== FALSE) ? TRUE : FALSE; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Auto Profiler + * + * This function cycles through the entire array of mark points and + * matches any two points that are named identically (ending in "_start" + * and "_end" respectively). It then compiles the execution times for + * all points and returns it as an array + * + * @return array + */ + protected function _compile_benchmarks() + { + $profile = array(); + foreach ($this->CI->benchmark->marker as $key => $val) + { + // We match the "end" marker so that the list ends + // up in the order that it was defined + if (preg_match("/(.+?)_end/i", $key, $match)) + { + if (isset($this->CI->benchmark->marker[$match[1].'_end']) AND isset($this->CI->benchmark->marker[$match[1].'_start'])) + { + $profile[$match[1]] = $this->CI->benchmark->elapsed_time($match[1].'_start', $key); + } + } + } + + // Build a table containing the profile data. + // Note: At some point we should turn this into a template that can + // be modified. We also might want to make this data available to be logged + + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_benchmarks').'  '; + $output .= "\n"; + $output .= "\n\n\n"; + + foreach ($profile as $key => $val) + { + $key = ucwords(str_replace(array('_', '-'), ' ', $key)); + $output .= "\n"; + } + + $output .= "
    ".$key."  ".$val."
    \n"; + $output .= "
    "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Compile Queries + * + * @return string + */ + protected function _compile_queries() + { + $dbs = array(); + + // Let's determine which databases are currently connected to + foreach (get_object_vars($this->CI) as $CI_object) + { + if (is_object($CI_object) && is_subclass_of(get_class($CI_object), 'CI_DB') ) + { + $dbs[] = $CI_object; + } + } + + if (count($dbs) == 0) + { + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_queries').'  '; + $output .= "\n"; + $output .= "\n\n\n"; + $output .="\n"; + $output .= "
    ".$this->CI->lang->line('profiler_no_db')."
    \n"; + $output .= "
    "; + + return $output; + } + + // Load the text helper so we can highlight the SQL + $this->CI->load->helper('text'); + + // Key words we want bolded + $highlight = array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'AND', 'LEFT JOIN', 'ORDER BY', 'GROUP BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR ', 'HAVING', 'OFFSET', 'NOT IN', 'IN', 'LIKE', 'NOT LIKE', 'COUNT', 'MAX', 'MIN', 'ON', 'AS', 'AVG', 'SUM', '(', ')'); + + $output = "\n\n"; + + $count = 0; + + foreach ($dbs as $db) + { + $count++; + + $hide_queries = (count($db->queries) > $this->_query_toggle_count) ? ' display:none' : ''; + + $show_hide_js = '('.$this->CI->lang->line('profiler_section_hide').')'; + + if ($hide_queries != '') + { + $show_hide_js = '('.$this->CI->lang->line('profiler_section_show').')'; + } + + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_database').':  '.$db->database.'   '.$this->CI->lang->line('profiler_queries').': '.count($db->queries).'  '.$show_hide_js.''; + $output .= "\n"; + $output .= "\n\n\n"; + + if (count($db->queries) == 0) + { + $output .= "\n"; + } + else + { + foreach ($db->queries as $key => $val) + { + $time = number_format($db->query_times[$key], 4); + + $val = highlight_code($val, ENT_QUOTES); + + foreach ($highlight as $bold) + { + $val = str_replace($bold, ''.$bold.'', $val); + } + + $output .= "\n"; + } + } + + $output .= "
    ".$this->CI->lang->line('profiler_no_queries')."
    ".$time."  ".$val."
    \n"; + $output .= "
    "; + + } + + return $output; + } + + + // -------------------------------------------------------------------- + + /** + * Compile $_GET Data + * + * @return string + */ + protected function _compile_get() + { + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_get_data').'  '; + $output .= "\n"; + + if (count($_GET) == 0) + { + $output .= "
    ".$this->CI->lang->line('profiler_no_get')."
    "; + } + else + { + $output .= "\n\n\n"; + + foreach ($_GET as $key => $val) + { + if ( ! is_numeric($key)) + { + $key = "'".$key."'"; + } + + $output .= "\n"; + } + + $output .= "
    $_GET[".$key."]   "; + if (is_array($val)) + { + $output .= "
    " . htmlspecialchars(stripslashes(print_r($val, true))) . "
    "; + } + else + { + $output .= htmlspecialchars(stripslashes($val)); + } + $output .= "
    \n"; + } + $output .= "
    "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Compile $_POST Data + * + * @return string + */ + protected function _compile_post() + { + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_post_data').'  '; + $output .= "\n"; + + if (count($_POST) == 0) + { + $output .= "
    ".$this->CI->lang->line('profiler_no_post')."
    "; + } + else + { + $output .= "\n\n\n"; + + foreach ($_POST as $key => $val) + { + if ( ! is_numeric($key)) + { + $key = "'".$key."'"; + } + + $output .= "\n"; + } + + $output .= "
    $_POST[".$key."]   "; + if (is_array($val)) + { + $output .= "
    " . htmlspecialchars(stripslashes(print_r($val, TRUE))) . "
    "; + } + else + { + $output .= htmlspecialchars(stripslashes($val)); + } + $output .= "
    \n"; + } + $output .= "
    "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Show query string + * + * @return string + */ + protected function _compile_uri_string() + { + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_uri_string').'  '; + $output .= "\n"; + + if ($this->CI->uri->uri_string == '') + { + $output .= "
    ".$this->CI->lang->line('profiler_no_uri')."
    "; + } + else + { + $output .= "
    ".$this->CI->uri->uri_string."
    "; + } + + $output .= "
    "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Show the controller and function that were called + * + * @return string + */ + protected function _compile_controller_info() + { + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_controller_info').'  '; + $output .= "\n"; + + $output .= "
    ".$this->CI->router->fetch_class()."/".$this->CI->router->fetch_method()."
    "; + + $output .= "
    "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Compile memory usage + * + * Display total used memory + * + * @return string + */ + protected function _compile_memory_usage() + { + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_memory_usage').'  '; + $output .= "\n"; + + if (function_exists('memory_get_usage') && ($usage = memory_get_usage()) != '') + { + $output .= "
    ".number_format($usage).' bytes
    '; + } + else + { + $output .= "
    ".$this->CI->lang->line('profiler_no_memory')."
    "; + } + + $output .= "
    "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Compile header information + * + * Lists HTTP headers + * + * @return string + */ + protected function _compile_http_headers() + { + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_headers').'  ('.$this->CI->lang->line('profiler_section_show').')'; + $output .= "\n"; + + $output .= "\n\n\n"; + + foreach (array('HTTP_ACCEPT', 'HTTP_USER_AGENT', 'HTTP_CONNECTION', 'SERVER_PORT', 'SERVER_NAME', 'REMOTE_ADDR', 'SERVER_SOFTWARE', 'HTTP_ACCEPT_LANGUAGE', 'SCRIPT_NAME', 'REQUEST_METHOD',' HTTP_HOST', 'REMOTE_HOST', 'CONTENT_TYPE', 'SERVER_PROTOCOL', 'QUERY_STRING', 'HTTP_ACCEPT_ENCODING', 'HTTP_X_FORWARDED_FOR') as $header) + { + $val = (isset($_SERVER[$header])) ? $_SERVER[$header] : ''; + $output .= "\n"; + } + + $output .= "\n"; + $output .= "
    "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Compile config information + * + * Lists developer config variables + * + * @return string + */ + protected function _compile_config() + { + $output = "\n\n"; + $output .= '
    '; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_config').'  ('.$this->CI->lang->line('profiler_section_show').')'; + $output .= "\n"; + + $output .= "\n\n\n"; + + foreach ($this->CI->config->config as $config=>$val) + { + if (is_array($val)) + { + $val = print_r($val, TRUE); + } + + $output .= "\n"; + } + + $output .= "\n"; + $output .= "
    "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Compile session userdata + * + * @return string + */ + private function _compile_session_data() + { + if ( ! isset($this->CI->session)) + { + return; + } + + $output = '
    '; + $output .= '  '.$this->CI->lang->line('profiler_session_data').'  ('.$this->CI->lang->line('profiler_section_show').')'; + $output .= ""; + + foreach ($this->CI->session->all_userdata() as $key => $val) + { + if (is_array($val) OR is_object($val)) + { + $val = print_r($val, TRUE); + } + + $output .= "\n"; + } + + $output .= ''; + $output .= "
    "; + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Run the Profiler + * + * @return string + */ + public function run() + { + $output = "
    "; + $fields_displayed = 0; + + foreach ($this->_available_sections as $section) + { + if ($this->_compile_{$section} !== FALSE) + { + $func = "_compile_{$section}"; + $output .= $this->{$func}(); + $fields_displayed++; + } + } + + if ($fields_displayed == 0) + { + $output .= '

    '.$this->CI->lang->line('profiler_no_profiles').'

    '; + } + + $output .= '
    '; + + return $output; + } +} + +// END CI_Profiler class + +/* End of file Profiler.php */ +/* Location: ./system/libraries/Profiler.php */ \ No newline at end of file diff --git a/system/libraries/Session.php b/system/libraries/Session.php new file mode 100644 index 0000000..891fdd3 --- /dev/null +++ b/system/libraries/Session.php @@ -0,0 +1,780 @@ +CI =& get_instance(); + + // Set all the session preferences, which can either be set + // manually via the $params array above or via the config file + foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) + { + $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key); + } + + if ($this->encryption_key == '') + { + show_error('In order to use the Session class you are required to set an encryption key in your config file.'); + } + + // Load the string helper so we can use the strip_slashes() function + $this->CI->load->helper('string'); + + // Do we need encryption? If so, load the encryption class + if ($this->sess_encrypt_cookie == TRUE) + { + $this->CI->load->library('encrypt'); + } + + // Are we using a database? If so, load it + if ($this->sess_use_database === TRUE AND $this->sess_table_name != '') + { + $this->CI->load->database(); + } + + // Set the "now" time. Can either be GMT or server time, based on the + // config prefs. We use this to set the "last activity" time + $this->now = $this->_get_time(); + + // Set the session length. If the session expiration is + // set to zero we'll set the expiration two years from now. + if ($this->sess_expiration == 0) + { + $this->sess_expiration = (60*60*24*365*2); + } + + // Set the cookie name + $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; + + // Run the Session routine. If a session doesn't exist we'll + // create a new one. If it does, we'll update it. + if ( ! $this->sess_read()) + { + $this->sess_create(); + } + else + { + $this->sess_update(); + } + + // Delete 'old' flashdata (from last request) + $this->_flashdata_sweep(); + + // Mark all new flashdata as old (data will be deleted before next request) + $this->_flashdata_mark(); + + // Delete expired sessions if necessary + $this->_sess_gc(); + + log_message('debug', "Session routines successfully run"); + } + + // -------------------------------------------------------------------- + + /** + * Fetch the current session data if it exists + * + * @access public + * @return bool + */ + function sess_read() + { + // Fetch the cookie + $session = $this->CI->input->cookie($this->sess_cookie_name); + + // No cookie? Goodbye cruel world!... + if ($session === FALSE) + { + log_message('debug', 'A session cookie was not found.'); + return FALSE; + } + + // Decrypt the cookie data + if ($this->sess_encrypt_cookie == TRUE) + { + $session = $this->CI->encrypt->decode($session); + } + else + { + // encryption was not used, so we need to check the md5 hash + $hash = substr($session, strlen($session)-32); // get last 32 chars + $session = substr($session, 0, strlen($session)-32); + + // Does the md5 hash match? This is to prevent manipulation of session data in userspace + if ($hash !== md5($session.$this->encryption_key)) + { + log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.'); + $this->sess_destroy(); + return FALSE; + } + } + + // Unserialize the session array + $session = $this->_unserialize($session); + + // Is the session data we unserialized an array with the correct format? + if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity'])) + { + $this->sess_destroy(); + return FALSE; + } + + // Is the session current? + if (($session['last_activity'] + $this->sess_expiration) < $this->now) + { + $this->sess_destroy(); + return FALSE; + } + + // Does the IP Match? + if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address()) + { + $this->sess_destroy(); + return FALSE; + } + + // Does the User Agent Match? + if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 120))) + { + $this->sess_destroy(); + return FALSE; + } + + // Is there a corresponding session in the DB? + if ($this->sess_use_database === TRUE) + { + $this->CI->db->where('session_id', $session['session_id']); + + if ($this->sess_match_ip == TRUE) + { + $this->CI->db->where('ip_address', $session['ip_address']); + } + + if ($this->sess_match_useragent == TRUE) + { + $this->CI->db->where('user_agent', $session['user_agent']); + } + + $query = $this->CI->db->get($this->sess_table_name); + + // No result? Kill it! + if ($query->num_rows() == 0) + { + $this->sess_destroy(); + return FALSE; + } + + // Is there custom data? If so, add it to the main session array + $row = $query->row(); + if (isset($row->user_data) AND $row->user_data != '') + { + $custom_data = $this->_unserialize($row->user_data); + + if (is_array($custom_data)) + { + foreach ($custom_data as $key => $val) + { + $session[$key] = $val; + } + } + } + } + + // Session is valid! + $this->userdata = $session; + unset($session); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Write the session data + * + * @access public + * @return void + */ + function sess_write() + { + // Are we saving custom data to the DB? If not, all we do is update the cookie + if ($this->sess_use_database === FALSE) + { + $this->_set_cookie(); + return; + } + + // set the custom userdata, the session data we will set in a second + $custom_userdata = $this->userdata; + $cookie_userdata = array(); + + // Before continuing, we need to determine if there is any custom data to deal with. + // Let's determine this by removing the default indexes to see if there's anything left in the array + // and set the session data while we're at it + foreach (array('session_id','ip_address','user_agent','last_activity') as $val) + { + unset($custom_userdata[$val]); + $cookie_userdata[$val] = $this->userdata[$val]; + } + + // Did we find any custom data? If not, we turn the empty array into a string + // since there's no reason to serialize and store an empty array in the DB + if (count($custom_userdata) === 0) + { + $custom_userdata = ''; + } + else + { + // Serialize the custom data array so we can store it + $custom_userdata = $this->_serialize($custom_userdata); + } + + // Run the update query + $this->CI->db->where('session_id', $this->userdata['session_id']); + $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata)); + + // Write the cookie. Notice that we manually pass the cookie data array to the + // _set_cookie() function. Normally that function will store $this->userdata, but + // in this case that array contains custom data, which we do not want in the cookie. + $this->_set_cookie($cookie_userdata); + } + + // -------------------------------------------------------------------- + + /** + * Create a new session + * + * @access public + * @return void + */ + function sess_create() + { + $sessid = ''; + while (strlen($sessid) < 32) + { + $sessid .= mt_rand(0, mt_getrandmax()); + } + + // To make the session ID even more secure we'll combine it with the user's IP + $sessid .= $this->CI->input->ip_address(); + + $this->userdata = array( + 'session_id' => md5(uniqid($sessid, TRUE)), + 'ip_address' => $this->CI->input->ip_address(), + 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), + 'last_activity' => $this->now, + 'user_data' => '' + ); + + + // Save the data to the DB if needed + if ($this->sess_use_database === TRUE) + { + $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata)); + } + + // Write the cookie + $this->_set_cookie(); + } + + // -------------------------------------------------------------------- + + /** + * Update an existing session + * + * @access public + * @return void + */ + function sess_update() + { + // We only update the session every five minutes by default + if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) + { + return; + } + + // Save the old session id so we know which record to + // update in the database if we need it + $old_sessid = $this->userdata['session_id']; + $new_sessid = ''; + while (strlen($new_sessid) < 32) + { + $new_sessid .= mt_rand(0, mt_getrandmax()); + } + + // To make the session ID even more secure we'll combine it with the user's IP + $new_sessid .= $this->CI->input->ip_address(); + + // Turn it into a hash + $new_sessid = md5(uniqid($new_sessid, TRUE)); + + // Update the session data in the session data array + $this->userdata['session_id'] = $new_sessid; + $this->userdata['last_activity'] = $this->now; + + // _set_cookie() will handle this for us if we aren't using database sessions + // by pushing all userdata to the cookie. + $cookie_data = NULL; + + // Update the session ID and last_activity field in the DB if needed + if ($this->sess_use_database === TRUE) + { + // set cookie explicitly to only have our session data + $cookie_data = array(); + foreach (array('session_id','ip_address','user_agent','last_activity') as $val) + { + $cookie_data[$val] = $this->userdata[$val]; + } + + $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid))); + } + + // Write the cookie + $this->_set_cookie($cookie_data); + } + + // -------------------------------------------------------------------- + + /** + * Destroy the current session + * + * @access public + * @return void + */ + function sess_destroy() + { + // Kill the session DB row + if ($this->sess_use_database === TRUE && isset($this->userdata['session_id'])) + { + $this->CI->db->where('session_id', $this->userdata['session_id']); + $this->CI->db->delete($this->sess_table_name); + } + + // Kill the cookie + setcookie( + $this->sess_cookie_name, + addslashes(serialize(array())), + ($this->now - 31500000), + $this->cookie_path, + $this->cookie_domain, + 0 + ); + + // Kill session data + $this->userdata = array(); + } + + // -------------------------------------------------------------------- + + /** + * Fetch a specific item from the session array + * + * @access public + * @param string + * @return string + */ + function userdata($item) + { + return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item]; + } + + // -------------------------------------------------------------------- + + /** + * Fetch all session data + * + * @access public + * @return array + */ + function all_userdata() + { + return $this->userdata; + } + + // -------------------------------------------------------------------- + + /** + * Add or change data in the "userdata" array + * + * @access public + * @param mixed + * @param string + * @return void + */ + function set_userdata($newdata = array(), $newval = '') + { + if (is_string($newdata)) + { + $newdata = array($newdata => $newval); + } + + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $this->userdata[$key] = $val; + } + } + + $this->sess_write(); + } + + // -------------------------------------------------------------------- + + /** + * Delete a session variable from the "userdata" array + * + * @access array + * @return void + */ + function unset_userdata($newdata = array()) + { + if (is_string($newdata)) + { + $newdata = array($newdata => ''); + } + + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + unset($this->userdata[$key]); + } + } + + $this->sess_write(); + } + + // ------------------------------------------------------------------------ + + /** + * Add or change flashdata, only available + * until the next request + * + * @access public + * @param mixed + * @param string + * @return void + */ + function set_flashdata($newdata = array(), $newval = '') + { + if (is_string($newdata)) + { + $newdata = array($newdata => $newval); + } + + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $flashdata_key = $this->flashdata_key.':new:'.$key; + $this->set_userdata($flashdata_key, $val); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Keeps existing flashdata available to next request. + * + * @access public + * @param string + * @return void + */ + function keep_flashdata($key) + { + // 'old' flashdata gets removed. Here we mark all + // flashdata as 'new' to preserve it from _flashdata_sweep() + // Note the function will return FALSE if the $key + // provided cannot be found + $old_flashdata_key = $this->flashdata_key.':old:'.$key; + $value = $this->userdata($old_flashdata_key); + + $new_flashdata_key = $this->flashdata_key.':new:'.$key; + $this->set_userdata($new_flashdata_key, $value); + } + + // ------------------------------------------------------------------------ + + /** + * Fetch a specific flashdata item from the session array + * + * @access public + * @param string + * @return string + */ + function flashdata($key) + { + $flashdata_key = $this->flashdata_key.':old:'.$key; + return $this->userdata($flashdata_key); + } + + // ------------------------------------------------------------------------ + + /** + * Identifies flashdata as 'old' for removal + * when _flashdata_sweep() runs. + * + * @access private + * @return void + */ + function _flashdata_mark() + { + $userdata = $this->all_userdata(); + foreach ($userdata as $name => $value) + { + $parts = explode(':new:', $name); + if (is_array($parts) && count($parts) === 2) + { + $new_name = $this->flashdata_key.':old:'.$parts[1]; + $this->set_userdata($new_name, $value); + $this->unset_userdata($name); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Removes all flashdata marked as 'old' + * + * @access private + * @return void + */ + + function _flashdata_sweep() + { + $userdata = $this->all_userdata(); + foreach ($userdata as $key => $value) + { + if (strpos($key, ':old:')) + { + $this->unset_userdata($key); + } + } + + } + + // -------------------------------------------------------------------- + + /** + * Get the "now" time + * + * @access private + * @return string + */ + function _get_time() + { + if (strtolower($this->time_reference) == 'gmt') + { + $now = time(); + $time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now)); + } + else + { + $time = time(); + } + + return $time; + } + + // -------------------------------------------------------------------- + + /** + * Write the session cookie + * + * @access public + * @return void + */ + function _set_cookie($cookie_data = NULL) + { + if (is_null($cookie_data)) + { + $cookie_data = $this->userdata; + } + + // Serialize the userdata for the cookie + $cookie_data = $this->_serialize($cookie_data); + + if ($this->sess_encrypt_cookie == TRUE) + { + $cookie_data = $this->CI->encrypt->encode($cookie_data); + } + else + { + // if encryption is not used, we provide an md5 hash to prevent userside tampering + $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); + } + + $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); + + // Set the cookie + setcookie( + $this->sess_cookie_name, + $cookie_data, + $expire, + $this->cookie_path, + $this->cookie_domain, + $this->cookie_secure + ); + } + + // -------------------------------------------------------------------- + + /** + * Serialize an array + * + * This function first converts any slashes found in the array to a temporary + * marker, so when it gets unserialized the slashes will be preserved + * + * @access private + * @param array + * @return string + */ + function _serialize($data) + { + if (is_array($data)) + { + foreach ($data as $key => $val) + { + if (is_string($val)) + { + $data[$key] = str_replace('\\', '{{slash}}', $val); + } + } + } + else + { + if (is_string($data)) + { + $data = str_replace('\\', '{{slash}}', $data); + } + } + + return serialize($data); + } + + // -------------------------------------------------------------------- + + /** + * Unserialize + * + * This function unserializes a data string, then converts any + * temporary slash markers back to actual slashes + * + * @access private + * @param array + * @return string + */ + function _unserialize($data) + { + $data = @unserialize(strip_slashes($data)); + + if (is_array($data)) + { + foreach ($data as $key => $val) + { + if (is_string($val)) + { + $data[$key] = str_replace('{{slash}}', '\\', $val); + } + } + + return $data; + } + + return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data; + } + + // -------------------------------------------------------------------- + + /** + * Garbage collection + * + * This deletes expired session rows from database + * if the probability percentage is met + * + * @access public + * @return void + */ + function _sess_gc() + { + if ($this->sess_use_database != TRUE) + { + return; + } + + srand(time()); + if ((rand() % 100) < $this->gc_probability) + { + $expire = $this->now - $this->sess_expiration; + + $this->CI->db->where("last_activity < {$expire}"); + $this->CI->db->delete($this->sess_table_name); + + log_message('debug', 'Session garbage collection performed.'); + } + } + + +} +// END Session Class + +/* End of file Session.php */ +/* Location: ./system/libraries/Session.php */ \ No newline at end of file diff --git a/system/libraries/Sha1.php b/system/libraries/Sha1.php new file mode 100644 index 0000000..1a65757 --- /dev/null +++ b/system/libraries/Sha1.php @@ -0,0 +1,251 @@ +> 6) + 1; + + for ($i = 0; $i < $n * 16; $i++) + { + $x[$i] = 0; + } + + for ($i = 0; $i < strlen($str); $i++) + { + $x[$i >> 2] |= ord(substr($str, $i, 1)) << (24 - ($i % 4) * 8); + } + + $x[$i >> 2] |= 0x80 << (24 - ($i % 4) * 8); + + $x[$n * 16 - 1] = strlen($str) * 8; + + $a = 1732584193; + $b = -271733879; + $c = -1732584194; + $d = 271733878; + $e = -1009589776; + + for ($i = 0; $i < count($x); $i += 16) + { + $olda = $a; + $oldb = $b; + $oldc = $c; + $oldd = $d; + $olde = $e; + + for ($j = 0; $j < 80; $j++) + { + if ($j < 16) + { + $w[$j] = $x[$i + $j]; + } + else + { + $w[$j] = $this->_rol($w[$j - 3] ^ $w[$j - 8] ^ $w[$j - 14] ^ $w[$j - 16], 1); + } + + $t = $this->_safe_add($this->_safe_add($this->_rol($a, 5), $this->_ft($j, $b, $c, $d)), $this->_safe_add($this->_safe_add($e, $w[$j]), $this->_kt($j))); + + $e = $d; + $d = $c; + $c = $this->_rol($b, 30); + $b = $a; + $a = $t; + } + + $a = $this->_safe_add($a, $olda); + $b = $this->_safe_add($b, $oldb); + $c = $this->_safe_add($c, $oldc); + $d = $this->_safe_add($d, $oldd); + $e = $this->_safe_add($e, $olde); + } + + return $this->_hex($a).$this->_hex($b).$this->_hex($c).$this->_hex($d).$this->_hex($e); + } + + // -------------------------------------------------------------------- + + /** + * Convert a decimal to hex + * + * @access private + * @param string + * @return string + */ + function _hex($str) + { + $str = dechex($str); + + if (strlen($str) == 7) + { + $str = '0'.$str; + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Return result based on iteration + * + * @access private + * @return string + */ + function _ft($t, $b, $c, $d) + { + if ($t < 20) + return ($b & $c) | ((~$b) & $d); + if ($t < 40) + return $b ^ $c ^ $d; + if ($t < 60) + return ($b & $c) | ($b & $d) | ($c & $d); + + return $b ^ $c ^ $d; + } + + // -------------------------------------------------------------------- + + /** + * Determine the additive constant + * + * @access private + * @return string + */ + function _kt($t) + { + if ($t < 20) + { + return 1518500249; + } + else if ($t < 40) + { + return 1859775393; + } + else if ($t < 60) + { + return -1894007588; + } + else + { + return -899497514; + } + } + + // -------------------------------------------------------------------- + + /** + * Add integers, wrapping at 2^32 + * + * @access private + * @return string + */ + function _safe_add($x, $y) + { + $lsw = ($x & 0xFFFF) + ($y & 0xFFFF); + $msw = ($x >> 16) + ($y >> 16) + ($lsw >> 16); + + return ($msw << 16) | ($lsw & 0xFFFF); + } + + // -------------------------------------------------------------------- + + /** + * Bitwise rotate a 32-bit number + * + * @access private + * @return integer + */ + function _rol($num, $cnt) + { + return ($num << $cnt) | $this->_zero_fill($num, 32 - $cnt); + } + + // -------------------------------------------------------------------- + + /** + * Pad string with zero + * + * @access private + * @return string + */ + function _zero_fill($a, $b) + { + $bin = decbin($a); + + if (strlen($bin) < $b) + { + $bin = 0; + } + else + { + $bin = substr($bin, 0, strlen($bin) - $b); + } + + for ($i=0; $i < $b; $i++) + { + $bin = "0".$bin; + } + + return bindec($bin); + } +} +// END CI_SHA + +/* End of file Sha1.php */ +/* Location: ./system/libraries/Sha1.php */ \ No newline at end of file diff --git a/system/libraries/Table.php b/system/libraries/Table.php new file mode 100644 index 0000000..def6967 --- /dev/null +++ b/system/libraries/Table.php @@ -0,0 +1,531 @@ +template = $template; + } + + // -------------------------------------------------------------------- + + /** + * Set the table heading + * + * Can be passed as an array or discreet params + * + * @access public + * @param mixed + * @return void + */ + function set_heading() + { + $args = func_get_args(); + $this->heading = $this->_prep_args($args); + } + + // -------------------------------------------------------------------- + + /** + * Set columns. Takes a one-dimensional array as input and creates + * a multi-dimensional array with a depth equal to the number of + * columns. This allows a single array with many elements to be + * displayed in a table that has a fixed column count. + * + * @access public + * @param array + * @param int + * @return void + */ + function make_columns($array = array(), $col_limit = 0) + { + if ( ! is_array($array) OR count($array) == 0) + { + return FALSE; + } + + // Turn off the auto-heading feature since it's doubtful we + // will want headings from a one-dimensional array + $this->auto_heading = FALSE; + + if ($col_limit == 0) + { + return $array; + } + + $new = array(); + while (count($array) > 0) + { + $temp = array_splice($array, 0, $col_limit); + + if (count($temp) < $col_limit) + { + for ($i = count($temp); $i < $col_limit; $i++) + { + $temp[] = ' '; + } + } + + $new[] = $temp; + } + + return $new; + } + + // -------------------------------------------------------------------- + + /** + * Set "empty" cells + * + * Can be passed as an array or discreet params + * + * @access public + * @param mixed + * @return void + */ + function set_empty($value) + { + $this->empty_cells = $value; + } + + // -------------------------------------------------------------------- + + /** + * Add a table row + * + * Can be passed as an array or discreet params + * + * @access public + * @param mixed + * @return void + */ + function add_row() + { + $args = func_get_args(); + $this->rows[] = $this->_prep_args($args); + } + + // -------------------------------------------------------------------- + + /** + * Prep Args + * + * Ensures a standard associative array format for all cell data + * + * @access public + * @param type + * @return type + */ + function _prep_args($args) + { + // If there is no $args[0], skip this and treat as an associative array + // This can happen if there is only a single key, for example this is passed to table->generate + // array(array('foo'=>'bar')) + if (isset($args[0]) AND (count($args) == 1 && is_array($args[0]))) + { + // args sent as indexed array + if ( ! isset($args[0]['data'])) + { + foreach ($args[0] as $key => $val) + { + if (is_array($val) && isset($val['data'])) + { + $args[$key] = $val; + } + else + { + $args[$key] = array('data' => $val); + } + } + } + } + else + { + foreach ($args as $key => $val) + { + if ( ! is_array($val)) + { + $args[$key] = array('data' => $val); + } + } + } + + return $args; + } + + // -------------------------------------------------------------------- + + /** + * Add a table caption + * + * @access public + * @param string + * @return void + */ + function set_caption($caption) + { + $this->caption = $caption; + } + + // -------------------------------------------------------------------- + + /** + * Generate the table + * + * @access public + * @param mixed + * @return string + */ + function generate($table_data = NULL) + { + // The table data can optionally be passed to this function + // either as a database result object or an array + if ( ! is_null($table_data)) + { + if (is_object($table_data)) + { + $this->_set_from_object($table_data); + } + elseif (is_array($table_data)) + { + $set_heading = (count($this->heading) == 0 AND $this->auto_heading == FALSE) ? FALSE : TRUE; + $this->_set_from_array($table_data, $set_heading); + } + } + + // Is there anything to display? No? Smite them! + if (count($this->heading) == 0 AND count($this->rows) == 0) + { + return 'Undefined table data'; + } + + // Compile and validate the template date + $this->_compile_template(); + + // set a custom cell manipulation function to a locally scoped variable so its callable + $function = $this->function; + + // Build the table! + + $out = $this->template['table_open']; + $out .= $this->newline; + + // Add any caption here + if ($this->caption) + { + $out .= $this->newline; + $out .= '' . $this->caption . ''; + $out .= $this->newline; + } + + // Is there a table heading to display? + if (count($this->heading) > 0) + { + $out .= $this->template['thead_open']; + $out .= $this->newline; + $out .= $this->template['heading_row_start']; + $out .= $this->newline; + + foreach ($this->heading as $heading) + { + $temp = $this->template['heading_cell_start']; + + foreach ($heading as $key => $val) + { + if ($key != 'data') + { + $temp = str_replace('template['heading_cell_end']; + } + + $out .= $this->template['heading_row_end']; + $out .= $this->newline; + $out .= $this->template['thead_close']; + $out .= $this->newline; + } + + // Build the table rows + if (count($this->rows) > 0) + { + $out .= $this->template['tbody_open']; + $out .= $this->newline; + + $i = 1; + foreach ($this->rows as $row) + { + if ( ! is_array($row)) + { + break; + } + + // We use modulus to alternate the row colors + $name = (fmod($i++, 2)) ? '' : 'alt_'; + + $out .= $this->template['row_'.$name.'start']; + $out .= $this->newline; + + foreach ($row as $cell) + { + $temp = $this->template['cell_'.$name.'start']; + + foreach ($cell as $key => $val) + { + if ($key != 'data') + { + $temp = str_replace('empty_cells; + } + else + { + if ($function !== FALSE && is_callable($function)) + { + $out .= call_user_func($function, $cell); + } + else + { + $out .= $cell; + } + } + + $out .= $this->template['cell_'.$name.'end']; + } + + $out .= $this->template['row_'.$name.'end']; + $out .= $this->newline; + } + + $out .= $this->template['tbody_close']; + $out .= $this->newline; + } + + $out .= $this->template['table_close']; + + // Clear table class properties before generating the table + $this->clear(); + + return $out; + } + + // -------------------------------------------------------------------- + + /** + * Clears the table arrays. Useful if multiple tables are being generated + * + * @access public + * @return void + */ + function clear() + { + $this->rows = array(); + $this->heading = array(); + $this->auto_heading = TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set table data from a database result object + * + * @access public + * @param object + * @return void + */ + function _set_from_object($query) + { + if ( ! is_object($query)) + { + return FALSE; + } + + // First generate the headings from the table column names + if (count($this->heading) == 0) + { + if ( ! method_exists($query, 'list_fields')) + { + return FALSE; + } + + $this->heading = $this->_prep_args($query->list_fields()); + } + + // Next blast through the result array and build out the rows + + if ($query->num_rows() > 0) + { + foreach ($query->result_array() as $row) + { + $this->rows[] = $this->_prep_args($row); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Set table data from an array + * + * @access public + * @param array + * @return void + */ + function _set_from_array($data, $set_heading = TRUE) + { + if ( ! is_array($data) OR count($data) == 0) + { + return FALSE; + } + + $i = 0; + foreach ($data as $row) + { + // If a heading hasn't already been set we'll use the first row of the array as the heading + if ($i == 0 AND count($data) > 1 AND count($this->heading) == 0 AND $set_heading == TRUE) + { + $this->heading = $this->_prep_args($row); + } + else + { + $this->rows[] = $this->_prep_args($row); + } + + $i++; + } + } + + // -------------------------------------------------------------------- + + /** + * Compile Template + * + * @access private + * @return void + */ + function _compile_template() + { + if ($this->template == NULL) + { + $this->template = $this->_default_template(); + return; + } + + $this->temp = $this->_default_template(); + foreach (array('table_open', 'thead_open', 'thead_close', 'heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end', 'tbody_open', 'tbody_close', 'row_start', 'row_end', 'cell_start', 'cell_end', 'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end', 'table_close') as $val) + { + if ( ! isset($this->template[$val])) + { + $this->template[$val] = $this->temp[$val]; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Default Template + * + * @access private + * @return void + */ + function _default_template() + { + return array ( + 'table_open' => '', + + 'thead_open' => '', + 'thead_close' => '', + + 'heading_row_start' => '', + 'heading_row_end' => '', + 'heading_cell_start' => '', + + 'tbody_open' => '', + 'tbody_close' => '', + + 'row_start' => '', + 'row_end' => '', + 'cell_start' => '', + + 'row_alt_start' => '', + 'row_alt_end' => '', + 'cell_alt_start' => '', + + 'table_close' => '
    ', + 'heading_cell_end' => '
    ', + 'cell_end' => '
    ', + 'cell_alt_end' => '
    ' + ); + } + + +} + + +/* End of file Table.php */ +/* Location: ./system/libraries/Table.php */ \ No newline at end of file diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php new file mode 100644 index 0000000..b0a7678 --- /dev/null +++ b/system/libraries/Trackback.php @@ -0,0 +1,548 @@ + '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => ''); + var $convert_ascii = TRUE; + var $response = ''; + var $error_msg = array(); + + /** + * Constructor + * + * @access public + */ + public function __construct() + { + log_message('debug', "Trackback Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Send Trackback + * + * @access public + * @param array + * @return bool + */ + function send($tb_data) + { + if ( ! is_array($tb_data)) + { + $this->set_error('The send() method must be passed an array'); + return FALSE; + } + + // Pre-process the Trackback Data + foreach (array('url', 'title', 'excerpt', 'blog_name', 'ping_url') as $item) + { + if ( ! isset($tb_data[$item])) + { + $this->set_error('Required item missing: '.$item); + return FALSE; + } + + switch ($item) + { + case 'ping_url' : $$item = $this->extract_urls($tb_data[$item]); + break; + case 'excerpt' : $$item = $this->limit_characters($this->convert_xml(strip_tags(stripslashes($tb_data[$item])))); + break; + case 'url' : $$item = str_replace('-', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item])))); + break; + default : $$item = $this->convert_xml(strip_tags(stripslashes($tb_data[$item]))); + break; + } + + // Convert High ASCII Characters + if ($this->convert_ascii == TRUE) + { + if ($item == 'excerpt') + { + $$item = $this->convert_ascii($$item); + } + elseif ($item == 'title') + { + $$item = $this->convert_ascii($$item); + } + elseif ($item == 'blog_name') + { + $$item = $this->convert_ascii($$item); + } + } + } + + // Build the Trackback data string + $charset = ( ! isset($tb_data['charset'])) ? $this->charset : $tb_data['charset']; + + $data = "url=".rawurlencode($url)."&title=".rawurlencode($title)."&blog_name=".rawurlencode($blog_name)."&excerpt=".rawurlencode($excerpt)."&charset=".rawurlencode($charset); + + // Send Trackback(s) + $return = TRUE; + if (count($ping_url) > 0) + { + foreach ($ping_url as $url) + { + if ($this->process($url, $data) == FALSE) + { + $return = FALSE; + } + } + } + + return $return; + } + + // -------------------------------------------------------------------- + + /** + * Receive Trackback Data + * + * This function simply validates the incoming TB data. + * It returns FALSE on failure and TRUE on success. + * If the data is valid it is set to the $this->data array + * so that it can be inserted into a database. + * + * @access public + * @return bool + */ + function receive() + { + foreach (array('url', 'title', 'blog_name', 'excerpt') as $val) + { + if ( ! isset($_POST[$val]) OR $_POST[$val] == '') + { + $this->set_error('The following required POST variable is missing: '.$val); + return FALSE; + } + + $this->data['charset'] = ( ! isset($_POST['charset'])) ? 'auto' : strtoupper(trim($_POST['charset'])); + + if ($val != 'url' && function_exists('mb_convert_encoding')) + { + $_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']); + } + + $_POST[$val] = ($val != 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]); + + if ($val == 'excerpt') + { + $_POST['excerpt'] = $this->limit_characters($_POST['excerpt']); + } + + $this->data[$val] = $_POST[$val]; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Send Trackback Error Message + * + * Allows custom errors to be set. By default it + * sends the "incomplete information" error, as that's + * the most common one. + * + * @access public + * @param string + * @return void + */ + function send_error($message = 'Incomplete Information') + { + echo "\n\n1\n".$message."\n"; + exit; + } + + // -------------------------------------------------------------------- + + /** + * Send Trackback Success Message + * + * This should be called when a trackback has been + * successfully received and inserted. + * + * @access public + * @return void + */ + function send_success() + { + echo "\n\n0\n"; + exit; + } + + // -------------------------------------------------------------------- + + /** + * Fetch a particular item + * + * @access public + * @param string + * @return string + */ + function data($item) + { + return ( ! isset($this->data[$item])) ? '' : $this->data[$item]; + } + + // -------------------------------------------------------------------- + + /** + * Process Trackback + * + * Opens a socket connection and passes the data to + * the server. Returns TRUE on success, FALSE on failure + * + * @access public + * @param string + * @param string + * @return bool + */ + function process($url, $data) + { + $target = parse_url($url); + + // Open the socket + if ( ! $fp = @fsockopen($target['host'], 80)) + { + $this->set_error('Invalid Connection: '.$url); + return FALSE; + } + + // Build the path + $ppath = ( ! isset($target['path'])) ? $url : $target['path']; + + $path = (isset($target['query']) && $target['query'] != "") ? $ppath.'?'.$target['query'] : $ppath; + + // Add the Trackback ID to the data string + if ($id = $this->get_id($url)) + { + $data = "tb_id=".$id."&".$data; + } + + // Transfer the data + fputs ($fp, "POST " . $path . " HTTP/1.0\r\n" ); + fputs ($fp, "Host: " . $target['host'] . "\r\n" ); + fputs ($fp, "Content-type: application/x-www-form-urlencoded\r\n" ); + fputs ($fp, "Content-length: " . strlen($data) . "\r\n" ); + fputs ($fp, "Connection: close\r\n\r\n" ); + fputs ($fp, $data); + + // Was it successful? + $this->response = ""; + + while ( ! feof($fp)) + { + $this->response .= fgets($fp, 128); + } + @fclose($fp); + + + if (stristr($this->response, '0') === FALSE) + { + $message = 'An unknown error was encountered'; + + if (preg_match("/(.*?)<\/message>/is", $this->response, $match)) + { + $message = trim($match['1']); + } + + $this->set_error($message); + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Extract Trackback URLs + * + * This function lets multiple trackbacks be sent. + * It takes a string of URLs (separated by comma or + * space) and puts each URL into an array + * + * @access public + * @param string + * @return string + */ + function extract_urls($urls) + { + // Remove the pesky white space and replace with a comma. + $urls = preg_replace("/\s*(\S+)\s*/", "\\1,", $urls); + + // If they use commas get rid of the doubles. + $urls = str_replace(",,", ",", $urls); + + // Remove any comma that might be at the end + if (substr($urls, -1) == ",") + { + $urls = substr($urls, 0, -1); + } + + // Break into an array via commas + $urls = preg_split('/[,]/', $urls); + + // Removes duplicates + $urls = array_unique($urls); + + array_walk($urls, array($this, 'validate_url')); + + return $urls; + } + + // -------------------------------------------------------------------- + + /** + * Validate URL + * + * Simply adds "http://" if missing + * + * @access public + * @param string + * @return string + */ + function validate_url($url) + { + $url = trim($url); + + if (substr($url, 0, 4) != "http") + { + $url = "http://".$url; + } + } + + // -------------------------------------------------------------------- + + /** + * Find the Trackback URL's ID + * + * @access public + * @param string + * @return string + */ + function get_id($url) + { + $tb_id = ""; + + if (strpos($url, '?') !== FALSE) + { + $tb_array = explode('/', $url); + $tb_end = $tb_array[count($tb_array)-1]; + + if ( ! is_numeric($tb_end)) + { + $tb_end = $tb_array[count($tb_array)-2]; + } + + $tb_array = explode('=', $tb_end); + $tb_id = $tb_array[count($tb_array)-1]; + } + else + { + $url = rtrim($url, '/'); + + $tb_array = explode('/', $url); + $tb_id = $tb_array[count($tb_array)-1]; + + if ( ! is_numeric($tb_id)) + { + $tb_id = $tb_array[count($tb_array)-2]; + } + } + + if ( ! preg_match ("/^([0-9]+)$/", $tb_id)) + { + return FALSE; + } + else + { + return $tb_id; + } + } + + // -------------------------------------------------------------------- + + /** + * Convert Reserved XML characters to Entities + * + * @access public + * @param string + * @return string + */ + function convert_xml($str) + { + $temp = '__TEMP_AMPERSANDS__'; + + $str = preg_replace("/&#(\d+);/", "$temp\\1;", $str); + $str = preg_replace("/&(\w+);/", "$temp\\1;", $str); + + $str = str_replace(array("&","<",">","\"", "'", "-"), + array("&", "<", ">", """, "'", "-"), + $str); + + $str = preg_replace("/$temp(\d+);/","&#\\1;",$str); + $str = preg_replace("/$temp(\w+);/","&\\1;", $str); + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Character limiter + * + * Limits the string based on the character count. Will preserve complete words. + * + * @access public + * @param string + * @param integer + * @param string + * @return string + */ + function limit_characters($str, $n = 500, $end_char = '…') + { + if (strlen($str) < $n) + { + return $str; + } + + $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str)); + + if (strlen($str) <= $n) + { + return $str; + } + + $out = ""; + foreach (explode(' ', trim($str)) as $val) + { + $out .= $val.' '; + if (strlen($out) >= $n) + { + return trim($out).$end_char; + } + } + } + + // -------------------------------------------------------------------- + + /** + * High ASCII to Entities + * + * Converts Hight ascii text and MS Word special chars + * to character entities + * + * @access public + * @param string + * @return string + */ + function convert_ascii($str) + { + $count = 1; + $out = ''; + $temp = array(); + + for ($i = 0, $s = strlen($str); $i < $s; $i++) + { + $ordinal = ord($str[$i]); + + if ($ordinal < 128) + { + $out .= $str[$i]; + } + else + { + if (count($temp) == 0) + { + $count = ($ordinal < 224) ? 2 : 3; + } + + $temp[] = $ordinal; + + if (count($temp) == $count) + { + $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64); + + $out .= '&#'.$number.';'; + $count = 1; + $temp = array(); + } + } + } + + return $out; + } + + // -------------------------------------------------------------------- + + /** + * Set error message + * + * @access public + * @param string + * @return void + */ + function set_error($msg) + { + log_message('error', $msg); + $this->error_msg[] = $msg; + } + + // -------------------------------------------------------------------- + + /** + * Show error messages + * + * @access public + * @param string + * @param string + * @return string + */ + function display_errors($open = '

    ', $close = '

    ') + { + $str = ''; + foreach ($this->error_msg as $val) + { + $str .= $open.$val.$close; + } + + return $str; + } + +} +// END Trackback Class + +/* End of file Trackback.php */ +/* Location: ./system/libraries/Trackback.php */ \ No newline at end of file diff --git a/system/libraries/Typography.php b/system/libraries/Typography.php new file mode 100644 index 0000000..734cec1 --- /dev/null +++ b/system/libraries/Typography.php @@ -0,0 +1,410 @@ + tags + var $block_elements = 'address|blockquote|div|dl|fieldset|form|h\d|hr|noscript|object|ol|p|pre|script|table|ul'; + + // Elements that should not have

    and
    tags within them. + var $skip_elements = 'p|pre|ol|ul|dl|object|table|h\d'; + + // Tags we want the parser to completely ignore when splitting the string. + var $inline_elements = 'a|abbr|acronym|b|bdo|big|br|button|cite|code|del|dfn|em|i|img|ins|input|label|map|kbd|q|samp|select|small|span|strong|sub|sup|textarea|tt|var'; + + // array of block level elements that require inner content to be within another block level element + var $inner_block_required = array('blockquote'); + + // the last block element parsed + var $last_block_element = ''; + + // whether or not to protect quotes within { curly braces } + var $protect_braced_quotes = FALSE; + + /** + * Auto Typography + * + * This function converts text, making it typographically correct: + * - Converts double spaces into paragraphs. + * - Converts single line breaks into
    tags + * - Converts single and double quotes into correctly facing curly quote entities. + * - Converts three dots into ellipsis. + * - Converts double dashes into em-dashes. + * - Converts two spaces into entities + * + * @access public + * @param string + * @param bool whether to reduce more then two consecutive newlines to two + * @return string + */ + function auto_typography($str, $reduce_linebreaks = FALSE) + { + if ($str == '') + { + return ''; + } + + // Standardize Newlines to make matching easier + if (strpos($str, "\r") !== FALSE) + { + $str = str_replace(array("\r\n", "\r"), "\n", $str); + } + + // Reduce line breaks. If there are more than two consecutive linebreaks + // we'll compress them down to a maximum of two since there's no benefit to more. + if ($reduce_linebreaks === TRUE) + { + $str = preg_replace("/\n\n+/", "\n\n", $str); + } + + // HTML comment tags don't conform to patterns of normal tags, so pull them out separately, only if needed + $html_comments = array(); + if (strpos($str, '", + "'", + "<", + ">", + '"', + '&', + '$', + '=', + ';', + '?', + '/', + "%20", + "%22", + "%3c", // < + "%253c", // < + "%3e", // > + "%0e", // > + "%28", // ( + "%29", // ) + "%2528", // ( + "%26", // & + "%24", // $ + "%3f", // ? + "%3b", // ; + "%3d" // = + ); + + $filename = str_replace($bad, '', $filename); + + return stripslashes($filename); + } + + // -------------------------------------------------------------------- + + /** + * Limit the File Name Length + * + * @param string + * @return string + */ + public function limit_filename_length($filename, $length) + { + if (strlen($filename) < $length) + { + return $filename; + } + + $ext = ''; + if (strpos($filename, '.') !== FALSE) + { + $parts = explode('.', $filename); + $ext = '.'.array_pop($parts); + $filename = implode('.', $parts); + } + + return substr($filename, 0, ($length - strlen($ext))).$ext; + } + + // -------------------------------------------------------------------- + + /** + * Runs the file through the XSS clean function + * + * This prevents people from embedding malicious code in their files. + * I'm not sure that it won't negatively affect certain files in unexpected ways, + * but so far I haven't found that it causes trouble. + * + * @return void + */ + public function do_xss_clean() + { + $file = $this->file_temp; + + if (filesize($file) == 0) + { + return FALSE; + } + + if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit') != '') + { + $current = ini_get('memory_limit') * 1024 * 1024; + + // There was a bug/behavioural change in PHP 5.2, where numbers over one million get output + // into scientific notation. number_format() ensures this number is an integer + // http://bugs.php.net/bug.php?id=43053 + + $new_memory = number_format(ceil(filesize($file) + $current), 0, '.', ''); + + ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net + } + + // If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but + // IE can be fooled into mime-type detecting a malformed image as an html file, thus executing an XSS attack on anyone + // using IE who looks at the image. It does this by inspecting the first 255 bytes of an image. To get around this + // CI will itself look at the first 255 bytes of an image to determine its relative safety. This can save a lot of + // processor power and time if it is actually a clean image, as it will be in nearly all instances _except_ an + // attempted XSS attack. + + if (function_exists('getimagesize') && @getimagesize($file) !== FALSE) + { + if (($file = @fopen($file, 'rb')) === FALSE) // "b" to force binary + { + return FALSE; // Couldn't open the file, return FALSE + } + + $opening_bytes = fread($file, 256); + fclose($file); + + // These are known to throw IE into mime-type detection chaos + // ]/i', $opening_bytes)) + { + return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good + } + else + { + return FALSE; + } + } + + if (($data = @file_get_contents($file)) === FALSE) + { + return FALSE; + } + + $CI =& get_instance(); + return $CI->security->xss_clean($data, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Set an error message + * + * @param string + * @return void + */ + public function set_error($msg) + { + $CI =& get_instance(); + $CI->lang->load('upload'); + + if (is_array($msg)) + { + foreach ($msg as $val) + { + $msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val); + $this->error_msg[] = $msg; + log_message('error', $msg); + } + } + else + { + $msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg); + $this->error_msg[] = $msg; + log_message('error', $msg); + } + } + + // -------------------------------------------------------------------- + + /** + * Display the error message + * + * @param string + * @param string + * @return string + */ + public function display_errors($open = '

    ', $close = '

    ') + { + $str = ''; + foreach ($this->error_msg as $val) + { + $str .= $open.$val.$close; + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * List of Mime Types + * + * This is a list of mime types. We use it to validate + * the "allowed types" set by the developer + * + * @param string + * @return string + */ + public function mimes_types($mime) + { + global $mimes; + + if (count($this->mimes) == 0) + { + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'); + } + elseif (is_file(APPPATH.'config/mimes.php')) + { + include(APPPATH.'config//mimes.php'); + } + else + { + return FALSE; + } + + $this->mimes = $mimes; + unset($mimes); + } + + return ( ! isset($this->mimes[$mime])) ? FALSE : $this->mimes[$mime]; + } + + // -------------------------------------------------------------------- + + /** + * Prep Filename + * + * Prevents possible script execution from Apache's handling of files multiple extensions + * http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext + * + * @param string + * @return string + */ + protected function _prep_filename($filename) + { + if (strpos($filename, '.') === FALSE OR $this->allowed_types == '*') + { + return $filename; + } + + $parts = explode('.', $filename); + $ext = array_pop($parts); + $filename = array_shift($parts); + + foreach ($parts as $part) + { + if ( ! in_array(strtolower($part), $this->allowed_types) OR $this->mimes_types(strtolower($part)) === FALSE) + { + $filename .= '.'.$part.'_'; + } + else + { + $filename .= '.'.$part; + } + } + + $filename .= '.'.$ext; + + return $filename; + } + + // -------------------------------------------------------------------- + + /** + * File MIME type + * + * Detects the (actual) MIME type of the uploaded file, if possible. + * The input array is expected to be $_FILES[$field] + * + * @param array + * @return void + */ + protected function _file_mime_type($file) + { + // We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii) + $regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/'; + + /* Fileinfo extension - most reliable method + * + * Unfortunately, prior to PHP 5.3 - it's only available as a PECL extension and the + * more convenient FILEINFO_MIME_TYPE flag doesn't exist. + */ + if (function_exists('finfo_file')) + { + $finfo = finfo_open(FILEINFO_MIME); + if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system + { + $mime = @finfo_file($finfo, $file['tmp_name']); + finfo_close($finfo); + + /* According to the comments section of the PHP manual page, + * it is possible that this function returns an empty string + * for some files (e.g. if they don't exist in the magic MIME database) + */ + if (is_string($mime) && preg_match($regexp, $mime, $matches)) + { + $this->file_type = $matches[1]; + return; + } + } + } + + /* This is an ugly hack, but UNIX-type systems provide a "native" way to detect the file type, + * which is still more secure than depending on the value of $_FILES[$field]['type'], and as it + * was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better + * than mime_content_type() as well, hence the attempts to try calling the command line with + * three different functions. + * + * Notes: + * - the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system + * - many system admins would disable the exec(), shell_exec(), popen() and similar functions + * due to security concerns, hence the function_exists() checks + */ + if (DIRECTORY_SEPARATOR !== '\\') + { + $cmd = 'file --brief --mime ' . escapeshellarg($file['tmp_name']) . ' 2>&1'; + + if (function_exists('exec')) + { + /* This might look confusing, as $mime is being populated with all of the output when set in the second parameter. + * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites + * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy + * value, which is only put to allow us to get the return status code. + */ + $mime = @exec($cmd, $mime, $return_status); + if ($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches)) + { + $this->file_type = $matches[1]; + return; + } + } + + if ( (bool) @ini_get('safe_mode') === FALSE && function_exists('shell_exec')) + { + $mime = @shell_exec($cmd); + if (strlen($mime) > 0) + { + $mime = explode("\n", trim($mime)); + if (preg_match($regexp, $mime[(count($mime) - 1)], $matches)) + { + $this->file_type = $matches[1]; + return; + } + } + } + + if (function_exists('popen')) + { + $proc = @popen($cmd, 'r'); + if (is_resource($proc)) + { + $mime = @fread($proc, 512); + @pclose($proc); + if ($mime !== FALSE) + { + $mime = explode("\n", trim($mime)); + if (preg_match($regexp, $mime[(count($mime) - 1)], $matches)) + { + $this->file_type = $matches[1]; + return; + } + } + } + } + } + + // Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type']) + if (function_exists('mime_content_type')) + { + $this->file_type = @mime_content_type($file['tmp_name']); + if (strlen($this->file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string + { + return; + } + } + + $this->file_type = $file['type']; + } + + // -------------------------------------------------------------------- + +} +// END Upload Class + +/* End of file Upload.php */ +/* Location: ./system/libraries/Upload.php */ diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php new file mode 100644 index 0000000..0b77a7d --- /dev/null +++ b/system/libraries/User_agent.php @@ -0,0 +1,549 @@ +agent = trim($_SERVER['HTTP_USER_AGENT']); + } + + if ( ! is_null($this->agent)) + { + if ($this->_load_agent_file()) + { + $this->_compile_data(); + } + } + + log_message('debug', "User Agent Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Compile the User Agent Data + * + * @access private + * @return bool + */ + private function _load_agent_file() + { + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php'); + } + elseif (is_file(APPPATH.'config/user_agents.php')) + { + include(APPPATH.'config/user_agents.php'); + } + else + { + return FALSE; + } + + $return = FALSE; + + if (isset($platforms)) + { + $this->platforms = $platforms; + unset($platforms); + $return = TRUE; + } + + if (isset($browsers)) + { + $this->browsers = $browsers; + unset($browsers); + $return = TRUE; + } + + if (isset($mobiles)) + { + $this->mobiles = $mobiles; + unset($mobiles); + $return = TRUE; + } + + if (isset($robots)) + { + $this->robots = $robots; + unset($robots); + $return = TRUE; + } + + return $return; + } + + // -------------------------------------------------------------------- + + /** + * Compile the User Agent Data + * + * @access private + * @return bool + */ + private function _compile_data() + { + $this->_set_platform(); + + foreach (array('_set_robot', '_set_browser', '_set_mobile') as $function) + { + if ($this->$function() === TRUE) + { + break; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Set the Platform + * + * @access private + * @return mixed + */ + private function _set_platform() + { + if (is_array($this->platforms) AND count($this->platforms) > 0) + { + foreach ($this->platforms as $key => $val) + { + if (preg_match("|".preg_quote($key)."|i", $this->agent)) + { + $this->platform = $val; + return TRUE; + } + } + } + $this->platform = 'Unknown Platform'; + } + + // -------------------------------------------------------------------- + + /** + * Set the Browser + * + * @access private + * @return bool + */ + private function _set_browser() + { + if (is_array($this->browsers) AND count($this->browsers) > 0) + { + foreach ($this->browsers as $key => $val) + { + if (preg_match("|".preg_quote($key).".*?([0-9\.]+)|i", $this->agent, $match)) + { + $this->is_browser = TRUE; + $this->version = $match[1]; + $this->browser = $val; + $this->_set_mobile(); + return TRUE; + } + } + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Set the Robot + * + * @access private + * @return bool + */ + private function _set_robot() + { + if (is_array($this->robots) AND count($this->robots) > 0) + { + foreach ($this->robots as $key => $val) + { + if (preg_match("|".preg_quote($key)."|i", $this->agent)) + { + $this->is_robot = TRUE; + $this->robot = $val; + return TRUE; + } + } + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Set the Mobile Device + * + * @access private + * @return bool + */ + private function _set_mobile() + { + if (is_array($this->mobiles) AND count($this->mobiles) > 0) + { + foreach ($this->mobiles as $key => $val) + { + if (FALSE !== (strpos(strtolower($this->agent), $key))) + { + $this->is_mobile = TRUE; + $this->mobile = $val; + return TRUE; + } + } + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Set the accepted languages + * + * @access private + * @return void + */ + private function _set_languages() + { + if ((count($this->languages) == 0) AND isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) AND $_SERVER['HTTP_ACCEPT_LANGUAGE'] != '') + { + $languages = preg_replace('/(;q=[0-9\.]+)/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_LANGUAGE']))); + + $this->languages = explode(',', $languages); + } + + if (count($this->languages) == 0) + { + $this->languages = array('Undefined'); + } + } + + // -------------------------------------------------------------------- + + /** + * Set the accepted character sets + * + * @access private + * @return void + */ + private function _set_charsets() + { + if ((count($this->charsets) == 0) AND isset($_SERVER['HTTP_ACCEPT_CHARSET']) AND $_SERVER['HTTP_ACCEPT_CHARSET'] != '') + { + $charsets = preg_replace('/(;q=.+)/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET']))); + + $this->charsets = explode(',', $charsets); + } + + if (count($this->charsets) == 0) + { + $this->charsets = array('Undefined'); + } + } + + // -------------------------------------------------------------------- + + /** + * Is Browser + * + * @access public + * @return bool + */ + public function is_browser($key = NULL) + { + if ( ! $this->is_browser) + { + return FALSE; + } + + // No need to be specific, it's a browser + if ($key === NULL) + { + return TRUE; + } + + // Check for a specific browser + return array_key_exists($key, $this->browsers) AND $this->browser === $this->browsers[$key]; + } + + // -------------------------------------------------------------------- + + /** + * Is Robot + * + * @access public + * @return bool + */ + public function is_robot($key = NULL) + { + if ( ! $this->is_robot) + { + return FALSE; + } + + // No need to be specific, it's a robot + if ($key === NULL) + { + return TRUE; + } + + // Check for a specific robot + return array_key_exists($key, $this->robots) AND $this->robot === $this->robots[$key]; + } + + // -------------------------------------------------------------------- + + /** + * Is Mobile + * + * @access public + * @return bool + */ + public function is_mobile($key = NULL) + { + if ( ! $this->is_mobile) + { + return FALSE; + } + + // No need to be specific, it's a mobile + if ($key === NULL) + { + return TRUE; + } + + // Check for a specific robot + return array_key_exists($key, $this->mobiles) AND $this->mobile === $this->mobiles[$key]; + } + + // -------------------------------------------------------------------- + + /** + * Is this a referral from another site? + * + * @access public + * @return bool + */ + public function is_referral() + { + if ( ! isset($_SERVER['HTTP_REFERER']) OR $_SERVER['HTTP_REFERER'] == '') + { + return FALSE; + } + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Agent String + * + * @access public + * @return string + */ + public function agent_string() + { + return $this->agent; + } + + // -------------------------------------------------------------------- + + /** + * Get Platform + * + * @access public + * @return string + */ + public function platform() + { + return $this->platform; + } + + // -------------------------------------------------------------------- + + /** + * Get Browser Name + * + * @access public + * @return string + */ + public function browser() + { + return $this->browser; + } + + // -------------------------------------------------------------------- + + /** + * Get the Browser Version + * + * @access public + * @return string + */ + public function version() + { + return $this->version; + } + + // -------------------------------------------------------------------- + + /** + * Get The Robot Name + * + * @access public + * @return string + */ + public function robot() + { + return $this->robot; + } + // -------------------------------------------------------------------- + + /** + * Get the Mobile Device + * + * @access public + * @return string + */ + public function mobile() + { + return $this->mobile; + } + + // -------------------------------------------------------------------- + + /** + * Get the referrer + * + * @access public + * @return bool + */ + public function referrer() + { + return ( ! isset($_SERVER['HTTP_REFERER']) OR $_SERVER['HTTP_REFERER'] == '') ? '' : trim($_SERVER['HTTP_REFERER']); + } + + // -------------------------------------------------------------------- + + /** + * Get the accepted languages + * + * @access public + * @return array + */ + public function languages() + { + if (count($this->languages) == 0) + { + $this->_set_languages(); + } + + return $this->languages; + } + + // -------------------------------------------------------------------- + + /** + * Get the accepted Character Sets + * + * @access public + * @return array + */ + public function charsets() + { + if (count($this->charsets) == 0) + { + $this->_set_charsets(); + } + + return $this->charsets; + } + + // -------------------------------------------------------------------- + + /** + * Test for a particular language + * + * @access public + * @return bool + */ + public function accept_lang($lang = 'en') + { + return (in_array(strtolower($lang), $this->languages(), TRUE)); + } + + // -------------------------------------------------------------------- + + /** + * Test for a particular character set + * + * @access public + * @return bool + */ + public function accept_charset($charset = 'utf-8') + { + return (in_array(strtolower($charset), $this->charsets(), TRUE)); + } + +} + + +/* End of file User_agent.php */ +/* Location: ./system/libraries/User_agent.php */ \ No newline at end of file diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php new file mode 100644 index 0000000..d702e90 --- /dev/null +++ b/system/libraries/Xmlrpc.php @@ -0,0 +1,1423 @@ +xmlrpcName = $this->xmlrpcName; + $this->xmlrpc_backslash = chr(92).chr(92); + + // Types for info sent back and forth + $this->xmlrpcTypes = array( + $this->xmlrpcI4 => '1', + $this->xmlrpcInt => '1', + $this->xmlrpcBoolean => '1', + $this->xmlrpcString => '1', + $this->xmlrpcDouble => '1', + $this->xmlrpcDateTime => '1', + $this->xmlrpcBase64 => '1', + $this->xmlrpcArray => '2', + $this->xmlrpcStruct => '3' + ); + + // Array of Valid Parents for Various XML-RPC elements + $this->valid_parents = array('BOOLEAN' => array('VALUE'), + 'I4' => array('VALUE'), + 'INT' => array('VALUE'), + 'STRING' => array('VALUE'), + 'DOUBLE' => array('VALUE'), + 'DATETIME.ISO8601' => array('VALUE'), + 'BASE64' => array('VALUE'), + 'ARRAY' => array('VALUE'), + 'STRUCT' => array('VALUE'), + 'PARAM' => array('PARAMS'), + 'METHODNAME' => array('METHODCALL'), + 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), + 'MEMBER' => array('STRUCT'), + 'NAME' => array('MEMBER'), + 'DATA' => array('ARRAY'), + 'FAULT' => array('METHODRESPONSE'), + 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT') + ); + + + // XML-RPC Responses + $this->xmlrpcerr['unknown_method'] = '1'; + $this->xmlrpcstr['unknown_method'] = 'This is not a known method for this XML-RPC Server'; + $this->xmlrpcerr['invalid_return'] = '2'; + $this->xmlrpcstr['invalid_return'] = 'The XML data received was either invalid or not in the correct form for XML-RPC. Turn on debugging to examine the XML data further.'; + $this->xmlrpcerr['incorrect_params'] = '3'; + $this->xmlrpcstr['incorrect_params'] = 'Incorrect parameters were passed to method'; + $this->xmlrpcerr['introspect_unknown'] = '4'; + $this->xmlrpcstr['introspect_unknown'] = "Cannot inspect signature for request: method unknown"; + $this->xmlrpcerr['http_error'] = '5'; + $this->xmlrpcstr['http_error'] = "Did not receive a '200 OK' response from remote server."; + $this->xmlrpcerr['no_data'] = '6'; + $this->xmlrpcstr['no_data'] ='No data received from server.'; + + $this->initialize($config); + + log_message('debug', "XML-RPC Class Initialized"); + } + + + //------------------------------------- + // Initialize Prefs + //------------------------------------- + + function initialize($config = array()) + { + if (count($config) > 0) + { + foreach ($config as $key => $val) + { + if (isset($this->$key)) + { + $this->$key = $val; + } + } + } + } + // END + + //------------------------------------- + // Take URL and parse it + //------------------------------------- + + function server($url, $port=80) + { + if (substr($url, 0, 4) != "http") + { + $url = "http://".$url; + } + + $parts = parse_url($url); + + $path = ( ! isset($parts['path'])) ? '/' : $parts['path']; + + if (isset($parts['query']) && $parts['query'] != '') + { + $path .= '?'.$parts['query']; + } + + $this->client = new XML_RPC_Client($path, $parts['host'], $port); + } + // END + + //------------------------------------- + // Set Timeout + //------------------------------------- + + function timeout($seconds=5) + { + if ( ! is_null($this->client) && is_int($seconds)) + { + $this->client->timeout = $seconds; + } + } + // END + + //------------------------------------- + // Set Methods + //------------------------------------- + + function method($function) + { + $this->method = $function; + } + // END + + //------------------------------------- + // Take Array of Data and Create Objects + //------------------------------------- + + function request($incoming) + { + if ( ! is_array($incoming)) + { + // Send Error + } + + $this->data = array(); + + foreach ($incoming as $key => $value) + { + $this->data[$key] = $this->values_parsing($value); + } + } + // END + + + //------------------------------------- + // Set Debug + //------------------------------------- + + function set_debug($flag = TRUE) + { + $this->debug = ($flag == TRUE) ? TRUE : FALSE; + } + + //------------------------------------- + // Values Parsing + //------------------------------------- + + function values_parsing($value, $return = FALSE) + { + if (is_array($value) && array_key_exists(0, $value)) + { + if ( ! isset($value['1']) OR ( ! isset($this->xmlrpcTypes[$value['1']]))) + { + if (is_array($value[0])) + { + $temp = new XML_RPC_Values($value['0'], 'array'); + } + else + { + $temp = new XML_RPC_Values($value['0'], 'string'); + } + } + elseif (is_array($value['0']) && ($value['1'] == 'struct' OR $value['1'] == 'array')) + { + while (list($k) = each($value['0'])) + { + $value['0'][$k] = $this->values_parsing($value['0'][$k], TRUE); + } + + $temp = new XML_RPC_Values($value['0'], $value['1']); + } + else + { + $temp = new XML_RPC_Values($value['0'], $value['1']); + } + } + else + { + $temp = new XML_RPC_Values($value, 'string'); + } + + return $temp; + } + // END + + + //------------------------------------- + // Sends XML-RPC Request + //------------------------------------- + + function send_request() + { + $this->message = new XML_RPC_Message($this->method,$this->data); + $this->message->debug = $this->debug; + + if ( ! $this->result = $this->client->send($this->message)) + { + $this->error = $this->result->errstr; + return FALSE; + } + elseif ( ! is_object($this->result->val)) + { + $this->error = $this->result->errstr; + return FALSE; + } + + $this->response = $this->result->decode(); + + return TRUE; + } + // END + + //------------------------------------- + // Returns Error + //------------------------------------- + + function display_error() + { + return $this->error; + } + // END + + //------------------------------------- + // Returns Remote Server Response + //------------------------------------- + + function display_response() + { + return $this->response; + } + // END + + //------------------------------------- + // Sends an Error Message for Server Request + //------------------------------------- + + function send_error_message($number, $message) + { + return new XML_RPC_Response('0',$number, $message); + } + // END + + + //------------------------------------- + // Send Response for Server Request + //------------------------------------- + + function send_response($response) + { + // $response should be array of values, which will be parsed + // based on their data and type into a valid group of XML-RPC values + + $response = $this->values_parsing($response); + + return new XML_RPC_Response($response); + } + // END + +} // END XML_RPC Class + + + +/** + * XML-RPC Client class + * + * @category XML-RPC + * @author ExpressionEngine Dev Team + * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html + */ +class XML_RPC_Client extends CI_Xmlrpc +{ + var $path = ''; + var $server = ''; + var $port = 80; + var $errno = ''; + var $errstring = ''; + var $timeout = 5; + var $no_multicall = FALSE; + + public function __construct($path, $server, $port=80) + { + parent::__construct(); + + $this->port = $port; + $this->server = $server; + $this->path = $path; + } + + function send($msg) + { + if (is_array($msg)) + { + // Multi-call disabled + $r = new XML_RPC_Response(0, $this->xmlrpcerr['multicall_recursion'],$this->xmlrpcstr['multicall_recursion']); + return $r; + } + + return $this->sendPayload($msg); + } + + function sendPayload($msg) + { + $fp = @fsockopen($this->server, $this->port,$this->errno, $this->errstr, $this->timeout); + + if ( ! is_resource($fp)) + { + error_log($this->xmlrpcstr['http_error']); + $r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'],$this->xmlrpcstr['http_error']); + return $r; + } + + if (empty($msg->payload)) + { + // $msg = XML_RPC_Messages + $msg->createPayload(); + } + + $r = "\r\n"; + $op = "POST {$this->path} HTTP/1.0$r"; + $op .= "Host: {$this->server}$r"; + $op .= "Content-Type: text/xml$r"; + $op .= "User-Agent: {$this->xmlrpcName}$r"; + $op .= "Content-Length: ".strlen($msg->payload). "$r$r"; + $op .= $msg->payload; + + + if ( ! fputs($fp, $op, strlen($op))) + { + error_log($this->xmlrpcstr['http_error']); + $r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']); + return $r; + } + $resp = $msg->parseResponse($fp); + fclose($fp); + return $resp; + } + +} // end class XML_RPC_Client + + +/** + * XML-RPC Response class + * + * @category XML-RPC + * @author ExpressionEngine Dev Team + * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html + */ +class XML_RPC_Response +{ + var $val = 0; + var $errno = 0; + var $errstr = ''; + var $headers = array(); + var $xss_clean = TRUE; + + public function __construct($val, $code = 0, $fstr = '') + { + if ($code != 0) + { + // error + $this->errno = $code; + $this->errstr = htmlentities($fstr); + } + else if ( ! is_object($val)) + { + // programmer error, not an object + error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to XML_RPC_Response. Defaulting to empty value."); + $this->val = new XML_RPC_Values(); + } + else + { + $this->val = $val; + } + } + + function faultCode() + { + return $this->errno; + } + + function faultString() + { + return $this->errstr; + } + + function value() + { + return $this->val; + } + + function prepare_response() + { + $result = "\n"; + if ($this->errno) + { + $result .= ' + + + + faultCode + ' . $this->errno . ' + + + faultString + ' . $this->errstr . ' + + + +'; + } + else + { + $result .= "\n\n" . + $this->val->serialize_class() . + "\n"; + } + $result .= "\n"; + return $result; + } + + function decode($array=FALSE) + { + $CI =& get_instance(); + + if ($array !== FALSE && is_array($array)) + { + while (list($key) = each($array)) + { + if (is_array($array[$key])) + { + $array[$key] = $this->decode($array[$key]); + } + else + { + $array[$key] = ($this->xss_clean) ? $CI->security->xss_clean($array[$key]) : $array[$key]; + } + } + + $result = $array; + } + else + { + $result = $this->xmlrpc_decoder($this->val); + + if (is_array($result)) + { + $result = $this->decode($result); + } + else + { + $result = ($this->xss_clean) ? $CI->security->xss_clean($result) : $result; + } + } + + return $result; + } + + + + //------------------------------------- + // XML-RPC Object to PHP Types + //------------------------------------- + + function xmlrpc_decoder($xmlrpc_val) + { + $kind = $xmlrpc_val->kindOf(); + + if ($kind == 'scalar') + { + return $xmlrpc_val->scalarval(); + } + elseif ($kind == 'array') + { + reset($xmlrpc_val->me); + list($a,$b) = each($xmlrpc_val->me); + $size = count($b); + + $arr = array(); + + for ($i = 0; $i < $size; $i++) + { + $arr[] = $this->xmlrpc_decoder($xmlrpc_val->me['array'][$i]); + } + return $arr; + } + elseif ($kind == 'struct') + { + reset($xmlrpc_val->me['struct']); + $arr = array(); + + while (list($key,$value) = each($xmlrpc_val->me['struct'])) + { + $arr[$key] = $this->xmlrpc_decoder($value); + } + return $arr; + } + } + + + //------------------------------------- + // ISO-8601 time to server or UTC time + //------------------------------------- + + function iso8601_decode($time, $utc=0) + { + // return a timet in the localtime, or UTC + $t = 0; + if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs)) + { + $fnc = ($utc == 1) ? 'gmmktime' : 'mktime'; + $t = $fnc($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); + } + return $t; + } + +} // End Response Class + + + +/** + * XML-RPC Message class + * + * @category XML-RPC + * @author ExpressionEngine Dev Team + * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html + */ +class XML_RPC_Message extends CI_Xmlrpc +{ + var $payload; + var $method_name; + var $params = array(); + var $xh = array(); + + public function __construct($method, $pars=0) + { + parent::__construct(); + + $this->method_name = $method; + if (is_array($pars) && count($pars) > 0) + { + for ($i=0; $iparams[] = $pars[$i]; + } + } + } + + //------------------------------------- + // Create Payload to Send + //------------------------------------- + + function createPayload() + { + $this->payload = "\r\n\r\n"; + $this->payload .= '' . $this->method_name . "\r\n"; + $this->payload .= "\r\n"; + + for ($i=0; $iparams); $i++) + { + // $p = XML_RPC_Values + $p = $this->params[$i]; + $this->payload .= "\r\n".$p->serialize_class()."\r\n"; + } + + $this->payload .= "\r\n\r\n"; + } + + //------------------------------------- + // Parse External XML-RPC Server's Response + //------------------------------------- + + function parseResponse($fp) + { + $data = ''; + + while ($datum = fread($fp, 4096)) + { + $data .= $datum; + } + + //------------------------------------- + // DISPLAY HTTP CONTENT for DEBUGGING + //------------------------------------- + + if ($this->debug === TRUE) + { + echo "
    ";
    +			echo "---DATA---\n" . htmlspecialchars($data) . "\n---END DATA---\n\n";
    +			echo "
    "; + } + + //------------------------------------- + // Check for data + //------------------------------------- + + if ($data == "") + { + error_log($this->xmlrpcstr['no_data']); + $r = new XML_RPC_Response(0, $this->xmlrpcerr['no_data'], $this->xmlrpcstr['no_data']); + return $r; + } + + + //------------------------------------- + // Check for HTTP 200 Response + //------------------------------------- + + if (strncmp($data, 'HTTP', 4) == 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data)) + { + $errstr= substr($data, 0, strpos($data, "\n")-1); + $r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']. ' (' . $errstr . ')'); + return $r; + } + + //------------------------------------- + // Create and Set Up XML Parser + //------------------------------------- + + $parser = xml_parser_create($this->xmlrpc_defencoding); + + $this->xh[$parser] = array(); + $this->xh[$parser]['isf'] = 0; + $this->xh[$parser]['ac'] = ''; + $this->xh[$parser]['headers'] = array(); + $this->xh[$parser]['stack'] = array(); + $this->xh[$parser]['valuestack'] = array(); + $this->xh[$parser]['isf_reason'] = 0; + + xml_set_object($parser, $this); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_set_element_handler($parser, 'open_tag', 'closing_tag'); + xml_set_character_data_handler($parser, 'character_data'); + //xml_set_default_handler($parser, 'default_handler'); + + + //------------------------------------- + // GET HEADERS + //------------------------------------- + + $lines = explode("\r\n", $data); + while (($line = array_shift($lines))) + { + if (strlen($line) < 1) + { + break; + } + $this->xh[$parser]['headers'][] = $line; + } + $data = implode("\r\n", $lines); + + + //------------------------------------- + // PARSE XML DATA + //------------------------------------- + + if ( ! xml_parse($parser, $data, count($data))) + { + $errstr = sprintf('XML error: %s at line %d', + xml_error_string(xml_get_error_code($parser)), + xml_get_current_line_number($parser)); + //error_log($errstr); + $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']); + xml_parser_free($parser); + return $r; + } + xml_parser_free($parser); + + // --------------------------------------- + // Got Ourselves Some Badness, It Seems + // --------------------------------------- + + if ($this->xh[$parser]['isf'] > 1) + { + if ($this->debug === TRUE) + { + echo "---Invalid Return---\n"; + echo $this->xh[$parser]['isf_reason']; + echo "---Invalid Return---\n\n"; + } + + $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'],$this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']); + return $r; + } + elseif ( ! is_object($this->xh[$parser]['value'])) + { + $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'],$this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']); + return $r; + } + + //------------------------------------- + // DISPLAY XML CONTENT for DEBUGGING + //------------------------------------- + + if ($this->debug === TRUE) + { + echo "
    ";
    +
    +			if (count($this->xh[$parser]['headers'] > 0))
    +			{
    +				echo "---HEADERS---\n";
    +				foreach ($this->xh[$parser]['headers'] as $header)
    +				{
    +					echo "$header\n";
    +				}
    +				echo "---END HEADERS---\n\n";
    +			}
    +
    +			echo "---DATA---\n" . htmlspecialchars($data) . "\n---END DATA---\n\n";
    +
    +			echo "---PARSED---\n" ;
    +			var_dump($this->xh[$parser]['value']);
    +			echo "\n---END PARSED---
    "; + } + + //------------------------------------- + // SEND RESPONSE + //------------------------------------- + + $v = $this->xh[$parser]['value']; + + if ($this->xh[$parser]['isf']) + { + $errno_v = $v->me['struct']['faultCode']; + $errstr_v = $v->me['struct']['faultString']; + $errno = $errno_v->scalarval(); + + if ($errno == 0) + { + // FAULT returned, errno needs to reflect that + $errno = -1; + } + + $r = new XML_RPC_Response($v, $errno, $errstr_v->scalarval()); + } + else + { + $r = new XML_RPC_Response($v); + } + + $r->headers = $this->xh[$parser]['headers']; + return $r; + } + + // ------------------------------------ + // Begin Return Message Parsing section + // ------------------------------------ + + // quick explanation of components: + // ac - used to accumulate values + // isf - used to indicate a fault + // lv - used to indicate "looking for a value": implements + // the logic to allow values with no types to be strings + // params - used to store parameters in method calls + // method - used to store method name + // stack - array with parent tree of the xml element, + // used to validate the nesting of elements + + //------------------------------------- + // Start Element Handler + //------------------------------------- + + function open_tag($the_parser, $name, $attrs) + { + // If invalid nesting, then return + if ($this->xh[$the_parser]['isf'] > 1) return; + + // Evaluate and check for correct nesting of XML elements + + if (count($this->xh[$the_parser]['stack']) == 0) + { + if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') + { + $this->xh[$the_parser]['isf'] = 2; + $this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing'; + return; + } + } + else + { + // not top level element: see if parent is OK + if ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE)) + { + $this->xh[$the_parser]['isf'] = 2; + $this->xh[$the_parser]['isf_reason'] = "XML-RPC element $name cannot be child of ".$this->xh[$the_parser]['stack'][0]; + return; + } + } + + switch($name) + { + case 'STRUCT': + case 'ARRAY': + // Creates array for child elements + + $cur_val = array('value' => array(), + 'type' => $name); + + array_unshift($this->xh[$the_parser]['valuestack'], $cur_val); + break; + case 'METHODNAME': + case 'NAME': + $this->xh[$the_parser]['ac'] = ''; + break; + case 'FAULT': + $this->xh[$the_parser]['isf'] = 1; + break; + case 'PARAM': + $this->xh[$the_parser]['value'] = NULL; + break; + case 'VALUE': + $this->xh[$the_parser]['vt'] = 'value'; + $this->xh[$the_parser]['ac'] = ''; + $this->xh[$the_parser]['lv'] = 1; + break; + case 'I4': + case 'INT': + case 'STRING': + case 'BOOLEAN': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + if ($this->xh[$the_parser]['vt'] != 'value') + { + //two data elements inside a value: an error occurred! + $this->xh[$the_parser]['isf'] = 2; + $this->xh[$the_parser]['isf_reason'] = "'Twas a $name element following a ".$this->xh[$the_parser]['vt']." element inside a single value"; + return; + } + + $this->xh[$the_parser]['ac'] = ''; + break; + case 'MEMBER': + // Set name of to nothing to prevent errors later if no is found + $this->xh[$the_parser]['valuestack'][0]['name'] = ''; + + // Set NULL value to check to see if value passed for this param/member + $this->xh[$the_parser]['value'] = NULL; + break; + case 'DATA': + case 'METHODCALL': + case 'METHODRESPONSE': + case 'PARAMS': + // valid elements that add little to processing + break; + default: + /// An Invalid Element is Found, so we have trouble + $this->xh[$the_parser]['isf'] = 2; + $this->xh[$the_parser]['isf_reason'] = "Invalid XML-RPC element found: $name"; + break; + } + + // Add current element name to stack, to allow validation of nesting + array_unshift($this->xh[$the_parser]['stack'], $name); + + if ($name != 'VALUE') $this->xh[$the_parser]['lv'] = 0; + } + // END + + + //------------------------------------- + // End Element Handler + //------------------------------------- + + function closing_tag($the_parser, $name) + { + if ($this->xh[$the_parser]['isf'] > 1) return; + + // Remove current element from stack and set variable + // NOTE: If the XML validates, then we do not have to worry about + // the opening and closing of elements. Nesting is checked on the opening + // tag so we be safe there as well. + + $curr_elem = array_shift($this->xh[$the_parser]['stack']); + + switch($name) + { + case 'STRUCT': + case 'ARRAY': + $cur_val = array_shift($this->xh[$the_parser]['valuestack']); + $this->xh[$the_parser]['value'] = ( ! isset($cur_val['values'])) ? array() : $cur_val['values']; + $this->xh[$the_parser]['vt'] = strtolower($name); + break; + case 'NAME': + $this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac']; + break; + case 'BOOLEAN': + case 'I4': + case 'INT': + case 'STRING': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + $this->xh[$the_parser]['vt'] = strtolower($name); + + if ($name == 'STRING') + { + $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; + } + elseif ($name=='DATETIME.ISO8601') + { + $this->xh[$the_parser]['vt'] = $this->xmlrpcDateTime; + $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; + } + elseif ($name=='BASE64') + { + $this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']); + } + elseif ($name=='BOOLEAN') + { + // Translated BOOLEAN values to TRUE AND FALSE + if ($this->xh[$the_parser]['ac'] == '1') + { + $this->xh[$the_parser]['value'] = TRUE; + } + else + { + $this->xh[$the_parser]['value'] = FALSE; + } + } + elseif ($name=='DOUBLE') + { + // we have a DOUBLE + // we must check that only 0123456789-. are characters here + if ( ! preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac'])) + { + $this->xh[$the_parser]['value'] = 'ERROR_NON_NUMERIC_FOUND'; + } + else + { + $this->xh[$the_parser]['value'] = (double)$this->xh[$the_parser]['ac']; + } + } + else + { + // we have an I4/INT + // we must check that only 0123456789- are characters here + if ( ! preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac'])) + { + $this->xh[$the_parser]['value'] = 'ERROR_NON_NUMERIC_FOUND'; + } + else + { + $this->xh[$the_parser]['value'] = (int)$this->xh[$the_parser]['ac']; + } + } + $this->xh[$the_parser]['ac'] = ''; + $this->xh[$the_parser]['lv'] = 3; // indicate we've found a value + break; + case 'VALUE': + // This if() detects if no scalar was inside + if ($this->xh[$the_parser]['vt']=='value') + { + $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; + $this->xh[$the_parser]['vt'] = $this->xmlrpcString; + } + + // build the XML-RPC value out of the data received, and substitute it + $temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']); + + if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] == 'ARRAY') + { + // Array + $this->xh[$the_parser]['valuestack'][0]['values'][] = $temp; + } + else + { + // Struct + $this->xh[$the_parser]['value'] = $temp; + } + break; + case 'MEMBER': + $this->xh[$the_parser]['ac']=''; + + // If value add to array in the stack for the last element built + if ($this->xh[$the_parser]['value']) + { + $this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value']; + } + break; + case 'DATA': + $this->xh[$the_parser]['ac']=''; + break; + case 'PARAM': + if ($this->xh[$the_parser]['value']) + { + $this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value']; + } + break; + case 'METHODNAME': + $this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']); + break; + case 'PARAMS': + case 'FAULT': + case 'METHODCALL': + case 'METHORESPONSE': + // We're all good kids with nuthin' to do + break; + default: + // End of an Invalid Element. Taken care of during the opening tag though + break; + } + } + + //------------------------------------- + // Parses Character Data + //------------------------------------- + + function character_data($the_parser, $data) + { + if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already + + // If a value has not been found + if ($this->xh[$the_parser]['lv'] != 3) + { + if ($this->xh[$the_parser]['lv'] == 1) + { + $this->xh[$the_parser]['lv'] = 2; // Found a value + } + + if ( ! @isset($this->xh[$the_parser]['ac'])) + { + $this->xh[$the_parser]['ac'] = ''; + } + + $this->xh[$the_parser]['ac'] .= $data; + } + } + + + function addParam($par) { $this->params[]=$par; } + + function output_parameters($array=FALSE) + { + $CI =& get_instance(); + + if ($array !== FALSE && is_array($array)) + { + while (list($key) = each($array)) + { + if (is_array($array[$key])) + { + $array[$key] = $this->output_parameters($array[$key]); + } + else + { + // 'bits' is for the MetaWeblog API image bits + // @todo - this needs to be made more general purpose + $array[$key] = ($key == 'bits' OR $this->xss_clean == FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]); + } + } + + $parameters = $array; + } + else + { + $parameters = array(); + + for ($i = 0; $i < count($this->params); $i++) + { + $a_param = $this->decode_message($this->params[$i]); + + if (is_array($a_param)) + { + $parameters[] = $this->output_parameters($a_param); + } + else + { + $parameters[] = ($this->xss_clean) ? $CI->security->xss_clean($a_param) : $a_param; + } + } + } + + return $parameters; + } + + + function decode_message($param) + { + $kind = $param->kindOf(); + + if ($kind == 'scalar') + { + return $param->scalarval(); + } + elseif ($kind == 'array') + { + reset($param->me); + list($a,$b) = each($param->me); + + $arr = array(); + + for($i = 0; $i < count($b); $i++) + { + $arr[] = $this->decode_message($param->me['array'][$i]); + } + + return $arr; + } + elseif ($kind == 'struct') + { + reset($param->me['struct']); + + $arr = array(); + + while (list($key,$value) = each($param->me['struct'])) + { + $arr[$key] = $this->decode_message($value); + } + + return $arr; + } + } + +} // End XML_RPC_Messages class + + + +/** + * XML-RPC Values class + * + * @category XML-RPC + * @author ExpressionEngine Dev Team + * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html + */ +class XML_RPC_Values extends CI_Xmlrpc +{ + var $me = array(); + var $mytype = 0; + + public function __construct($val=-1, $type='') + { + parent::__construct(); + + if ($val != -1 OR $type != '') + { + $type = $type == '' ? 'string' : $type; + + if ($this->xmlrpcTypes[$type] == 1) + { + $this->addScalar($val,$type); + } + elseif ($this->xmlrpcTypes[$type] == 2) + { + $this->addArray($val); + } + elseif ($this->xmlrpcTypes[$type] == 3) + { + $this->addStruct($val); + } + } + } + + function addScalar($val, $type='string') + { + $typeof = $this->xmlrpcTypes[$type]; + + if ($this->mytype==1) + { + echo 'XML_RPC_Values: scalar can have only one value
    '; + return 0; + } + + if ($typeof != 1) + { + echo 'XML_RPC_Values: not a scalar type (${typeof})
    '; + return 0; + } + + if ($type == $this->xmlrpcBoolean) + { + if (strcasecmp($val,'true')==0 OR $val==1 OR ($val==true && strcasecmp($val,'false'))) + { + $val = 1; + } + else + { + $val=0; + } + } + + if ($this->mytype == 2) + { + // adding to an array here + $ar = $this->me['array']; + $ar[] = new XML_RPC_Values($val, $type); + $this->me['array'] = $ar; + } + else + { + // a scalar, so set the value and remember we're scalar + $this->me[$type] = $val; + $this->mytype = $typeof; + } + return 1; + } + + function addArray($vals) + { + if ($this->mytype != 0) + { + echo 'XML_RPC_Values: already initialized as a [' . $this->kindOf() . ']
    '; + return 0; + } + + $this->mytype = $this->xmlrpcTypes['array']; + $this->me['array'] = $vals; + return 1; + } + + function addStruct($vals) + { + if ($this->mytype != 0) + { + echo 'XML_RPC_Values: already initialized as a [' . $this->kindOf() . ']
    '; + return 0; + } + $this->mytype = $this->xmlrpcTypes['struct']; + $this->me['struct'] = $vals; + return 1; + } + + function kindOf() + { + switch($this->mytype) + { + case 3: + return 'struct'; + break; + case 2: + return 'array'; + break; + case 1: + return 'scalar'; + break; + default: + return 'undef'; + } + } + + function serializedata($typ, $val) + { + $rs = ''; + + switch($this->xmlrpcTypes[$typ]) + { + case 3: + // struct + $rs .= "\n"; + reset($val); + while (list($key2, $val2) = each($val)) + { + $rs .= "\n{$key2}\n"; + $rs .= $this->serializeval($val2); + $rs .= "\n"; + } + $rs .= ''; + break; + case 2: + // array + $rs .= "\n\n"; + for($i=0; $i < count($val); $i++) + { + $rs .= $this->serializeval($val[$i]); + } + $rs.="\n\n"; + break; + case 1: + // others + switch ($typ) + { + case $this->xmlrpcBase64: + $rs .= "<{$typ}>" . base64_encode((string)$val) . "\n"; + break; + case $this->xmlrpcBoolean: + $rs .= "<{$typ}>" . ((bool)$val ? '1' : '0') . "\n"; + break; + case $this->xmlrpcString: + $rs .= "<{$typ}>" . htmlspecialchars((string)$val). "\n"; + break; + default: + $rs .= "<{$typ}>{$val}\n"; + break; + } + default: + break; + } + return $rs; + } + + function serialize_class() + { + return $this->serializeval($this); + } + + function serializeval($o) + { + $ar = $o->me; + reset($ar); + + list($typ, $val) = each($ar); + $rs = "\n".$this->serializedata($typ, $val)."\n"; + return $rs; + } + + function scalarval() + { + reset($this->me); + list($a,$b) = each($this->me); + return $b; + } + + + //------------------------------------- + // Encode time in ISO-8601 form. + //------------------------------------- + + // Useful for sending time in XML-RPC + + function iso8601_encode($time, $utc=0) + { + if ($utc == 1) + { + $t = strftime("%Y%m%dT%H:%i:%s", $time); + } + else + { + if (function_exists('gmstrftime')) + $t = gmstrftime("%Y%m%dT%H:%i:%s", $time); + else + $t = strftime("%Y%m%dT%H:%i:%s", $time - date('Z')); + } + return $t; + } + +} +// END XML_RPC_Values Class + +/* End of file Xmlrpc.php */ +/* Location: ./system/libraries/Xmlrpc.php */ \ No newline at end of file diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php new file mode 100644 index 0000000..9cd3321 --- /dev/null +++ b/system/libraries/Xmlrpcs.php @@ -0,0 +1,612 @@ +set_system_methods(); + + if (isset($config['functions']) && is_array($config['functions'])) + { + $this->methods = array_merge($this->methods, $config['functions']); + } + + log_message('debug', "XML-RPC Server Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize Prefs and Serve + * + * @access public + * @param mixed + * @return void + */ + function initialize($config=array()) + { + if (isset($config['functions']) && is_array($config['functions'])) + { + $this->methods = array_merge($this->methods, $config['functions']); + } + + if (isset($config['debug'])) + { + $this->debug = $config['debug']; + } + + if (isset($config['object']) && is_object($config['object'])) + { + $this->object = $config['object']; + } + + if (isset($config['xss_clean'])) + { + $this->xss_clean = $config['xss_clean']; + } + } + + // -------------------------------------------------------------------- + + /** + * Setting of System Methods + * + * @access public + * @return void + */ + function set_system_methods() + { + $this->methods = array( + 'system.listMethods' => array( + 'function' => 'this.listMethods', + 'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString), array($this->xmlrpcArray)), + 'docstring' => 'Returns an array of available methods on this server'), + 'system.methodHelp' => array( + 'function' => 'this.methodHelp', + 'signature' => array(array($this->xmlrpcString, $this->xmlrpcString)), + 'docstring' => 'Returns a documentation string for the specified method'), + 'system.methodSignature' => array( + 'function' => 'this.methodSignature', + 'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString)), + 'docstring' => 'Returns an array describing the return type and required parameters of a method'), + 'system.multicall' => array( + 'function' => 'this.multicall', + 'signature' => array(array($this->xmlrpcArray, $this->xmlrpcArray)), + 'docstring' => 'Combine multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details') + ); + } + + // -------------------------------------------------------------------- + + /** + * Main Server Function + * + * @access public + * @return void + */ + function serve() + { + $r = $this->parseRequest(); + $payload = 'xmlrpc_defencoding.'"?'.'>'."\n"; + $payload .= $this->debug_msg; + $payload .= $r->prepare_response(); + + header("Content-Type: text/xml"); + header("Content-Length: ".strlen($payload)); + exit($payload); + } + + // -------------------------------------------------------------------- + + /** + * Add Method to Class + * + * @access public + * @param string method name + * @param string function + * @param string signature + * @param string docstring + * @return void + */ + function add_to_map($methodname, $function, $sig, $doc) + { + $this->methods[$methodname] = array( + 'function' => $function, + 'signature' => $sig, + 'docstring' => $doc + ); + } + + // -------------------------------------------------------------------- + + /** + * Parse Server Request + * + * @access public + * @param string data + * @return object xmlrpc response + */ + function parseRequest($data='') + { + global $HTTP_RAW_POST_DATA; + + //------------------------------------- + // Get Data + //------------------------------------- + + if ($data == '') + { + $data = $HTTP_RAW_POST_DATA; + } + + //------------------------------------- + // Set up XML Parser + //------------------------------------- + + $parser = xml_parser_create($this->xmlrpc_defencoding); + $parser_object = new XML_RPC_Message("filler"); + + $parser_object->xh[$parser] = array(); + $parser_object->xh[$parser]['isf'] = 0; + $parser_object->xh[$parser]['isf_reason'] = ''; + $parser_object->xh[$parser]['params'] = array(); + $parser_object->xh[$parser]['stack'] = array(); + $parser_object->xh[$parser]['valuestack'] = array(); + $parser_object->xh[$parser]['method'] = ''; + + xml_set_object($parser, $parser_object); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_set_element_handler($parser, 'open_tag', 'closing_tag'); + xml_set_character_data_handler($parser, 'character_data'); + //xml_set_default_handler($parser, 'default_handler'); + + + //------------------------------------- + // PARSE + PROCESS XML DATA + //------------------------------------- + + if ( ! xml_parse($parser, $data, 1)) + { + // return XML error as a faultCode + $r = new XML_RPC_Response(0, + $this->xmlrpcerrxml + xml_get_error_code($parser), + sprintf('XML error: %s at line %d', + xml_error_string(xml_get_error_code($parser)), + xml_get_current_line_number($parser))); + xml_parser_free($parser); + } + elseif ($parser_object->xh[$parser]['isf']) + { + return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']); + } + else + { + xml_parser_free($parser); + + $m = new XML_RPC_Message($parser_object->xh[$parser]['method']); + $plist=''; + + for ($i=0; $i < count($parser_object->xh[$parser]['params']); $i++) + { + if ($this->debug === TRUE) + { + $plist .= "$i - " . print_r(get_object_vars($parser_object->xh[$parser]['params'][$i]), TRUE). ";\n"; + } + + $m->addParam($parser_object->xh[$parser]['params'][$i]); + } + + if ($this->debug === TRUE) + { + echo "
    ";
    +				echo "---PLIST---\n" . $plist . "\n---PLIST END---\n\n";
    +				echo "
    "; + } + + $r = $this->_execute($m); + } + + //------------------------------------- + // SET DEBUGGING MESSAGE + //------------------------------------- + + if ($this->debug === TRUE) + { + $this->debug_msg = "\n"; + } + + return $r; + } + + // -------------------------------------------------------------------- + + /** + * Executes the Method + * + * @access protected + * @param object + * @return mixed + */ + function _execute($m) + { + $methName = $m->method_name; + + // Check to see if it is a system call + $system_call = (strncmp($methName, 'system', 5) == 0) ? TRUE : FALSE; + + if ($this->xss_clean == FALSE) + { + $m->xss_clean = FALSE; + } + + //------------------------------------- + // Valid Method + //------------------------------------- + + if ( ! isset($this->methods[$methName]['function'])) + { + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + } + + //------------------------------------- + // Check for Method (and Object) + //------------------------------------- + + $method_parts = explode(".", $this->methods[$methName]['function']); + $objectCall = (isset($method_parts['1']) && $method_parts['1'] != "") ? TRUE : FALSE; + + if ($system_call === TRUE) + { + if ( ! is_callable(array($this,$method_parts['1']))) + { + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + } + } + else + { + if ($objectCall && ! is_callable(array($method_parts['0'],$method_parts['1']))) + { + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + } + elseif ( ! $objectCall && ! is_callable($this->methods[$methName]['function'])) + { + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + } + } + + //------------------------------------- + // Checking Methods Signature + //------------------------------------- + + if (isset($this->methods[$methName]['signature'])) + { + $sig = $this->methods[$methName]['signature']; + for ($i=0; $iparams)+1) + { + for ($n=0; $n < count($m->params); $n++) + { + $p = $m->params[$n]; + $pt = ($p->kindOf() == 'scalar') ? $p->scalarval() : $p->kindOf(); + + if ($pt != $current_sig[$n+1]) + { + $pno = $n+1; + $wanted = $current_sig[$n+1]; + + return new XML_RPC_Response(0, + $this->xmlrpcerr['incorrect_params'], + $this->xmlrpcstr['incorrect_params'] . + ": Wanted {$wanted}, got {$pt} at param {$pno})"); + } + } + } + } + } + + //------------------------------------- + // Calls the Function + //------------------------------------- + + if ($objectCall === TRUE) + { + if ($method_parts[0] == "this" && $system_call == TRUE) + { + return call_user_func(array($this, $method_parts[1]), $m); + } + else + { + if ($this->object === FALSE) + { + $CI =& get_instance(); + return $CI->$method_parts['1']($m); + } + else + { + return $this->object->$method_parts['1']($m); + //return call_user_func(array(&$method_parts['0'],$method_parts['1']), $m); + } + } + } + else + { + return call_user_func($this->methods[$methName]['function'], $m); + } + } + + // -------------------------------------------------------------------- + + /** + * Server Function: List Methods + * + * @access public + * @param mixed + * @return object + */ + function listMethods($m) + { + $v = new XML_RPC_Values(); + $output = array(); + + foreach ($this->methods as $key => $value) + { + $output[] = new XML_RPC_Values($key, 'string'); + } + + foreach ($this->system_methods as $key => $value) + { + $output[]= new XML_RPC_Values($key, 'string'); + } + + $v->addArray($output); + return new XML_RPC_Response($v); + } + + // -------------------------------------------------------------------- + + /** + * Server Function: Return Signature for Method + * + * @access public + * @param mixed + * @return object + */ + function methodSignature($m) + { + $parameters = $m->output_parameters(); + $method_name = $parameters[0]; + + if (isset($this->methods[$method_name])) + { + if ($this->methods[$method_name]['signature']) + { + $sigs = array(); + $signature = $this->methods[$method_name]['signature']; + + for ($i=0; $i < count($signature); $i++) + { + $cursig = array(); + $inSig = $signature[$i]; + for ($j=0; $jxmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']); + } + return $r; + } + + // -------------------------------------------------------------------- + + /** + * Server Function: Doc String for Method + * + * @access public + * @param mixed + * @return object + */ + function methodHelp($m) + { + $parameters = $m->output_parameters(); + $method_name = $parameters[0]; + + if (isset($this->methods[$method_name])) + { + $docstring = isset($this->methods[$method_name]['docstring']) ? $this->methods[$method_name]['docstring'] : ''; + + return new XML_RPC_Response(new XML_RPC_Values($docstring, 'string')); + } + else + { + return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']); + } + } + + // -------------------------------------------------------------------- + + /** + * Server Function: Multi-call + * + * @access public + * @param mixed + * @return object + */ + function multicall($m) + { + // Disabled + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + + $parameters = $m->output_parameters(); + $calls = $parameters[0]; + + $result = array(); + + foreach ($calls as $value) + { + //$attempt = $this->_execute(new XML_RPC_Message($value[0], $value[1])); + + $m = new XML_RPC_Message($value[0]); + $plist=''; + + for ($i=0; $i < count($value[1]); $i++) + { + $m->addParam(new XML_RPC_Values($value[1][$i], 'string')); + } + + $attempt = $this->_execute($m); + + if ($attempt->faultCode() != 0) + { + return $attempt; + } + + $result[] = new XML_RPC_Values(array($attempt->value()), 'array'); + } + + return new XML_RPC_Response(new XML_RPC_Values($result, 'array')); + } + + // -------------------------------------------------------------------- + + /** + * Multi-call Function: Error Handling + * + * @access public + * @param mixed + * @return object + */ + function multicall_error($err) + { + $str = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString(); + $code = is_string($err) ? $this->xmlrpcerr["multicall_${err}"] : $err->faultCode(); + + $struct['faultCode'] = new XML_RPC_Values($code, 'int'); + $struct['faultString'] = new XML_RPC_Values($str, 'string'); + + return new XML_RPC_Values($struct, 'struct'); + } + + // -------------------------------------------------------------------- + + /** + * Multi-call Function: Processes method + * + * @access public + * @param mixed + * @return object + */ + function do_multicall($call) + { + if ($call->kindOf() != 'struct') + { + return $this->multicall_error('notstruct'); + } + elseif ( ! $methName = $call->me['struct']['methodName']) + { + return $this->multicall_error('nomethod'); + } + + list($scalar_type,$scalar_value)=each($methName->me); + $scalar_type = $scalar_type == $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type; + + if ($methName->kindOf() != 'scalar' OR $scalar_type != 'string') + { + return $this->multicall_error('notstring'); + } + elseif ($scalar_value == 'system.multicall') + { + return $this->multicall_error('recursion'); + } + elseif ( ! $params = $call->me['struct']['params']) + { + return $this->multicall_error('noparams'); + } + elseif ($params->kindOf() != 'array') + { + return $this->multicall_error('notarray'); + } + + list($a,$b)=each($params->me); + $numParams = count($b); + + $msg = new XML_RPC_Message($scalar_value); + for ($i = 0; $i < $numParams; $i++) + { + $msg->params[] = $params->me['array'][$i]; + } + + $result = $this->_execute($msg); + + if ($result->faultCode() != 0) + { + return $this->multicall_error($result); + } + + return new XML_RPC_Values(array($result->value()), 'array'); + } + +} +// END XML_RPC_Server class + + +/* End of file Xmlrpcs.php */ +/* Location: ./system/libraries/Xmlrpcs.php */ \ No newline at end of file diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php new file mode 100644 index 0000000..666327d --- /dev/null +++ b/system/libraries/Zip.php @@ -0,0 +1,423 @@ +now = time(); + } + + // -------------------------------------------------------------------- + + /** + * Add Directory + * + * Lets you add a virtual directory into which you can place files. + * + * @access public + * @param mixed the directory name. Can be string or array + * @return void + */ + function add_dir($directory) + { + foreach ((array)$directory as $dir) + { + if ( ! preg_match("|.+/$|", $dir)) + { + $dir .= '/'; + } + + $dir_time = $this->_get_mod_time($dir); + + $this->_add_dir($dir, $dir_time['file_mtime'], $dir_time['file_mdate']); + } + } + + // -------------------------------------------------------------------- + + /** + * Get file/directory modification time + * + * If this is a newly created file/dir, we will set the time to 'now' + * + * @param string path to file + * @return array filemtime/filemdate + */ + function _get_mod_time($dir) + { + // filemtime() will return false, but it does raise an error. + $date = (@filemtime($dir)) ? filemtime($dir) : getdate($this->now); + + $time['file_mtime'] = ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2; + $time['file_mdate'] = (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday']; + + return $time; + } + + // -------------------------------------------------------------------- + + /** + * Add Directory + * + * @access private + * @param string the directory name + * @return void + */ + function _add_dir($dir, $file_mtime, $file_mdate) + { + $dir = str_replace("\\", "/", $dir); + + $this->zipdata .= + "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) + .pack('V', 0) // crc32 + .pack('V', 0) // compressed filesize + .pack('V', 0) // uncompressed filesize + .pack('v', strlen($dir)) // length of pathname + .pack('v', 0) // extra field length + .$dir + // below is "data descriptor" segment + .pack('V', 0) // crc32 + .pack('V', 0) // compressed filesize + .pack('V', 0); // uncompressed filesize + + $this->directory .= + "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) + .pack('V',0) // crc32 + .pack('V',0) // compressed filesize + .pack('V',0) // uncompressed filesize + .pack('v', strlen($dir)) // length of pathname + .pack('v', 0) // extra field length + .pack('v', 0) // file comment length + .pack('v', 0) // disk number start + .pack('v', 0) // internal file attributes + .pack('V', 16) // external file attributes - 'directory' bit set + .pack('V', $this->offset) // relative offset of local header + .$dir; + + $this->offset = strlen($this->zipdata); + $this->entries++; + } + + // -------------------------------------------------------------------- + + /** + * Add Data to Zip + * + * Lets you add files to the archive. If the path is included + * in the filename it will be placed within a directory. Make + * sure you use add_dir() first to create the folder. + * + * @access public + * @param mixed + * @param string + * @return void + */ + function add_data($filepath, $data = NULL) + { + if (is_array($filepath)) + { + foreach ($filepath as $path => $data) + { + $file_data = $this->_get_mod_time($path); + + $this->_add_data($path, $data, $file_data['file_mtime'], $file_data['file_mdate']); + } + } + else + { + $file_data = $this->_get_mod_time($filepath); + + $this->_add_data($filepath, $data, $file_data['file_mtime'], $file_data['file_mdate']); + } + } + + // -------------------------------------------------------------------- + + /** + * Add Data to Zip + * + * @access private + * @param string the file name/path + * @param string the data to be encoded + * @return void + */ + function _add_data($filepath, $data, $file_mtime, $file_mdate) + { + $filepath = str_replace("\\", "/", $filepath); + + $uncompressed_size = strlen($data); + $crc32 = crc32($data); + + $gzdata = gzcompress($data); + $gzdata = substr($gzdata, 2, -4); + $compressed_size = strlen($gzdata); + + $this->zipdata .= + "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) + .pack('V', $crc32) + .pack('V', $compressed_size) + .pack('V', $uncompressed_size) + .pack('v', strlen($filepath)) // length of filename + .pack('v', 0) // extra field length + .$filepath + .$gzdata; // "file data" segment + + $this->directory .= + "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) + .pack('V', $crc32) + .pack('V', $compressed_size) + .pack('V', $uncompressed_size) + .pack('v', strlen($filepath)) // length of filename + .pack('v', 0) // extra field length + .pack('v', 0) // file comment length + .pack('v', 0) // disk number start + .pack('v', 0) // internal file attributes + .pack('V', 32) // external file attributes - 'archive' bit set + .pack('V', $this->offset) // relative offset of local header + .$filepath; + + $this->offset = strlen($this->zipdata); + $this->entries++; + $this->file_num++; + } + + // -------------------------------------------------------------------- + + /** + * Read the contents of a file and add it to the zip + * + * @access public + * @return bool + */ + function read_file($path, $preserve_filepath = FALSE) + { + if ( ! file_exists($path)) + { + return FALSE; + } + + if (FALSE !== ($data = file_get_contents($path))) + { + $name = str_replace("\\", "/", $path); + + if ($preserve_filepath === FALSE) + { + $name = preg_replace("|.*/(.+)|", "\\1", $name); + } + + $this->add_data($name, $data); + return TRUE; + } + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Read a directory and add it to the zip. + * + * This function recursively reads a folder and everything it contains (including + * sub-folders) and creates a zip based on it. Whatever directory structure + * is in the original file path will be recreated in the zip file. + * + * @access public + * @param string path to source + * @return bool + */ + function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL) + { + if ( ! $fp = @opendir($path)) + { + return FALSE; + } + + // Set the original directory root for child dir's to use as relative + if ($root_path === NULL) + { + $root_path = dirname($path).'/'; + } + + while (FALSE !== ($file = readdir($fp))) + { + if (substr($file, 0, 1) == '.') + { + continue; + } + + if (@is_dir($path.$file)) + { + $this->read_dir($path.$file."/", $preserve_filepath, $root_path); + } + else + { + if (FALSE !== ($data = file_get_contents($path.$file))) + { + $name = str_replace("\\", "/", $path); + + if ($preserve_filepath === FALSE) + { + $name = str_replace($root_path, '', $name); + } + + $this->add_data($name.$file, $data); + } + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Get the Zip file + * + * @access public + * @return binary string + */ + function get_zip() + { + // Is there any data to return? + if ($this->entries == 0) + { + return FALSE; + } + + $zip_data = $this->zipdata; + $zip_data .= $this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00"; + $zip_data .= pack('v', $this->entries); // total # of entries "on this disk" + $zip_data .= pack('v', $this->entries); // total # of entries overall + $zip_data .= pack('V', strlen($this->directory)); // size of central dir + $zip_data .= pack('V', strlen($this->zipdata)); // offset to start of central dir + $zip_data .= "\x00\x00"; // .zip file comment length + + return $zip_data; + } + + // -------------------------------------------------------------------- + + /** + * Write File to the specified directory + * + * Lets you write a file + * + * @access public + * @param string the file name + * @return bool + */ + function archive($filepath) + { + if ( ! ($fp = @fopen($filepath, FOPEN_WRITE_CREATE_DESTRUCTIVE))) + { + return FALSE; + } + + flock($fp, LOCK_EX); + fwrite($fp, $this->get_zip()); + flock($fp, LOCK_UN); + fclose($fp); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Download + * + * @access public + * @param string the file name + * @param string the data to be encoded + * @return bool + */ + function download($filename = 'backup.zip') + { + if ( ! preg_match("|.+?\.zip$|", $filename)) + { + $filename .= '.zip'; + } + + $CI =& get_instance(); + $CI->load->helper('download'); + + $get_zip = $this->get_zip(); + + $zip_content =& $get_zip; + + force_download($filename, $zip_content); + } + + // -------------------------------------------------------------------- + + /** + * Initialize Data + * + * Lets you clear current zip data. Useful if you need to create + * multiple zips with different data. + * + * @access public + * @return void + */ + function clear_data() + { + $this->zipdata = ''; + $this->directory = ''; + $this->entries = 0; + $this->file_num = 0; + $this->offset = 0; + } + +} + +/* End of file Zip.php */ +/* Location: ./system/libraries/Zip.php */ \ No newline at end of file diff --git a/system/libraries/index.html b/system/libraries/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/system/libraries/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + + \ No newline at end of file diff --git a/system/libraries/javascript/Jquery.php b/system/libraries/javascript/Jquery.php new file mode 100644 index 0000000..baab83d --- /dev/null +++ b/system/libraries/javascript/Jquery.php @@ -0,0 +1,1071 @@ +CI =& get_instance(); + extract($params); + + if ($autoload === TRUE) + { + $this->script(); + } + + log_message('debug', "Jquery Class Initialized"); + } + + // -------------------------------------------------------------------- + // Event Code + // -------------------------------------------------------------------- + + /** + * Blur + * + * Outputs a jQuery blur event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _blur($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'blur'); + } + + // -------------------------------------------------------------------- + + /** + * Change + * + * Outputs a jQuery change event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _change($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'change'); + } + + // -------------------------------------------------------------------- + + /** + * Click + * + * Outputs a jQuery click event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @param boolean whether or not to return false + * @return string + */ + function _click($element = 'this', $js = '', $ret_false = TRUE) + { + if ( ! is_array($js)) + { + $js = array($js); + } + + if ($ret_false) + { + $js[] = "return false;"; + } + + return $this->_add_event($element, $js, 'click'); + } + + // -------------------------------------------------------------------- + + /** + * Double Click + * + * Outputs a jQuery dblclick event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _dblclick($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'dblclick'); + } + + // -------------------------------------------------------------------- + + /** + * Error + * + * Outputs a jQuery error event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _error($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'error'); + } + + // -------------------------------------------------------------------- + + /** + * Focus + * + * Outputs a jQuery focus event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _focus($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'focus'); + } + + // -------------------------------------------------------------------- + + /** + * Hover + * + * Outputs a jQuery hover event + * + * @access private + * @param string - element + * @param string - Javascript code for mouse over + * @param string - Javascript code for mouse out + * @return string + */ + function _hover($element = 'this', $over, $out) + { + $event = "\n\t$(" . $this->_prep_element($element) . ").hover(\n\t\tfunction()\n\t\t{\n\t\t\t{$over}\n\t\t}, \n\t\tfunction()\n\t\t{\n\t\t\t{$out}\n\t\t});\n"; + + $this->jquery_code_for_compile[] = $event; + + return $event; + } + + // -------------------------------------------------------------------- + + /** + * Keydown + * + * Outputs a jQuery keydown event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _keydown($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'keydown'); + } + + // -------------------------------------------------------------------- + + /** + * Keyup + * + * Outputs a jQuery keydown event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _keyup($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'keyup'); + } + + // -------------------------------------------------------------------- + + /** + * Load + * + * Outputs a jQuery load event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _load($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'load'); + } + + // -------------------------------------------------------------------- + + /** + * Mousedown + * + * Outputs a jQuery mousedown event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _mousedown($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'mousedown'); + } + + // -------------------------------------------------------------------- + + /** + * Mouse Out + * + * Outputs a jQuery mouseout event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _mouseout($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'mouseout'); + } + + // -------------------------------------------------------------------- + + /** + * Mouse Over + * + * Outputs a jQuery mouseover event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _mouseover($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'mouseover'); + } + + // -------------------------------------------------------------------- + + /** + * Mouseup + * + * Outputs a jQuery mouseup event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _mouseup($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'mouseup'); + } + + // -------------------------------------------------------------------- + + /** + * Output + * + * Outputs script directly + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _output($array_js = '') + { + if ( ! is_array($array_js)) + { + $array_js = array($array_js); + } + + foreach ($array_js as $js) + { + $this->jquery_code_for_compile[] = "\t$js\n"; + } + } + + // -------------------------------------------------------------------- + + /** + * Resize + * + * Outputs a jQuery resize event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _resize($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'resize'); + } + + // -------------------------------------------------------------------- + + /** + * Scroll + * + * Outputs a jQuery scroll event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _scroll($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'scroll'); + } + + // -------------------------------------------------------------------- + + /** + * Unload + * + * Outputs a jQuery unload event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _unload($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'unload'); + } + + // -------------------------------------------------------------------- + // Effects + // -------------------------------------------------------------------- + + /** + * Add Class + * + * Outputs a jQuery addClass event + * + * @access private + * @param string - element + * @return string + */ + function _addClass($element = 'this', $class='') + { + $element = $this->_prep_element($element); + $str = "$({$element}).addClass(\"$class\");"; + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Animate + * + * Outputs a jQuery animate event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _animate($element = 'this', $params = array(), $speed = '', $extra = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + $animations = "\t\t\t"; + + foreach ($params as $param=>$value) + { + $animations .= $param.': \''.$value.'\', '; + } + + $animations = substr($animations, 0, -2); // remove the last ", " + + if ($speed != '') + { + $speed = ', '.$speed; + } + + if ($extra != '') + { + $extra = ', '.$extra; + } + + $str = "$({$element}).animate({\n$animations\n\t\t}".$speed.$extra.");"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Fade In + * + * Outputs a jQuery hide event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _fadeIn($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).fadeIn({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Fade Out + * + * Outputs a jQuery hide event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _fadeOut($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).fadeOut({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Hide + * + * Outputs a jQuery hide action + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _hide($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).hide({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Remove Class + * + * Outputs a jQuery remove class event + * + * @access private + * @param string - element + * @return string + */ + function _removeClass($element = 'this', $class='') + { + $element = $this->_prep_element($element); + $str = "$({$element}).removeClass(\"$class\");"; + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Slide Up + * + * Outputs a jQuery slideUp event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _slideUp($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).slideUp({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Slide Down + * + * Outputs a jQuery slideDown event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _slideDown($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).slideDown({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Slide Toggle + * + * Outputs a jQuery slideToggle event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _slideToggle($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).slideToggle({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Toggle + * + * Outputs a jQuery toggle event + * + * @access private + * @param string - element + * @return string + */ + function _toggle($element = 'this') + { + $element = $this->_prep_element($element); + $str = "$({$element}).toggle();"; + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Toggle Class + * + * Outputs a jQuery toggle class event + * + * @access private + * @param string - element + * @return string + */ + function _toggleClass($element = 'this', $class='') + { + $element = $this->_prep_element($element); + $str = "$({$element}).toggleClass(\"$class\");"; + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Show + * + * Outputs a jQuery show event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _show($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).show({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Updater + * + * An Ajax call that populates the designated DOM node with + * returned content + * + * @access private + * @param string The element to attach the event to + * @param string the controller to run the call against + * @param string optional parameters + * @return string + */ + + function _updater($container = 'this', $controller, $options = '') + { + $container = $this->_prep_element($container); + + $controller = (strpos('://', $controller) === FALSE) ? $controller : $this->CI->config->site_url($controller); + + // ajaxStart and ajaxStop are better choices here... but this is a stop gap + if ($this->CI->config->item('javascript_ajax_img') == '') + { + $loading_notifier = "Loading..."; + } + else + { + $loading_notifier = 'CI->config->slash_item('base_url') . $this->CI->config->item('javascript_ajax_img') . '\' alt=\'Loading\' />'; + } + + $updater = "$($container).empty();\n"; // anything that was in... get it out + $updater .= "\t\t$($container).prepend(\"$loading_notifier\");\n"; // to replace with an image + + $request_options = ''; + if ($options != '') + { + $request_options .= ", {"; + $request_options .= (is_array($options)) ? "'".implode("', '", $options)."'" : "'".str_replace(":", "':'", $options)."'"; + $request_options .= "}"; + } + + $updater .= "\t\t$($container).load('$controller'$request_options);"; + return $updater; + } + + + // -------------------------------------------------------------------- + // Pre-written handy stuff + // -------------------------------------------------------------------- + + /** + * Zebra tables + * + * @access private + * @param string table name + * @param string plugin location + * @return string + */ + function _zebraTables($class = '', $odd = 'odd', $hover = '') + { + $class = ($class != '') ? '.'.$class : ''; + + $zebra = "\t\$(\"table{$class} tbody tr:nth-child(even)\").addClass(\"{$odd}\");"; + + $this->jquery_code_for_compile[] = $zebra; + + if ($hover != '') + { + $hover = $this->hover("table{$class} tbody tr", "$(this).addClass('hover');", "$(this).removeClass('hover');"); + } + + return $zebra; + } + + + + // -------------------------------------------------------------------- + // Plugins + // -------------------------------------------------------------------- + + /** + * Corner Plugin + * + * http://www.malsup.com/jquery/corner/ + * + * @access public + * @param string target + * @return string + */ + function corner($element = '', $corner_style = '') + { + // may want to make this configurable down the road + $corner_location = '/plugins/jquery.corner.js'; + + if ($corner_style != '') + { + $corner_style = '"'.$corner_style.'"'; + } + + return "$(" . $this->_prep_element($element) . ").corner(".$corner_style.");"; + } + + // -------------------------------------------------------------------- + + /** + * modal window + * + * Load a thickbox modal window + * + * @access public + * @return void + */ + function modal($src, $relative = FALSE) + { + $this->jquery_code_for_load[] = $this->external($src, $relative); + } + + // -------------------------------------------------------------------- + + /** + * Effect + * + * Load an Effect library + * + * @access public + * @return void + */ + function effect($src, $relative = FALSE) + { + $this->jquery_code_for_load[] = $this->external($src, $relative); + } + + // -------------------------------------------------------------------- + + /** + * Plugin + * + * Load a plugin library + * + * @access public + * @return void + */ + function plugin($src, $relative = FALSE) + { + $this->jquery_code_for_load[] = $this->external($src, $relative); + } + + // -------------------------------------------------------------------- + + /** + * UI + * + * Load a user interface library + * + * @access public + * @return void + */ + function ui($src, $relative = FALSE) + { + $this->jquery_code_for_load[] = $this->external($src, $relative); + } + // -------------------------------------------------------------------- + + /** + * Sortable + * + * Creates a jQuery sortable + * + * @access public + * @return void + */ + function sortable($element, $options = array()) + { + + if (count($options) > 0) + { + $sort_options = array(); + foreach ($options as $k=>$v) + { + $sort_options[] = "\n\t\t".$k.': '.$v.""; + } + $sort_options = implode(",", $sort_options); + } + else + { + $sort_options = ''; + } + + return "$(" . $this->_prep_element($element) . ").sortable({".$sort_options."\n\t});"; + } + + // -------------------------------------------------------------------- + + /** + * Table Sorter Plugin + * + * @access public + * @param string table name + * @param string plugin location + * @return string + */ + function tablesorter($table = '', $options = '') + { + $this->jquery_code_for_compile[] = "\t$(" . $this->_prep_element($table) . ").tablesorter($options);\n"; + } + + // -------------------------------------------------------------------- + // Class functions + // -------------------------------------------------------------------- + + /** + * Add Event + * + * Constructs the syntax for an event, and adds to into the array for compilation + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @param string The event to pass + * @return string + */ + function _add_event($element, $js, $event) + { + if (is_array($js)) + { + $js = implode("\n\t\t", $js); + + } + + $event = "\n\t$(" . $this->_prep_element($element) . ").{$event}(function(){\n\t\t{$js}\n\t});\n"; + $this->jquery_code_for_compile[] = $event; + return $event; + } + + // -------------------------------------------------------------------- + + /** + * Compile + * + * As events are specified, they are stored in an array + * This funciton compiles them all for output on a page + * + * @access private + * @return string + */ + function _compile($view_var = 'script_foot', $script_tags = TRUE) + { + // External references + $external_scripts = implode('', $this->jquery_code_for_load); + $this->CI->load->vars(array('library_src' => $external_scripts)); + + if (count($this->jquery_code_for_compile) == 0 ) + { + // no inline references, let's just return + return; + } + + // Inline references + $script = '$(document).ready(function() {' . "\n"; + $script .= implode('', $this->jquery_code_for_compile); + $script .= '});'; + + $output = ($script_tags === FALSE) ? $script : $this->inline($script); + + $this->CI->load->vars(array($view_var => $output)); + + } + + // -------------------------------------------------------------------- + + /** + * Clear Compile + * + * Clears the array of script events collected for output + * + * @access public + * @return void + */ + function _clear_compile() + { + $this->jquery_code_for_compile = array(); + } + + // -------------------------------------------------------------------- + + /** + * Document Ready + * + * A wrapper for writing document.ready() + * + * @access private + * @return string + */ + function _document_ready($js) + { + if ( ! is_array($js)) + { + $js = array ($js); + + } + + foreach ($js as $script) + { + $this->jquery_code_for_compile[] = $script; + } + } + + // -------------------------------------------------------------------- + + /** + * Script Tag + * + * Outputs the script tag that loads the jquery.js file into an HTML document + * + * @access public + * @param string + * @return string + */ + function script($library_src = '', $relative = FALSE) + { + $library_src = $this->external($library_src, $relative); + $this->jquery_code_for_load[] = $library_src; + return $library_src; + } + + // -------------------------------------------------------------------- + + /** + * Prep Element + * + * Puts HTML element in quotes for use in jQuery code + * unless the supplied element is the Javascript 'this' + * object, in which case no quotes are added + * + * @access public + * @param string + * @return string + */ + function _prep_element($element) + { + if ($element != 'this') + { + $element = '"'.$element.'"'; + } + + return $element; + } + + // -------------------------------------------------------------------- + + /** + * Validate Speed + * + * Ensures the speed parameter is valid for jQuery + * + * @access private + * @param string + * @return string + */ + function _validate_speed($speed) + { + if (in_array($speed, array('slow', 'normal', 'fast'))) + { + $speed = '"'.$speed.'"'; + } + elseif (preg_match("/[^0-9]/", $speed)) + { + $speed = ''; + } + + return $speed; + } + +} + +/* End of file Jquery.php */ +/* Location: ./system/libraries/Jquery.php */ \ No newline at end of file diff --git a/tambahan.txt b/tambahan.txt new file mode 100644 index 0000000..e0d9849 --- /dev/null +++ b/tambahan.txt @@ -0,0 +1,12 @@ +tabel volume +dealer +area +region +province +month +target +previous_stock +actual +sellout +order +pattern *dropdown \ No newline at end of file