ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ." ¤‡ú*õ'VŽ|¼´Úgllº¼klz[Æüï÷Aób‡Eÿ dÑ»Xx9ÃÜ£ÁT/`¼¸vI±Ýµ·Ë‚“G³þ*Ÿû´r|*}<¨îºœ @¦mÄ’M¹”.œ«Y–|6ÏU¤jç¥ÕÞqO ˜kDÆÁ¨5ÿ š;ÐЦ¦€GÙk \ –Þ=â¼=SͧµªS°ÚÍpÜãQűÀõ¬?ÃÁ1Ñ•õZà?hóœ€ L¦l{Y*K˜Ù›zc˜–ˆâ ø+¾ ­-Ök¥%ùEÜA'}ˆ><ÊIè“bpÍ/qÞâvoX€w,\úªò6Z[XdÒæ­@Ö—€$òJí#é>'°Ú ôª˜<)4ryÙ£|óAÅn5žêŸyÒäMÝ2{"}‰–¤l÷ûWX\l¾Á¸góÉOÔ /óñB¤f¸çñ[.P˜ZsÊË*ßT܈§QN¢’¡¨§V¼(Üù*eÕ“”5T¨‹Âê¥FŒã½Dü[8'Ò¥a…Ú¶k7a *•›¼'Ò·\8¨ª\@\õ¢¦íq+DÙrmÎ…_ªæ»ŠÓœ¡¯’Ré9MÅ×D™lælffc+ŒÑ,ý™ÿ ¯þǤ=Å’Á7µ÷ÚÛ/“Ü€ñýã¼àí¾ÕÑ+ƒ,uµMâÀÄbm:ÒÎPæ{˜Gz[ƒ¯«® KHà`ߨŠéí¯P8Aq.C‰ à€kòpj´kN¶qô€…Õ,ÜNŠª-­{Zö’æû44‰sŽè‰îVíRœÕm" 6?³D9¡ÇTíÅꋇ`4«¸ÝÁô ï’ýorqКÇZ«x4Žâéþuïf¹µö[P ,Q£éaX±`PÉÍZ ¸äYúg üAx ’6Lê‚xÝÓ*äQ  Ï’¨hÍ =²,6ï#rÃ<¯–£»ƒ‹,–ê•€ aÛsñ'%Æ"®ÛüìBᝠHÚ3ß°©$“XnœÖ’î2ËTeûìxîß ¦å¿çÉ ðK§þ{‘t‚Ϋ¬jéîZ[ ”š7L¥4VÚCE×]m¤Øy”ä4-dz£œ§¸x.*ãÊÊ b÷•h:©‡¦s`BTÁRû¾g⻩‹jø sF¢àJøFl‘È•Xᓁà~*j¯ +(ÚÕ6-£¯÷GŠØy‚<Ç’.F‹Hœw(+)ÜÜâÈzÄäT§FߘãÏ;DmVœ3Àu@mÚüXÝü•3B¨òÌÁÛ<·ÃÜ z,Ì@õÅ·d2]ü8s÷IôÞ¯^Ç9¢u„~ëAŸï4«M? K]­ÅàPl@s_ p:°¬ZR”´›JC[CS.h‹ƒïËœ«Æ]–÷ó‚wR×k7X‰k›‘´ù¦=¡«‰¨¨Â')—71ó’c‡Ðúµ `é.{§p¹ój\Ž{1h{o±Ý=áUÊïGÖŒõ–-BÄm+AZX¶¡ ïHðæ¥JmÙ;…䡟ˆ¦ ° äšiÉg«$üMk5¤L“’çÊvïâï ,=f“"íἊ5ô¬x6{ɏžID0e¸vçmi'︧ºð9$ò¹÷*£’9ÿ ²TÔ…×>JV¥}Œ}$p[bÔ®*[jzS*8 ”·T›Í–ñUîƒwo$áè=LT™ç—~ô·¤ÈÚ$榍q‰„+´kFm)ž‹©i–ËqÞŠ‰à¶ü( ‚•§ •°ò·‡#5ª•µÊ﯅¡X¨šÁ*F#TXJÊ ušJVÍ&=iÄs1‚3•'fý§5Ñ<=[íÞ­ PÚ;ѱÌ_~Ä££8rÞ ²w;’hDT°>ÈG¬8Á²ÚzŽ®ò®qZcqJêäÞ-ö[ܘbň±çb“ж31²n×iƒðÕ;1¶þÉ ªX‰,ßqÏ$>•î íZ¥Z 1{ç൵+ƒÕµ¥°T$§K]á»Ûï*·¤tMI’ÂZbŽÕiÒ˜}bÓ0£ª5›¨ [5Ž^ÝœWøÂÝh° ¢OWun£¤5 a2Z.G2³YL]jåtì”ä ÁÓ‘%"©<Ôúʰsº UZvä‡ÄiÆÒM .÷V·™ø#kèýiíÌ–ª)µT[)BˆõÑ xB¾B€ÖT¨.¥~ð@VĶr#¸ü*åZNDŽH;âi ],©£öØpù(šºãö¼T.uCê•4@ÿ GÕÛ)Cx›®0ø#:ÏðFÒbR\(€€Ä®fã4Þ‰Fä¯HXƒÅ,†öEÑÔÜ]Öv²?tLÃvBY£ú6Êu5ÅAQ³1‘’¬x–HŒÐ‡ ^ ¸KwJôÖŽ5×CÚ¨vÜ«/B0$×k°=ðbÇ(Ï)w±A†Á† 11Í=èQšµ626ŒÜ/`G«µ<}—-Ö7KEHÈÉðóȤmݱû±·ø«Snmá=“䫚mݱŸ¡¶~ó·“äUóJæúòB|E LêŽy´jDÔ$G¢þÐñ7óR8ýÒ…Ç› WVe#·Ÿ p·Fx~•ݤF÷0Èÿ K¯æS<6’¡WШ; ´ÿ ¥Êø\Òuî†åÝ–VNœkÒ7oòX¨Á­Ø÷FÎÑä±g÷ÿ M~Çî=p,X´ ÝÌÚÅ‹’ÃjÖ.ØöÏñ qïQ¤ÓZE†° =6·]܈ s¸>v•Ž^Ý\wq9r‰Î\¸¡kURÒ$­*‹Nq?Þª*!sŠÆ:TU_u±T+øX¡ ®¹¡,ÄâÃBTsÜ$Ø›4m椴zÜK]’’›Pƒ @€#â˜`é¹=I‡fiV•Ôî“nRm+µFPOhÍ0B£ €+¬5c v•:P'ÒyÎ ‰V~‚Ó†ÖuókDoh$å\*ö%Ю=£«…aȼ½÷Û.-½VŒŠ¼'lyî±1¬3ó#ÞE¿ÔS¤gV£m›=§\û"—WU¤ÚǼÿ ÂnÁGŒÃ ‚õN D³õNÚíŒÕ;HôyÄÈ©P¹Ä{:?R‘Ô¨âF÷ø£bÅó® JS|‚R÷ivýáâ€Æé¡è³´IئÑT!§˜•ت‚¬â@q€wnïCWÄ@JU€ê¯m6]Ï:£âx'+ÒðXvÓ¦Úm=–´7œ $ì“B£~p%ÕŸUþ« N@¼üï~w˜ñø5®—'Ôe»¤5ã//€ž~‰Tþ›Å7•#¤× Íö pÄ$ùeåì*«ÓŠEØWEÈsßg ¦ûvžSsLpºÊW–âµEWöˬH; ™!CYõZ ÃÄf æ#1W. \uWâ\,\Çf j’<qTbên›Î[vxx£ë 'ö¨1›˜ÀM¼Pÿ H)ƒêêŒA7s,|F“ 꺸k³9Ìö*ç®;Ö!Ö$Eiž•¹ÒÚ†ýóéÝû¾ÕS®ó$’NÝäŸz¤5r¦ãÄÃD÷Üø!°ø‡Ô&@m™Ì^Ãä­d q5Lnÿ N;.6½·N|#ä"1Nƒx“ã<3('&ñßt  ~ªu”1Tb㫨9ê–›–bìd$ߣ=#ÕãÒmU¯eí$EFù5ýYô櫨æì™Ç—±ssM]·á¿0ÕåJRÓªîiƒ+O58ÖñªŠÒx" \µâá¨i’¤i —Ö ” M+M¤ë9‚‰A¦°Qõ¾ßøK~¼Ã‘g…Ö´~÷Ï[3GUœÒ½#…kàÔ®Ò”‰³·dWV‰IP‰Ú8u¹”E ÖqLj¾êÕCBš{A^Âß;–¨`¯¬ìö ˼ ×tìø.tƐm*n¨y4o&Àx¥n¦×î‡aupáÛj8¿m›è¶ã!o½;ß0y^ý×^EÑ¿ÒjzŒ­)vÚÑnÄL …^ªô× ‡—‚3k Îý­hï]içå–îÏ*÷ñþ»Ô CÒjøjÍznˆ´ ¹#b'Fô‹ ‰v¥'’à'T´ƒHýÍ%M‰ ƒ&ÆÇŒï1 ‘ –Þ ‰i¬s žR-Ÿ kЬá¬7:þ 0ŒÅÒÕ/aÙ¬ÃÝ#Úøœ ©aiVc‰. ¹¦ãµ” ›Yg¦›ÆÎýº°f³7ƒhá·¸­}&D9¡ÂsÉÙÞèŠõØàC™¨ñbFC|´Ü(ŸƒÚÒ-%»'a Ì¿)ËÇn¿úÿ ÞŽX…4ÊÅH^ôΑí@ù¹Eh¶“L8Çjù ¼ÎåVªóR©Ï5uà V4lZß®=€xÖŸ–ÑÈ ÷”¨°¾__yM1tÉ?uÆþIkÄgæ@þ[¢†°XÃJ£j·:nkÅ¢u ‘}âGzö­/IµèЬ¼48q¦F°ŽR¼=ûì{´¯RýicS ÕÛ íNtÍÙï£,w4rêì®»~x(©Uñ§#Ñ&œÕ¤>ÎåÍÓ9’Ö{9eV­[Öjâ²ãu]˜å2›qÑšÕJç0€sÄ|Êëè0튔bÁ>“{×_F`Ø©ºê:µä,v¤ðfc1±"«ÔÍän1#=· Âøv~H½ÐßA¾¿Ü€Óš]Õ; I¾÷ç‚Qi†î¹9ywÔKG˜áñ zQY—§ÃÕZ07§X‚ Áh;ÁM)iÌCH-¯T‘ë|A0{Ò½LÚ–TâÖkÜ’dÀ“rmm»”جPF³ÖcbE§T€ÒxKºû’Ó®7±²(\4ŽÃ¸Uu@j™yĵ;³µ!Á¢b.W¤=mõ´êµK k ¸K^ÜÛ#p*Ü14qkZç5ïë †°5Ï%ÍÛ<Õ¤×Ô¥ê†C Õ´¼ú$ƒÖ“”]Ù¬qÞÚ[4©ý!ûÏ—Áb쳐XµA¬â~`›Çr¸8ìùÝ䫦<>ä÷«?xs´ÇÑ /á;¹øüÊÈÙà{"@Žïzâ¬[âß‚ U_<ÇŸ½4èN˜ú61®qŠu ¦þF£»äJ_ˆÙÎ~ ÞAã–݄ϗrŠD;xTž‘ô`É«…suãO`?³à™ô Lý#Íc5öoæØ‚y´´÷«ZR§<&JÇ+éâô´€i!Àˆ0æAoàðLèÖ-2ŸõW.’t^–(KÁmHµV@xÜÇy®Ñø­â^:Ú3w· 7½¹°ñ¸â¹®:',«Mœ—n­Á+Ãbš LÈ‘ÄnRÓÅœ%¦²‰¨ùQ:¤f‚ "PÕtô¸…cæl…&˜Ú˜Ôkv‹ž+vŠ,=¢v­6—Xy*¥t£«<™:“aîϲ=¦6rO]XI¿Œ÷¤zÚ­›¶ 6÷”w\d ü~v®ˆÌk«^m<ÿ ¢‰Õ\)ùºŽ;… lîÙÅEŠ®cѾ@vnMÏ,¼“ñ•ŽBxðÃzãÇç%3ˆ"}Ù•Åî> BÉú;Ò]V+P˜F_´ßé> Øše|ï‡ÄOmFæÇ ãqÞ$/xÐx­z`ï9"œÜij‚!7.\Td…9M‡•iŽ‹¾‘50ÞŽn¥ß4ÉôO ¹*í^QêËÜÇÌ8=ާs‰'ÂëÙ«á%Pú[O †ÅP¯Vsް.‰,kc¶ ¬A9n˜XÎ-ÞšN["¹QÕ‰ƒMýÁߺXJæÍaLj¾×Ãmã¾ãÚ uñÒþåQô¦¥ /ÄUx:‚ÍÜ’ Đ©ØÝ3V¨‰ÕnÐ6ó*óúK­«…c ¯U òhsý­jóÔj#,ímŒRµ«lbïUTŒÑ8†Ä0œÏr`ð¡¬É Ї ë"À² ™ 6¥ f¶ ¢ÚoܱԷ-<Àî)†a¶ž'Ú»¨TXqØæ¶÷YÄHy˜9ÈIW­YÀuMFë ºÏ’AqÌ4·/Ú †ô'i$øä­=Ä Ý|öK×40è|È6p‘0§)o¥ctî§H+CA-“ xØ|ÐXАç l8íºð3Ø:³¤¬KX¯UÿÙ * Library Author: Anthony Hand * Version: 1.1.1 * License: GPL v3.0 * * This extension is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This extension 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 * GNU General Public License for more details . * */ defined('_JEXEC') or die(); // Below are copyrights from MobileESP library. // ### Edits for MobileESP for Joomla marked by "###". Written by Robert Gerald Porter // Released under GPL v3, fully compatible with original Apache 2.0 license /* ******************************************* // Copyright 2010-2011, Anthony Hand // // File version date: August 22, 2011 // Update: // - Updated DetectAndroidTablet() to fix a bug introduced in the last fix! The true/false returns were mixed up. // // File version date: August 16, 2011 // Update: // - Updated DetectAndroidTablet() to exclude Opera Mini, which was falsely reporting as running on a tablet device when on a phone. // // File version date: August 7, 2011 // Update: // - The Opera for Android browser doesn't follow Google's recommended useragent string guidelines, so some fixes were needed. // - Updated DetectAndroidPhone() and DetectAndroidTablet() to properly detect devices running Opera Mobile. // - Created 2 new methods: DetectOperaAndroidPhone() and DetectOperaAndroidTablet(). // - Updated DetectTierIphone(). Removed the call to DetectMaemoTablet(), an obsolete mobile OS. // // File version date: July 15, 2011 // Update: // - Refactored the variable called maemoTablet. Its new name is the more generic deviceTablet. // - Created the variable deviceWebOShp for HP's line of WebOS devices starting with the TouchPad tablet. // - Created the DetectWebOSTablet() method for HP's line of WebOS tablets starting with the TouchPad tablet. // - Updated the DetectTierTablet() method to also search for WebOS tablets. // - Updated the DetectMaemoTablet() method to disambiguate against WebOS tablets which share some signature traits. // // // LICENSE INFORMATION // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, // either express or implied. See the License for the specific // language governing permissions and limitations under the License. // // // ABOUT THIS PROJECT // Project Owner: Anthony Hand // Email: anthony.hand@gmail.com // Web Site: http://www.mobileesp.com // Source Files: http://code.google.com/p/mobileesp/ // // Versions of this code are available for: // PHP, JavaScript, Java, ASP.NET (C#), and Ruby // // ******************************************* */ //************************** // The uagent_info class encapsulates information about // a browser's connection to your web site. // You can use it to find out whether the browser asking for // your site's content is probably running on a mobile device. // The methods were written so you can be as granular as you want. // For example, enquiring whether it's as specific as an iPod Touch or // as general as a smartphone class device. // The object's methods return 1 for true, or 0 for false. class uagent_info { var $useragent = ""; var $httpaccept = ""; //standardized values for true and false. var $true = 1; var $false = 0; //Let's store values for quickly accessing the same info multiple times. var $isIphone = 0; //Stores whether the device is an iPhone or iPod Touch. var $isAndroidPhone = 0; //Stores whether the device is a (small-ish) Android phone or media player. var $isTierTablet = 0; //Stores whether is the Tablet (HTML5-capable, larger screen) tier of devices. var $isTierIphone = 0; //Stores whether is the iPhone tier of devices. var $isTierRichCss = 0; //Stores whether the device can probably support Rich CSS, but JavaScript support is not assumed. (e.g., newer BlackBerry, Windows Mobile) var $isTierGenericMobile = 0; //Stores whether it is another mobile device, which cannot be assumed to support CSS or JS (eg, older BlackBerry, RAZR) // ### Added for AppleTV and disambiguation for iPad var $deviceIntelMacOSX = 'intel mac os x'; // Used for AppleTV2 w/ aTV Flash (black) Couch Surfer Pro browser detection //Initialize some initial smartphone string variables. var $engineWebKit = 'webkit'; var $deviceIphone = 'iphone'; var $deviceIpod = 'ipod'; var $deviceIpad = 'ipad'; var $deviceMacPpc = 'macintosh'; //Used for disambiguation var $deviceAndroid = 'android'; var $deviceGoogleTV = 'googletv'; var $deviceXoom = 'xoom'; //Motorola Xoom var $deviceHtcFlyer = 'htc_flyer'; //HTC Flyer var $deviceNuvifone = 'nuvifone'; //Garmin Nuvifone var $deviceSymbian = 'symbian'; var $deviceS60 = 'series60'; var $deviceS70 = 'series70'; var $deviceS80 = 'series80'; var $deviceS90 = 'series90'; var $deviceWinPhone7 = 'windows phone os 7'; var $deviceWinMob = 'windows ce'; var $deviceWindows = 'windows'; var $deviceIeMob = 'iemobile'; var $devicePpc = 'ppc'; //Stands for PocketPC var $enginePie = 'wm5 pie'; //An old Windows Mobile var $deviceBB = 'blackberry'; var $vndRIM = 'vnd.rim'; //Detectable when BB devices emulate IE or Firefox var $deviceBBStorm = 'blackberry95'; //Storm 1 and 2 var $deviceBBBold = 'blackberry97'; //Bold var $deviceBBTour = 'blackberry96'; //Tour var $deviceBBCurve = 'blackberry89'; //Curve2 var $deviceBBTorch = 'blackberry 98'; //Torch var $deviceBBBoldTouch97 = 'blackberry 979'; //### Bold Touch var $deviceBBBoldTouch = 'blackberry 99'; //### Bold Touch var $deviceBBCurveTouch = 'blackberry 938'; // ### Curve Touch var $deviceBBPlaybook = 'playbook'; //PlayBook tablet var $devicePalm = 'palm'; var $deviceWebOS = 'webos'; //For Palm's line of WebOS devices var $deviceWebOShp = 'hpwos'; //For HP's line of WebOS devices var $engineBlazer = 'blazer'; //Old Palm browser var $engineXiino = 'xiino'; //Another old Palm var $deviceKindle = 'kindle'; //Amazon Kindle, eInk one. //Initialize variables for mobile-specific content. var $vndwap = 'vnd.wap'; var $wml = 'wml'; //Initialize variables for other random devices and mobile browsers. var $deviceTablet = 'tablet'; //Generic term for slate and tablet devices var $deviceBrew = 'brew'; var $deviceDanger = 'danger'; var $deviceHiptop = 'hiptop'; var $devicePlaystation = 'playstation'; var $deviceNintendoDs = 'nitro'; var $deviceNintendo = 'nintendo'; var $deviceWii = 'wii'; var $deviceXbox = 'xbox'; var $deviceArchos = 'archos'; var $engineOpera = 'opera'; //Popular browser var $engineNetfront = 'netfront'; //Common embedded OS browser var $engineUpBrowser = 'up.browser'; //common on some phones var $engineOpenWeb = 'openweb'; //Transcoding by OpenWave server var $deviceMidp = 'midp'; //a mobile Java technology var $uplink = 'up.link'; var $engineTelecaQ = 'teleca q'; //a modern feature phone browser var $devicePda = 'pda'; //some devices report themselves as PDAs var $mini = 'mini'; //Some mobile browsers put 'mini' in their names. var $mobile = 'mobile'; //Some mobile browsers put 'mobile' in their user agent strings. var $mobi = 'mobi'; //Some mobile browsers put 'mobi' in their user agent strings. //Use Maemo, Tablet, and Linux to test for Nokia's Internet Tablets. var $maemo = 'maemo'; var $linux = 'linux'; var $qtembedded = 'qt embedded'; //for Sony Mylo and others var $mylocom2 = 'com2'; //for Sony Mylo also //In some UserAgents, the only clue is the manufacturer. var $manuSonyEricsson = "sonyericsson"; var $manuericsson = "ericsson"; var $manuSamsung1 = "sec-sgh"; var $manuSony = "sony"; var $manuHtc = "htc"; //Popular Android and WinMo manufacturer //In some UserAgents, the only clue is the operator. var $svcDocomo = "docomo"; var $svcKddi = "kddi"; var $svcVodafone = "vodafone"; //Disambiguation strings. var $disUpdate = "update"; //pda vs. update //************************** //The constructor. Initializes several default variables. function uagent_info() { $this->useragent = isset($_SERVER['HTTP_USER_AGENT'])?strtolower($_SERVER['HTTP_USER_AGENT']):''; $this->httpaccept = isset($_SERVER['HTTP_ACCEPT'])?strtolower($_SERVER['HTTP_ACCEPT']):''; //Let's initialize some values to save cycles later. $this->InitDeviceScan(); } //************************** // Initialize Key Stored Values. function InitDeviceScan() { global $isIphone, $isAndroidPhone, $isTierTablet, $isTierIphone; //We'll use these 4 variables to speed other processing. They're super common. $this->isIphone = $this->DetectIphoneOrIpod(); $this->isAndroidPhone = $this->DetectAndroidPhone(); $this->isTierIphone = $this->DetectTierIphone(); $this->isTierTablet = $this->DetectTierTablet(); //Optional: Comment these out if you don't need them. global $isTierRichCss, $isTierGenericMobile; $this->isTierRichCss = $this->DetectTierRichCss(); $this->isTierGenericMobile = $this->DetectTierOtherPhones(); } //************************** //Returns the contents of the User Agent value, in lower case. function Get_Uagent() { return $this->useragent; } //************************** //Returns the contents of the HTTP Accept value, in lower case. function Get_HttpAccept() { return $this->httpaccept; } //************************** // Detects if the current device is an iPhone. function DetectIphone() { if (stripos($this->useragent, $this->deviceIphone) > -1) { //The iPad and iPod Touch say they're an iPhone. So let's disambiguate. if ($this->DetectIpad() == $this->true || $this->DetectIpod() == $this->true) return $this->false; //Yay! It's an iPhone! else return $this->true; } else return $this->false; } //************************** // Detects if the current device is an iPod Touch. function DetectIpod() { if (stripos($this->useragent, $this->deviceIpod) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current device is an iPad tablet. function DetectIpad() { if (stripos($this->useragent, $this->deviceIpad) > -1 && $this->DetectWebkit() == $this->true && $this->DetectAppleTVTwo() == $this->false) // ### make sure it's not an Apple TV2 w/aTV Flash (black) return $this->true; else return $this->false; } //************************** // Detects if the current device is an iPhone or iPod Touch. function DetectIphoneOrIpod() { //We repeat the searches here because some iPods may report themselves as an iPhone, which would be okay. if (stripos($this->useragent, $this->deviceIphone) > -1 || stripos($this->useragent, $this->deviceIpod) > -1) return $this->true; else return $this->false; } //************************** // Detects *any* iOS device: iPhone, iPod Touch, iPad. function DetectIos() { if (($this->DetectIphoneOrIpod() == $this->true) || ($this->DetectIpad() == $this->true)) return $this->true; else return $this->false; } //************************** // ### // Detects AppleTV second generation, jailbroken with Firecore's aTV Flash (black) Couch Surfer Pro browser. function DetectAppleTVTwo() { // Couch Surfer Pro shows up as an iPad, but with Intel Mac OS X string if(stripos($this->useragent, $this->deviceIntelMacOSX) > -1 && stripos($this->useragent, $this->deviceIpad) > -1) return $this->true; else return $this->false; } //************************** // Detects *any* Android OS-based device: phone, tablet, and multi-media player. // Also detects Google TV. function DetectAndroid() { if ((stripos($this->useragent, $this->deviceAndroid) > -1) || ($this->DetectGoogleTV() == $this->true)) return $this->true; //Special check for the HTC Flyer 7" tablet if ((stripos($this->useragent, $this->deviceHtcFlyer) > -1)) return $this->true; else return $this->false; } //************************** // Detects if the current device is a (small-ish) Android OS-based device // used for calling and/or multi-media (like a Samsung Galaxy Player). // Google says these devices will have 'Android' AND 'mobile' in user agent. // Ignores tablets (Honeycomb and later). function DetectAndroidPhone() { if (($this->DetectAndroid() == $this->true) && (stripos($this->useragent, $this->mobile) > -1)) return $this->true; //Special check for Android phones with Opera Mobile. They should report here. if (($this->DetectOperaAndroidPhone() == $this->true)) return $this->true; //Special check for the HTC Flyer 7" tablet. It should report here. if ((stripos($this->useragent, $this->deviceHtcFlyer) > -1)) return $this->true; else return $this->false; } //************************** // Detects if the current device is a (self-reported) Android tablet. // Google says these devices will have 'Android' and NOT 'mobile' in their user agent. function DetectAndroidTablet() { //First, let's make sure we're on an Android device. if ($this->DetectAndroid() == $this->false) return $this->false; //Special check for Opera Android Phones. They should NOT report here. if ($this->DetectOperaMobile() == $this->true) return $this->false; //Special check for the HTC Flyer 7" tablet. It should NOT report here. if ((stripos($this->useragent, $this->deviceHtcFlyer) > -1)) return $this->false; //Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. if (stripos($this->useragent, $this->mobile) > -1) return $this->false; else return $this->true; } //************************** // Detects if the current device is an Android OS-based device and // the browser is based on WebKit. function DetectAndroidWebKit() { if (($this->DetectAndroid() == $this->true) && ($this->DetectWebkit() == $this->true)) return $this->true; else return $this->false; } //************************** // Detects if the current device is a GoogleTV. function DetectGoogleTV() { if (stripos($this->useragent, $this->deviceGoogleTV) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current browser is based on WebKit. function DetectWebkit() { if (stripos($this->useragent, $this->engineWebKit) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current browser is the Nokia S60 Open Source Browser. function DetectS60OssBrowser() { //First, test for WebKit, then make sure it's either Symbian or S60. if ($this->DetectWebkit() == $this->true) { if (stripos($this->useragent, $this->deviceSymbian) > -1 || stripos($this->useragent, $this->deviceS60) > -1) { return $this->true; } else return $this->false; } else return $this->false; } //************************** // Detects if the current device is any Symbian OS-based device, // including older S60, Series 70, Series 80, Series 90, and UIQ, // or other browsers running on these devices. function DetectSymbianOS() { if (stripos($this->useragent, $this->deviceSymbian) > -1 || stripos($this->useragent, $this->deviceS60) > -1 || stripos($this->useragent, $this->deviceS70) > -1 || stripos($this->useragent, $this->deviceS80) > -1 || stripos($this->useragent, $this->deviceS90) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current browser is a // Windows Phone 7 device. function DetectWindowsPhone7() { if (stripos($this->useragent, $this->deviceWinPhone7) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current browser is a Windows Mobile device. // Excludes Windows Phone 7 devices. // Focuses on Windows Mobile 6.xx and earlier. function DetectWindowsMobile() { if ($this->DetectWindowsPhone7() == $this->true) return $this->false; //Most devices use 'Windows CE', but some report 'iemobile' // and some older ones report as 'PIE' for Pocket IE. if (stripos($this->useragent, $this->deviceWinMob) > -1 || stripos($this->useragent, $this->deviceIeMob) > -1 || stripos($this->useragent, $this->enginePie) > -1) return $this->true; //Test for Windows Mobile PPC but not old Macintosh PowerPC. if (stripos($this->useragent, $this->devicePpc) > -1 && !(stripos($this->useragent, $this->deviceMacPpc) > 1)) return $this->true; //Test for certain Windwos Mobile-based HTC devices. if (stripos($this->useragent, $this->manuHtc) > -1 && stripos($this->useragent, $this->deviceWindows) > -1) return $this->true; if ($this->DetectWapWml() == $this->true && stripos($this->useragent, $this->deviceWindows) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current browser is any BlackBerry device. // Includes the PlayBook. function DetectBlackBerry() { if ((stripos($this->useragent, $this->deviceBB) > -1) || (stripos($this->httpaccept, $this->vndRIM) > -1)) return $this->true; else return $this->false; } //************************** // Detects if the current browser is on a BlackBerry tablet device. // Examples: PlayBook function DetectBlackBerryTablet() { if ((stripos($this->useragent, $this->deviceBBPlaybook) > -1)) return $this->true; else return $this->false; } //************************** // Detects if the current browser is a BlackBerry phone device AND uses a // WebKit-based browser. These are signatures for the new BlackBerry OS 6. // Examples: Torch. Includes the Playbook. function DetectBlackBerryWebKit() { if (($this->DetectBlackBerry() == $this->true) && ($this->DetectWebkit() == $this->true)) return $this->true; else return $this->false; } //************************** // Detects if the current browser is a BlackBerry Touch phone // device, such as the Storm or Torch. Excludes the Playbook. function DetectBlackBerryTouch() { if ((stripos($this->useragent, $this->deviceBBStorm) > -1) || (stripos($this->useragent, $this->deviceBBTorch) > -1) || (stripos($this->useragent, $this->deviceBBBoldTouch) > -1) || (stripos($this->useragent, $this->deviceBBBoldTouch97) > -1) || (stripos($this->useragent, $this->deviceBBCurveTouch) > -1)) // ### return $this->true; else return $this->false; } //************************** // Detects if the current browser is a BlackBerry OS 5 device AND // has a more capable recent browser. Excludes the Playbook. // Examples, Storm, Bold, Tour, Curve2 // Excludes the new BlackBerry OS 6 browser!! function DetectBlackBerryHigh() { //Disambiguate for BlackBerry OS 6 (WebKit) browser if ($this->DetectBlackBerryWebKit() == $this->true) return $this->false; if ($this->DetectBlackBerry() == $this->true) { if (($this->DetectBlackBerryTouch() == $this->true) || stripos($this->useragent, $this->deviceBBBold) > -1 || stripos($this->useragent, $this->deviceBBTour) > -1 || stripos($this->useragent, $this->deviceBBCurve) > -1) { return $this->true; } else return $this->false; } else return $this->false; } //************************** // Detects if the current browser is a BlackBerry device AND // has an older, less capable browser. // Examples: Pearl, 8800, Curve1. function DetectBlackBerryLow() { if ($this->DetectBlackBerry() == $this->true) { //Assume that if it's not in the High tier, then it's Low. if (($this->DetectBlackBerryHigh() == $this->true) || ($this->DetectBlackBerryWebKit() == $this->true)) return $this->false; else return $this->true; } else return $this->false; } //************************** // Detects if the current browser is on a PalmOS device. function DetectPalmOS() { //Most devices nowadays report as 'Palm', but some older ones reported as Blazer or Xiino. if (stripos($this->useragent, $this->devicePalm) > -1 || stripos($this->useragent, $this->engineBlazer) > -1 || stripos($this->useragent, $this->engineXiino) > -1) { //Make sure it's not WebOS first if ($this->DetectPalmWebOS() == $this->true) return $this->false; else return $this->true; } else return $this->false; } //************************** // Detects if the current browser is on a Palm device // running the new WebOS. function DetectPalmWebOS() { if (stripos($this->useragent, $this->deviceWebOS) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current browser is on an HP tablet running WebOS. function DetectWebOSTablet() { if ((stripos($this->useragent, $this->deviceWebOShp) > -1) && (stripos($this->useragent, $this->deviceTablet) > -1)) return $this->true; else return $this->false; } //************************** // Detects if the current browser is a // Garmin Nuvifone. function DetectGarminNuvifone() { if (stripos($this->useragent, $this->deviceNuvifone) > -1) return $this->true; else return $this->false; } //************************** // Check to see whether the device is any device // in the 'smartphone' category. function DetectSmartphone() { global $isIphone, $isAndroidPhone, $isTierIphone; if (($this->isIphone == $this->true) || ($this->isAndroidPhone == $this->true) || ($this->isTierIphone == $this->true) || ($this->DetectS60OssBrowser() == $this->true) || ($this->DetectSymbianOS() == $this->true) || ($this->DetectWindowsMobile() == $this->true) || ($this->DetectWindowsPhone7() == $this->true) || ($this->DetectBlackBerry() == $this->true) || ($this->DetectPalmWebOS() == $this->true) || ($this->DetectPalmOS() == $this->true) || ($this->DetectGarminNuvifone() == $this->true)) return $this->true; else return $this->false; } //************************** // Detects whether the device is a Brew-powered device. function DetectBrewDevice() { if (stripos($this->useragent, $this->deviceBrew) > -1) return $this->true; else return $this->false; } //************************** // Detects the Danger Hiptop device. function DetectDangerHiptop() { if (stripos($this->useragent, $this->deviceDanger) > -1 || stripos($this->useragent, $this->deviceHiptop) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current browser is Opera Mobile or Mini. function DetectOperaMobile() { if (stripos($this->useragent, $this->engineOpera) > -1) { if ((stripos($this->useragent, $this->mini) > -1) || (stripos($this->useragent, $this->mobi) > -1)) return $this->true; else return $this->false; } else return $this->false; } //************************** // Detects if the current browser is Opera Mobile // running on an Android phone. function DetectOperaAndroidPhone() { if ((stripos($this->useragent, $this->engineOpera) > -1) && (stripos($this->useragent, $this->deviceAndroid) > -1) && (stripos($this->useragent, $this->mobi) > -1)) return $this->true; else return $this->false; } //************************** // Detects if the current browser is Opera Mobile // running on an Android tablet. function DetectOperaAndroidTablet() { if ((stripos($this->useragent, $this->engineOpera) > -1) && (stripos($this->useragent, $this->deviceAndroid) > -1) && (stripos($this->useragent, $this->deviceTablet) > -1)) return $this->true; else return $this->false; } //************************** // Detects whether the device supports WAP or WML. function DetectWapWml() { if (stripos($this->httpaccept, $this->vndwap) > -1 || stripos($this->httpaccept, $this->wml) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current device is an Amazon Kindle. function DetectKindle() { if (stripos($this->useragent, $this->deviceKindle) > -1) return $this->true; else return $this->false; } //************************** // The quick way to detect for a mobile device. // Will probably detect most recent/current mid-tier Feature Phones // as well as smartphone-class devices. Excludes Apple iPads and other modern tablets. function DetectMobileQuick() { //Let's exclude tablets if ($this->isTierTablet == $this->true) return $this->false; //Most mobile browsing is done on smartphones if ($this->DetectSmartphone() == $this->true) return $this->true; if (($this->DetectWapWml() == $this->true) || ($this->DetectBrewDevice() == $this->true) || ($this->DetectOperaMobile() == $this->true)) return $this->true; if ((stripos($this->useragent, $this->engineNetfront) > -1) || (stripos($this->useragent, $this->engineUpBrowser) > -1) || (stripos($this->useragent, $this->engineOpenWeb) > -1)) return $this->true; if (($this->DetectDangerHiptop() == $this->true) || ($this->DetectMidpCapable() == $this->true) || ($this->DetectMaemoTablet() == $this->true) || ($this->DetectArchos() == $this->true)) return $this->true; if ((stripos($this->useragent, $this->devicePda) > -1) && !(stripos($this->useragent, $this->disUpdate) > -1)) return $this->true; if (stripos($this->useragent, $this->mobile) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current device is a Sony Playstation. function DetectSonyPlaystation() { if (stripos($this->useragent, $this->devicePlaystation) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current device is a Nintendo game device. function DetectNintendo() { if (stripos($this->useragent, $this->deviceNintendo) > -1 || stripos($this->useragent, $this->deviceWii) > -1 || stripos($this->useragent, $this->deviceNintendoDs) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current device is a Microsoft Xbox. function DetectXbox() { if (stripos($this->useragent, $this->deviceXbox) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current device is an Internet-capable game console. function DetectGameConsole() { if ($this->DetectSonyPlaystation() == $this->true) return $this->true; else if ($this->DetectNintendo() == $this->true) return $this->true; else if ($this->DetectXbox() == $this->true) return $this->true; else return $this->false; } //************************** // Detects if the current device supports MIDP, a mobile Java technology. function DetectMidpCapable() { if (stripos($this->useragent, $this->deviceMidp) > -1 || stripos($this->httpaccept, $this->deviceMidp) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current device is on one of the Maemo-based Nokia Internet Tablets. function DetectMaemoTablet() { if (stripos($this->useragent, $this->maemo) > -1) return $this->true; //For Nokia N810, must be Linux + Tablet, or else it could be something else. if ((stripos($this->useragent, $this->linux) > -1) && (stripos($this->useragent, $this->deviceTablet) > -1) && ($this->DetectWebOSTablet() == $this->false) && ($this->DetectAndroid() == $this->false)) return $this->true; else return $this->false; } //************************** // Detects if the current device is an Archos media player/Internet tablet. function DetectArchos() { if (stripos($this->useragent, $this->deviceArchos) > -1) return $this->true; else return $this->false; } //************************** // Detects if the current browser is a Sony Mylo device. function DetectSonyMylo() { if (stripos($this->useragent, $this->manuSony) > -1) { if ((stripos($this->useragent, $this->qtembedded) > -1) || (stripos($this->useragent, $this->mylocom2) > -1)) { return $this->true; } else return $this->false; } else return $this->false; } //************************** // The longer and more thorough way to detect for a mobile device. // Will probably detect most feature phones, // smartphone-class devices, Internet Tablets, // Internet-enabled game consoles, etc. // This ought to catch a lot of the more obscure and older devices, also -- // but no promises on thoroughness! function DetectMobileLong() { if ($this->DetectMobileQuick() == $this->true) return $this->true; if ($this->DetectGameConsole() == $this->true) return $this->true; if ($this->DetectSonyMylo() == $this->true) return $this->true; //Detect older phones from certain manufacturers and operators. if (stripos($this->useragent, $this->uplink) > -1) return $this->true; if (stripos($this->useragent, $this->manuSonyEricsson) > -1) return $this->true; if (stripos($this->useragent, $this->manuericsson) > -1) return $this->true; if (stripos($this->useragent, $this->manuSamsung1) > -1) return $this->true; if (stripos($this->useragent, $this->svcDocomo) > -1) return $this->true; if (stripos($this->useragent, $this->svcKddi) > -1) return $this->true; if (stripos($this->useragent, $this->svcVodafone) > -1) return $this->true; else return $this->false; } //***************************** // For Mobile Web Site Design //***************************** //************************** // The quick way to detect for a tier of devices. // This method detects for the new generation of // HTML 5 capable, larger screen tablets. // Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. function DetectTierTablet() { if (($this->DetectIpad() == $this->true) || ($this->DetectAndroidTablet() == $this->true) || ($this->DetectBlackBerryTablet() == $this->true) || ($this->DetectWebOSTablet() == $this->true)) return $this->true; else return $this->false; } //************************** // The quick way to detect for a tier of devices. // This method detects for devices which can // display iPhone-optimized web content. // Includes iPhone, iPod Touch, Android, WebOS, etc. function DetectTierIphone() { if (($this->isIphone == $this->true) || ($this->isAndroidPhone == $this->true)) return $this->true; if (($this->DetectBlackBerryWebKit() == $this->true) && ($this->DetectBlackBerryTouch() == $this->true)) return $this->true; if ($this->DetectPalmWebOS() == $this->true) return $this->true; if ($this->DetectGarminNuvifone() == $this->true) return $this->true; else return $this->false; } //************************** // The quick way to detect for a tier of devices. // This method detects for devices which are likely to be capable // of viewing CSS content optimized for the iPhone, // but may not necessarily support JavaScript. // Excludes all iPhone Tier devices. function DetectTierRichCss() { if ($this->DetectMobileQuick() == $this->true) { if (($this->DetectTierIphone() == $this->true)) return $this->false; //The following devices are explicitly ok. if ($this->DetectWebkit() == $this->true) //Any WebKit return $this->true; if ($this->DetectS60OssBrowser() == $this->true) return $this->true; //Note: 'High' BlackBerry devices ONLY if ($this->DetectBlackBerryHigh() == $this->true) return $this->true; //WP7's IE-7-based browser isn't good enough for iPhone Tier. if ($this->DetectWindowsPhone7() == $this->true) return $this->true; if ($this->DetectWindowsMobile() == $this->true) return $this->true; if (stripos($this->useragent, $this->engineTelecaQ) > -1) return $this->true; //default else return $this->false; } else return $this->false; } //************************** // The quick way to detect for a tier of devices. // This method detects for all other types of phones, // but excludes the iPhone and RichCSS Tier devices. function DetectTierOtherPhones() { //Exclude devices in the other 2 categories if (($this->DetectMobileLong() == $this->true) && ($this->DetectTierIphone() == $this->false) && ($this->DetectTierRichCss() == $this->false)) return $this->true; else return $this->false; } //**************************** // ### // Weever additional functions function DetectTierWeeverSmartphones() { if ($this->DetectIphoneOrIpod() == $this->true) return $this->true; if ($this->DetectAndroid() == $this->true) return $this->true; if ($this->DetectBlackBerryTouch() == $this->true) return $this->true; else return $this->false; } function DetectTierWeeverTablets() { if (($this->DetectIpad() == $this->true) || ($this->DetectAndroidTablet() == $this->true) || ($this->DetectBlackBerryTablet() == $this->true)) return $this->true; else return $this->false; } } //Was informed by a MobileESP user that it's a best practice // to omit the closing ?> marks here. They can sometimes // cause errors with HTML headers.